이미지파일다루기 opencv

김승환·2021년 7월 14일
0

딥러닝공부

목록 보기
3/17

opencv 패키지를 이용해서 이미지 파일을 다뤄보겠습니다!

  • 이미지는 행렬 형태와 매우 비슷합니다
  • 기존에 이미지 파일이 RGB의 순서로 저장이 됐다면, opencv는 BGR입니다!
  • 우리가 포토샵을 할때 특정 부분을 mark해서 편집하는 상황이 있습니다. 파이썬에서도 흡사하게 할 수 있는데 HSV라는 (색상(Hue), 채도(Saturation) 및 명도(Value) )로 변경하여 진행합니다

이제는 수많은 cifar이미지를 불러와서 비교를 할 것입니다. 어떤 비교를 할 것이냐면, 히스토그램의 값으로 이미지를 변환한 뒤 cv내부 함수를 이용해 비슷한 이미지를 찾고 가장 비슷한 이미지 부터 순서대로 정렬하여 원하는 만큼의 비슷한 이미지를 호출 하는 함수를 만들 것 입니다

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

dir_path = 'C:/study/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')

images_dir_path= 'C:/study/cifar-images'
filename = train[b'filenames'][0].decode()

호출한 이미지를 4개의 구간으로 나눈 히스토그램을 저장하겠습니다. 이때 list로 저장하고 list를 하나의 행렬로 합쳐줍니다. 합치는 이유는 하나의 행렬에서 값을 처리하기 위해서 인데 예를들어보겠습니다.

  • [1,2]와 [3,4]처럼 따로 저장되어있는 부분을 [[1,2],[3,4]]와 같이 합치는 것 입니다.
def get_histogram(image):
    histogram = []

    # 색삭은 총 3가지이기 때문에 3번 반복합니다.
    for i in range(3):
        #calcHist는 히스토그램을 만들어주는 함수 입니다.
        channel_histogram = cv2.calcHist(images=[image],
                                         channels=[i], 
                                         mask=None,
                                         histSize=[4],  # 히스토그램을 4개의 구간으로 나눕니다
                                         ranges=[0, 256])
        histogram.append(channel_histogram)   #list에 저장을 합니다.
    #list에 저장된 행렬을 결합해줍니다,
    histogram = np.concatenate(histogram)
    # 정규화를 시켜줍니다.
    histogram = cv2.normalize(histogram, histogram)

    return histogram
import cv2
#위에 만든 함수가 잘 작동하는지 보겠습니다.

file_path = os.path.join(images_dir_path, filename)
image = cv2.imread(file_path)
histogram = get_histogram(image)
histogram

array([[0.3126804 ],
[0.4080744 ],
[0.14521089],
[0.21940625],
[0.18654831],
[0.23742512],
[0.30208108],
[0.35931748],
[0.06465594],
[0.35825753],
[0.36991683],
[0.29254165]], dtype=float32)

12개의 행이 나타났습니다. 12개의 행이 나타난이유는 히스토그램을 4구간으로 나눴고 색은 3개의 구분으로 나눠있기 때문에 3x4로 12개가 나타난 것입니다.

위에서 히스토그램의 값으로 저장하는 함수를 만들었습니다. 이번에는 폴더에 있는 모든 이미지를 이름에 대한 히스토그램 값으로 저장하는 딕셔너리를 만들어 보겠습니다.


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

여기까지 만든 함수를 실험해 볼까요?

histogram_db = build_histogram_db()
histogram_db['adriatic_s_001807.png']

array([[0. ],
[0. ],
[0.29744893],
[0.5828624 ],
[0. ],
[0.17107612],
[0.41608465],
[0.29315054],
[0. ],
[0.34301192],
[0.37224102],
[0.16505837]], dtype=float32)

이젠 우리가 원하는 이미지를 입력해서 호출 할 수 있게 함수를 만들어 보겠습니다.

def get_target_histogram():
    filename = input("이미지 파일명을 입력하세요: ")
    if filename not in histogram_db:
        print('유효하지 않은 이미지 파일명입니다.')
        return None
    return histogram_db[filename]
target_histogram = get_target_histogram()

이미지 파일명을 입력하세요: adriatic_s_001807.png

원하는 이미지를 입력하니까 바로 값을 얻을 수 있습니다!

지금까지 만든 함수를 모두 합쳐보겠습니다! 히스토리값을 12개의 행으로 저장해주는 함수, 딕셔너리에 이름에 대한 값을 저장해주는 함수, 원하는 파일명을 입력하면 값을 호출하는 함수


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

{'adriatic_s_001807.png': 0.0,
'baby_s_001654.png': 0.047506706444185816,
'fogbank_s_000423.png': 0.059270738493642845,
'tank_s_000442.png': 0.060966690827361725,
'dessert_plate_s_000124.png': 0.06113711905561663}

#이제 우리는 비슷한 히스토리 값을 가진 이미지를 불러왔습니다.
#밖으로 호출을 해봅시다!
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)

머나먼 여정 끝에 우리는 opencv를 이용해서 하나의 이미지를 선택하면 히스토그램의 특성을 이용하여 비슷한 이미지를 원하는 만큼 호출할 수 있는 능력이 되었습니다!!! 짝짝짝

profile
인공지능 파이팅!

0개의 댓글