Logical Scribbles

[OpenCV] 서로 다른 이미지 간 유사도 측정해보기 본문

딥러닝/OpenCV

[OpenCV] 서로 다른 이미지 간 유사도 측정해보기

KimJake 2023. 12. 6. 14:05

이번 포스팅에서는 3가지의 이미지들의 유사도를 측정해보자.
 
학교 수업에서 진행하는 프로젝트 과정에서 이미지 유사도를 측정해야하는 일이 생겨 정리하게 되었다.
 
먼저 이미지를 불러오고, 이미지들을 확인해보자. 나는 바다 사진 2개와 항공 위성 사진 1개를 준비했다. 
 
바람직한 결과로는 바다 2개의 사진은 유사하다는 결과가, 바다와 항공 위성 사진은 유사하지 않다는 결과가 나와야 할 것이다.
 

import cv2
import numpy as np
import matplotlib.pylab as plt

image1 = plt.imread('/content/바다_1.jpeg')
image2 = plt.imread('/content/바다_2.jpg')
image3 = plt.imread('/content/P_SG-KOMPSAT-2_93.jpg')

# 서브플롯 생성
plt.figure(figsize=(15, 5))

# 첫 번째 서브플롯
plt.subplot(1, 3, 1)
plt.imshow(image1)
plt.title('Image 1')

# 두 번째 서브플롯
plt.subplot(1, 3, 2)
plt.imshow(image2)
plt.title('Image 2')

# 세 번째 서브플롯
plt.subplot(1, 3, 3)
plt.imshow(image3)
plt.title('Image 3')

# 레이아웃 조정
plt.tight_layout()

# 그래프 표시
plt.show()

 
먼저 사진을 불러오고 출력해보자.
 

 
사진들이 잘 불러와졌음을 알 수 있다. 하지만 이들의 사이즈가 모두 다르기 때문에, resize를 통해 크기를 통일해주는 과정이 필요할 것으로 보인다.
 
먼저, image1과 image2의 유사도를 측정해보자. 둘다 바다 사진이기 때문에 유사도가 높게 나와야 할 것이다.
 

imgs = []
imgs.append(cv2.resize(cv2.imread('/content/바다_1.jpeg'),(256,256)))
imgs.append(cv2.resize(cv2.imread('/content/바다_2.jpg'),(256,256)))


hists = []
for img in imgs:
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    hist = cv2.calcHist([hsv], [0], None, [256], [0, 256])
    cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
    hists.append(hist)

query = hists[0]

methods = ['CORREL', 'CHISQR', 'INTERSECT', 'BHATTACHARYYA']

for index, name in enumerate(methods):
    print('%-10s' % name, end = '\t')  
    
    for i, histogram in enumerate(hists):
        ret = cv2.compareHist(query ,histogram, index) 
            
        print("img%d :%7.2f"% (i+1 , ret), end='\t')    

    print()

 
resize를 적용해주고, cv2의 calcHist를 통해 두 이미지의 히스토그램을 만들고, hist 리스트에 저장해 놓는다. 그 뒤, compareHist를 통해 두 히스토그램을 비교해주면 된다.
 
코드를 자세히 살펴보자.
 
HSV는 RGB처럼 색을 표현하는 하나의 방법이자, 그 방법에 따라 색을 배치하는 방식이다. 색상(Hue), 채도(Saturation), 명도(Value)의 좌표를 써서 특정한 색을 지정한다. 
 

HSV 색 공간 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. HSV 색 공간 또는 HSV 모델은 색을 표현하는 하나의 방법이자, 그 방법에 따라 색을 배치하는 방식이다. 색상(Hue), 채도(Saturation), 명도(Value)의 좌표를 써서 특정한

ko.wikipedia.org

 
calcHist는 간단히 말해 이미지의 색상값 분포를 나타내는 히스토그램을 만들어주는 함수이다. 자세한 내용은 아래의 OpenCV에서 제공하는 글에 소개되어 있다.
 

OpenCV: Histogram Calculation

Prev Tutorial: Histogram Equalization Next Tutorial: Histogram Comparison Goal In this tutorial you will learn how to: Use the OpenCV function cv::split to divide an image into its correspondent planes. To calculate histograms of arrays of images by using

docs.opencv.org

 
두 히스토그램을 비교하는 method로 대표적인 4가지 방식을 사용해보았다. 각 방식에 대한 설명은 다음과 같다.
 

  • cv2.HISTCMP_CORREL : 상관관계 (1: 완전 일치, -1: 완전 불일치, 0: 무관계)
  • cv2.HISTCMP_CHISQR : 카이제곱 검정(Chi-Squared Test) (0: 완전 일치, 무한대: 완전 불일치)
  • cv2.HISTCMP_INTERSECT : 교차 (1: 완전 일치, 0: 완전 불일치(히스토그램이 1로 정규화된 경우))
  • cv2.HISTCMP_BHATTACHARYYA : 바타차야 거리 (0: 완전 일치, 1: 완전 불일치)

위의 방식중에서 상관관계는 상대적으로 빠르지만 부정확하고, 바타차야 거리는 상대적으로 느리지만 정확한 방식이라고 한다. 두 방식 중에 한가지 방식만 고집하지 않고, 적절히 사용해야할 것 같다.
 
아래는 위 코드의 결과이다.
 

 
image1을 기준 이미지로 했기 때문에, image2의 결과값을 중점적으로 보면 된다. 상관관계는 0.77, 바타차야 거리는 0.4가 나왔다. 이정도면 유사하다고 판단할 수 있을지 의문이 든다.
 
그러면 이제 바다 사진과 항공 위성 사진을 비교해보자.
 

imgs = []
imgs.append(cv2.resize(cv2.imread('/content/바다_1.jpeg'),(256,256)))
imgs.append(cv2.resize(cv2.imread('/content/P_SG-KOMPSAT-2_93.jpg'),(256,256)))


hists = []
for img in imgs:
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    hist = cv2.calcHist([hsv], [0], None, [256], [0, 256])
    cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
    hists.append(hist)

query = hists[0]

methods = ['CORREL', 'CHISQR', 'INTERSECT', 'BHATTACHARYYA']

for index, name in enumerate(methods):
    print('%-10s' % name, end = '\t')  
    
    for i, histogram in enumerate(hists):
        ret = cv2.compareHist(query ,histogram, index) 
            
        print("img%d :%7.2f"% (i+1 , ret), end='\t')    

    print()

 
 
코드는 같다. 결과값을 보자.
 

 
확실히 바다 사진 2개를 비교한 값과 비교했을 때 두 사진이 덜 유사하다는 것을 판단할 수 있을 것이다.
 
이 코드를 함수로 만들어 두 사진 간 유사도를 간단하게 계산 할 수도 있다.
 
 
끝!