Computer Vision

Histogram comparison with OpenCV and Python

Bằng cách so sánh color histogram, chúng ta có thể biết được sự tương đồng về màu sắc giữa các bức ảnh, từ đó xây dựng nên một hệ Image Search Engine.

Trong bài viết này chúng ta sẽ tìm hiểu các phương pháp so sánh color histogram khác nhau, sử dụng Python và OpenCV.

DATA SET

Chúng ta cần một tập hợp các hình ảnh (dataset) để tiến hành so sánh histogram. Đây là dataset của tôi, gồm 4 file fish-1.png, fish-2.png, fish-3.png và fish-4.png:

dataset

Figure 1 – Data set

Choosing which histogram comparison function to use is normally dependent on (1) the size of the dataset (2) as well as quality of the images in your dataset — you’ll definitely want to perform some experiments and explore different distance functions to get a feel for what metric will work best for your application.


Method #1: Using the OpenCV cv2.compareHist function

OpenCV có built-in function cv2.compareHist() dùng để so sánh 2 histograms với nhau:

cv2.compareHist(hist1, hist2, method)

Chúng ta có thể sử dụng 4 method flag sau:

  • cv2.cv.CV_COMP_CORREL: computes the correlation between the two histograms.
  • cv2.cv.CV_COMP_CHISQR: applies the Chi-Squared distance to the histograms.
  • cv2.cv.CV_COMP_INTERSECT: calculates the intersection between two histograms.
  • cv2.cv.CV_COMP_HELLINGER: used to measure the “overlap” between the two histograms.

Example 1:

import matplotlib.pyplot as plt
import numpy as np
import argparse
import glob
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset")
args = vars(ap.parse_args())

# index là dict chứa filename:hist
# images là dict chứa filename:image
index = {}
images = {}

for imagePath in glob.glob(args["dataset"] + "\*.jpg"):
    filename = imagePath[imagePath.rfind("\\") + 1:]
    image = cv2.imread(imagePath)
    images[filename] = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 3D histogram
    hist = cv2.calcHist([image], [0,1,2], None, [8,8,8], [0,256,0,256,0,256])
    hist = cv2.normalize(hist.flatten())
    index[filename] = hist

# tuples of methods
OPENCV_METHODS = (("Correlation", cv2.cv.CV_COMP_CORREL),
                  ("Chi-Squared", cv2.cv.CV_COMP_CHISQR),
                  ("Intersection", cv2.cv.CV_COMP_INTERSECT),
                  ("Hellinger", cv2.cv.CV_COMP_BHATTACHARYYA))

# loop over the comparison methods
for (methodName, method) in OPENCV_METHODS:
    # initialize the results dictionary and the sort
    # direction
    results = {}
    reverse = False

    # if we are using the correlation or intersection
    # method, then sort the results in reverse order
    if methodName in ("Correlation", "Intersection"):
        reverse = True

    for (k, hist) in index.items():
        # compute the distance between the two histograms
        # using the method and update the results dictionary
        d = cv2.compareHist(index["fish-1.jpg"], hist, method)
        results[k] = d

    # sort the results
    results = sorted([(v, k) for (k, v) in results.items()], reverse = reverse)

    # show the query image
    plt.figure("Query")
    plt.subplot(1, 1, 1)
    plt.imshow(images["fish-1.jpg"])
    plt.axis("off")

    # initialize the results figure
    plt.figure("Results: {}".format(methodName))
    plt.suptitle(methodName, fontsize = 20)
    plt.axis("off")

    # loop over the results
    for (i, (v, k)) in enumerate(results):
        # show the result
        plt.subplot(1, len(images), i + 1)
        plt.title("{}: {:.2f}".format(k, v))
        plt.imshow(images[k])
        plt.axis("off")

# show the OpenCV methods
plt.show()

Output:

query

Figure 2 – Query image

result

Figure 3 – Results

Với method Correlation và Intersection, kết quả so sánh càng cao chứng tỏ 2 images càng tương đồng về màu sắc; ngược lại đối với method Chi-squared và Hellinger.


Method #2: Using the SciPy distance metrics

The main difference between using SciPy distance functions and OpenCV methods is that the methods in OpenCV are histogram specific. This is not the case for SciPy, which implements much more general distance functions. However, they are still important to note and you can likely make use of them in your own applications.

SciPy có các distance function sau: 

dist.euclidean(Hist1, Hist2), dist.cityblock(Hist1, Hist2) và dist.chebyshev(Hist1, Hist2).

Example 2:

import scipy.spatial.distance as dist
import matplotlib.pyplot as plt
import numpy as np
import argparse
import glob
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset")
args = vars(ap.parse_args())

# index là dict chứa filename:hist
# images là dict chứa filename:image
index = {}
images = {}

for imagePath in glob.glob(args["dataset"] + "\*.jpg"):
    filename = imagePath[imagePath.rfind("\\") + 1:]
    image = cv2.imread(imagePath)
    images[filename] = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 3D histogram
    hist = cv2.calcHist([image], [0,1,2], None, [8,8,8], [0,256,0,256,0,256])
    hist = cv2.normalize(hist.flatten())
    index[filename] = hist

# initialize the scipy methods to calculate distances
SCIPY_METHODS = (("Euclidean", dist.euclidean),
                 ("Manhattan", dist.cityblock),
                 ("Chebysev", dist.chebyshev))

# loop over the comparison methods
for (methodName, method) in SCIPY_METHODS:
    # initialize the dictionary dictionary
    results = {}

    # loop over the index
    for (k, hist) in index.items():
        # compute the distance between the two histograms
        # using the method and update the results dictionary
        d = method(index["fish-1.jpg"], hist)
        results[k] = d

    # sort the results
    results = sorted([(v, k) for (k, v) in results.items()])

    # show the query image
    plt.figure("Query")
    plt.subplot(1, 1, 1)
    plt.imshow(images["fish-1.jpg"])
    plt.axis("off")

    # initialize the results figure
    plt.figure("Results: {}".format(methodName))
    plt.suptitle(methodName, fontsize = 20)
    plt.axis("off")

    # loop over the results
    for (i, (v, k)) in enumerate(results):
        # show the result
        plt.subplot(1, len(images), i + 1)
        plt.title("{}: {:.2f}".format(k, v))
        plt.imshow(images[k])
        plt.axis("off")

# show the SciPy methods
plt.show()

Output:
query

Figure 4 – Query image

result

Figure 5 – Results

Với 3 distance function này, kết quả so sánh càng nhỏ chứng tỏ 2 images càng tương đồng về màu sắc.


Kết luận

Ở phương pháp 1, function cv2.compareDistance() của OpenCV thực hiện các Distance methods với ưu điểm là tốc độ xử lý cao, bởi vì openCV được biên dịch trên C/C++.

Ở phương pháp 2, chúng ta đã sử dụng các Distance functions có trong subpackage distance của SciPy.

Nếu 2 phương pháp trên không phù hợp với ứng dụng của chúng ta, phương pháp thứ 3 sẽ là tự viết Distance Function của chính mình. Tôi sẽ trình bày phương pháp này ở một bài viết khác.

Cảm ơn các bạn đã theo dõi. Thân ái và quyết thắng.

Reference:
[1] How-To: 3 Ways to Compare Histograms using OpenCV and Python.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s