뮤트 개발일지

AIFFEL 아이펠 15일차 본문

AIFFEL

AIFFEL 아이펠 15일차

박뮤트 2022. 1. 24. 18:04

파이썬으로 이미지 파일 다루기

CIFAR-100 파일로 실습할 예정

 

Pillow 사용법

(이전에는 PIL로 사용하다가 2011년 개발이 중지되어 이후 Pillow가 이어져 내려오고 있음)

import numpy as np
from PIL import Image

data = np.zeros([32, 32, 3], dtype=np.uint8)
image = Image.fromarray(data, 'RGB')
image
# np.zeros로 모든 픽셀 값이 0으로 초기화되었기 때문에 검은색 이미지 출력됨

# 빨간색 이미지 출력
data[:, :] = [255, 0, 0]
image = Image.fromarray(data, 'RGB')
image

# 흰색 이미지 출력
data[:, :]= [255, 255, 255]
image = Image.fromarray(data, 'RGB')
image

Pillow를 활용한 데이터 전처리

import os
import pickle
from PIL import Image

dir_path = os.getenv('HOME')+'/aiffel/python_image_proc/data/cifar-100-python'
train_file_path = os.path.join(dir_path, 'train')

with open(train_file_path, 'rb') as f:
    train = pickle.load(f, encoding='bytes')

# train에 어떤 key가 있는지 확인
train.keys()

# 첫 번째 key였던 b'filenames' 데이터 타입 확인
type(train[b'filenames'])
>>> list type

# 이미지 확인하기
train[b'data'][0:5]
train[b'data'][0].shape

# 이미지 reshape
image_data = train[b'data'][0].reshape([32, 32, 3], order='F')
image = Image.fromarray(image_data)

# x축, y축 바꾸기
image_data = image_data.swapaxes(0, 1)
image = Image.fromarray(image_data)

위의 내용 50000장에 적용하기

import os
import pickle
from PIL import Image
import numpy
from tqdm import tqdm

dir_path = os.getenv('HOME')+'/aiffel/python_image_proc/data/cifar-100-python'
train_file_path = os.path.join(dir_path, 'train')

# image를 저장할 cifar-100-python의 하위 디렉토리(images)를 생성합니다. 
images_dir_path = os.getenv('HOME')+'/aiffel/python_image_proc/cifar-images'
if not os.path.exists(images_dir_path):
    os.mkdir(images_dir_path)  # images 디렉토리 생성

# 32X32의 이미지 파일 50000개를 생성합니다. 
with open(train_file_path, 'rb') as f:
    train = pickle.load(f, encoding='bytes')
    for i in tqdm(range(len(train[b'filenames']))):
        # [[YOUR CODE]]
        filename = train[b'filenames'][i].decode()
        data = train[b'data'][i].reshape([32, 32, 3], order='F')
        image = Image.fromarray(data.swapaxes(0, 1))
        image.save(os.path.join(images_dir_path, filename))

 

Open CV

import os
import cv2 as cv
import numpy as np
from  matplotlib import pyplot as plt
%matplotlib inline

img_path = os.getenv('HOME')+'/aiffel/python_image_proc/data/cv_practice.png'
img = cv.imread(img_path)

# Convert BGR to HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# define range of blue color in HSV
lower_blue = np.array([100,100,100])
upper_blue = np.array([130,255,255])

# Threshold the HSV image to get only blue colors
mask = cv.inRange(hsv, lower_blue, upper_blue)

# Bitwise-AND mask and original image
res = cv.bitwise_and(img, img, mask=mask)

plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.show()
plt.imshow(cv.cvtColor(mask, cv.COLOR_BGR2RGB))
plt.show()
plt.imshow(cv.cvtColor(res, cv.COLOR_BGR2RGB))
plt.show()

*HSV 색 공간에서 색상Hue 값 100~130 사이, 채도Saturation 및 명도Value 값 100~255 사이의 색들을 파란색이라고 정의함

*cv.inRange(): hsv 에 lower_blue, upper_blue를 적용해 해당하는 픽셀에 1 아닌 픽셀에 0을 찍은 배열을 반환

 

비슷한 이미지 찾아내기

히스토그램: 이미지에서 픽셀 별 색상 값의 분포

 

CIFAR-100의 이미지 중 1개를 골라 Using Matplotlib 내 색상별 히스토그램을 그리는 코드를 참조해 히스토그램을 그려보자.

import os
import pickle
import cv2
import numpy as np
from matplotlib import pyplot as plt
from tqdm import tqdm
from PIL import Image

# 전처리 시 생성했던 디렉토리 구조
dir_path = os.getenv('HOME')+'/aiffel/python_image_proc/'
train_file_path = os.path.join(dir_path, 'train')
images_dir_path = os.path.join(dir_path, 'cifar-images')

# 파일명을 인자로 받아 해당 이미지 파일과 히스토그램을 출력해 주는 함수
def draw_color_histogram_from_image(file_name):
    image_path = os.path.join(images_dir_path, file_name)
    # 이미지 열기
    img = Image.open(image_path)
    cv_image = cv2.imread(image_path)

    # Image와 Histogram 그려보기
    f=plt.figure(figsize=(10,3))
    im1 = f.add_subplot(1,2,1)
    im1.imshow(img)
    im1.set_title("Image")

    im2 = f.add_subplot(1,2,2)
    color = ('b','g','r')
    for i,col in enumerate(color):
        # image에서 i번째 채널의 히스토그램을 뽑아서(0:blue, 1:green, 2:red)
        histr = cv2.calcHist([cv_image],[i],None,[256],[0,256])   
        im2.plot(histr,color = col)   # 그래프를 그릴 때 채널 색상과 맞춰서 그립니다.
    im2.set_title("Histogram")
    
# 이미지와 히스토그램 출력
draw_color_histogram_from_image('adriatic_s_001807.png')

설계

- 프로그램 실행

- build_histogram_db():

  - CIFAR-100 이미지 불러오기

  - CIFAR-100 각 이미지 히스토그램으로 만들기

  - 이미지 이름을 key, 히스토그램을 값으로 하는 딕셔너리 histogram_db를 반환

- CIFAR-100 히스토그램 중 입력된 이미지 이름에 해당하는 히스토그램을 입력 이미지로 선택하여 target_histogram 변수에 저장

- search():

  - 입력 이미지 히스토그램 target_histogram과 딕셔너리 histogram_db(전체 검색 대상 이미지드르이 히스토그램을 가짐)를 입력으로 받는다.

  - OpenCV의 compareHist()를 사용해, 입력 이미지와 검색 대상 이미지 하나하나의 히스토그램 간 유사도 계산

  - 결과는 result라는 딕셔너리로, 키는 이미지 이름, 값은 유사도로 한다.

  - 유사도를 기준으로 정렬하여 순서를 매긴다.

  - 유사도 순서상 상위 5개 이미지를 result에 남긴다.

- 고른 이미지들 표시

- 프로그램 종료

 

# build_histogram_db() 구현

import os
import pickle
import cv2
import numpy as np
from matplotlib import pyplot as plt
from tqdm import tqdm

def build_histogram_db():
    histogram_db = {}

    #디렉토리에 모아 둔 이미지 파일들을 전부 리스트업합니다. 
    path = images_dir_path
    file_list = os.listdir(images_dir_path)

    for file_name in tqdm(file_list):
        file_path = os.path.join(images_dir_path, file_name)
        image = cv2.imread(file_path)

        histogram = get_histogram(image)

        histogram_db[file_name] = histogram

    return histogram_db
# target_histogram 에 입력받은 이미지 히스토그램을 저장하는 함수
def get_target_histogram():
    filename = input("이미지 파일명을 입력하세요: ")
    if filename not in histogram_db:
        print('유효하지 않은 이미지 파일명입니다.')
        return None
    return histogram_db[filename]
# search 함수
def search(histogram_db, target_histogram, top_k=5):
    results = {}

    # Calculate similarity distance by comparing histograms.
    for file_name, histogram in tqdm(histogram_db.items()):
        distance = cv2.compareHist(H1=target_histogram,
                                   H2=histogram,
                                   method=cv2.HISTCMP_CHISQR)

        results[file_name] = distance

    results = dict(sorted(results.items(), key=lambda item: item[1])[:top_k])

    return results
    
result = search(histogram_db, target_histogram)
result
# result를 입력받아 5개의 이미지 보여주는 함수
def show_result(result):
    f=plt.figure(figsize=(10,3))
    for idx, filename in enumerate(result.keys()):    
        img_path = os.path.join(images_dir_path, filename)
        im = f.add_subplot(1,len(result),idx+1)
        img = Image.open(img_path)
        im.imshow(img)

show_result(result)
# 정리
# 검색을 input으로 받으면 즉시 유사한 이미지 출력해주는 함수
target_histogram = get_target_histogram()
result = search(histogram_db, target_histogram)
show_result(result)

'AIFFEL' 카테고리의 다른 글

AIFFEL 아이펠 17일차  (0) 2022.01.25
AIFFEL 아이펠 16일차  (0) 2022.01.25
AIFFEL 아이펠 14일차  (0) 2022.01.17
AIFFEL 아이펠 13일차  (0) 2022.01.13
AIFFEL 아이펠 12일차  (0) 2022.01.12