Làm cách nào tôi có thể đánh giá hai hình ảnh tương tự như thế nào với OpenCV?


140

OpenCV có hỗ trợ so sánh hai hình ảnh, trả về một số giá trị (có thể là tỷ lệ phần trăm) cho biết mức độ giống nhau của những hình ảnh này không? Ví dụ: 100% sẽ được trả lại nếu cùng một hình ảnh được truyền hai lần, 0% sẽ được trả lại nếu các hình ảnh hoàn toàn khác nhau.

Tôi đã đọc rất nhiều chủ đề tương tự ở đây trên StackOverflow. Tôi cũng đã làm một số Googling. Đáng buồn thay, tôi không thể đưa ra một câu trả lời thỏa mãn.


Xem thêm câu trả lời tại stackoverflow.com/questions/4196453/
Đi

Câu trả lời:


208

Đây là một chủ đề rất lớn, với câu trả lời từ 3 dòng mã cho toàn bộ tạp chí nghiên cứu.

Tôi sẽ phác thảo các kỹ thuật phổ biến nhất như vậy và kết quả của họ.

So sánh biểu đồ

Một trong những phương pháp đơn giản & nhanh nhất. Đề xuất nhiều thập kỷ trước như là một phương tiện để tìm các hình ảnh tương tự. Ý tưởng là một khu rừng sẽ có rất nhiều màu xanh lá cây, và khuôn mặt của con người có rất nhiều màu hồng, hoặc bất cứ điều gì. Vì vậy, nếu bạn so sánh hai bức tranh với các khu rừng, bạn sẽ nhận được một số điểm tương đồng giữa các biểu đồ, bởi vì bạn có rất nhiều màu xanh lá cây trong cả hai.

Nhược điểm: nó quá đơn giản. Một quả chuối và một bãi biển sẽ trông giống nhau, vì cả hai đều có màu vàng.

Phương thức OpenCV: so sánhHist ()

Khớp mẫu

Một ví dụ điển hình ở đây matchTemplate tìm kiếm kết hợp tốt . Nó kết hợp hình ảnh tìm kiếm với người đang tìm kiếm. Nó thường được sử dụng để tìm các phần hình ảnh nhỏ hơn trong một hình lớn hơn.

Nhược điểm: Nó chỉ trả về kết quả tốt với hình ảnh giống hệt nhau, cùng kích thước và hướng.

Phương thức OpenCV: matchTemplate ()

Kết hợp tính năng

Được coi là một trong những cách hiệu quả nhất để tìm kiếm hình ảnh. Một số tính năng được trích xuất từ ​​một hình ảnh, theo cách đảm bảo các tính năng tương tự sẽ được nhận ra lại ngay cả khi xoay, thu nhỏ hoặc nghiêng. Các tính năng được trích xuất theo cách này có thể được so khớp với các bộ tính năng hình ảnh khác. Một hình ảnh khác có tỷ lệ cao các tính năng phù hợp với hình ảnh đầu tiên được coi là mô tả cùng một cảnh.

Tìm điểm tương đồng giữa hai bộ điểm sẽ cho phép bạn cũng tìm thấy sự khác biệt tương đối về góc chụp giữa các ảnh gốc hoặc số lượng chồng lấp.

Có một số hướng dẫn / mẫu OpenCV về điều này, và một video hay ở đây . Toàn bộ mô-đun OpenCV (features2d) được dành riêng cho nó.

Nhược điểm: Nó có thể chậm. Nó không hoàn hảo.


Trên trang web Hỏi & Đáp OpenCV tôi đang nói về sự khác biệt giữa các mô tả tính năng, rất tuyệt khi so sánh toàn bộ hình ảnh và mô tả kết cấu, được sử dụng để xác định các đối tượng như mặt người hoặc ô tô trong một hình ảnh.


để so sánh các hình ảnh tương tự chỉ có một vài hình ảnh riêng biệt (ví dụ: một đối tượng mới được chuyển sang cùng một chế độ xem khác), bạn cũng có thể làm việc với absdiff codota.com/code/java/methods/org.opencv.core.Core/absdiff Điều chỉnh kết quả tạo mặt nạ cho phép bạn làm nổi bật các vùng đã thay đổi từ cảnh này sang cảnh khác.
Tối đa

34

Nếu để phù hợp với hình ảnh giống hệt nhau (cùng kích thước / hướng)

// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity( const Mat A, const Mat B ) {
if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) {
    // Calculate the L2 relative error between images.
    double errorL2 = norm( A, B, CV_L2 );
    // Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
    double similarity = errorL2 / (double)( A.rows * A.cols );
    return similarity;
}
else {
    //Images have a different size
    return 100000000.0;  // Return a bad value
}

Nguồn


12

Giải pháp của Sam là đủ. Tôi đã sử dụng kết hợp cả sự khác biệt về biểu đồ và so khớp mẫu vì không có một phương pháp nào hoạt động với tôi 100%. Tôi đã ít coi trọng phương pháp biểu đồ hơn. Đây là cách tôi đã thực hiện trong kịch bản python đơn giản.

import cv2

class CompareImage(object):

    def __init__(self, image_1_path, image_2_path):
        self.minimum_commutative_image_diff = 1
        self.image_1_path = image_1_path
        self.image_2_path = image_2_path

    def compare_image(self):
        image_1 = cv2.imread(self.image_1_path, 0)
        image_2 = cv2.imread(self.image_2_path, 0)
        commutative_image_diff = self.get_image_difference(image_1, image_2)

        if commutative_image_diff < self.minimum_commutative_image_diff:
            print "Matched"
            return commutative_image_diff
        return 10000 //random failure value

    @staticmethod
    def get_image_difference(image_1, image_2):
        first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256])
        second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256])

        img_hist_diff = cv2.compareHist(first_image_hist, second_image_hist, cv2.HISTCMP_BHATTACHARYYA)
        img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0]
        img_template_diff = 1 - img_template_probability_match

        # taking only 10% of histogram diff, since it's less accurate than template method
        commutative_image_diff = (img_hist_diff / 10) + img_template_diff
        return commutative_image_diff


    if __name__ == '__main__':
        compare_image = CompareImage('image1/path', 'image2/path')
        image_difference = compare_image.compare_image()
        print image_difference

Tôi không hiểu rõ con trăn. Nhưng loại 'commutative_image_diff' là gì? cv.Mat hoặc đôi. Nếu là cv.Mat, hãy so sánh 'commutative_image_diff <self.minimum_commutative_image_diff' nó hoạt động như thế nào hoặc mục đích của việc so sánh này là gì. Bạn có thể giải thích cho tôi?
BulletRain

1

Một chút lạc đề nhưng hữu ích là numpycách tiếp cận pythonic . Nó mạnh mẽ và nhanh chóng nhưng chỉ so sánh các pixel chứ không phải các đối tượng hoặc dữ liệu mà hình ảnh chứa (và nó yêu cầu các hình ảnh có cùng kích thước và hình dạng):

Một cách tiếp cận rất đơn giản và nhanh chóng để làm điều này mà không cần openCV và bất kỳ thư viện nào cho tầm nhìn máy tính là định mức các mảng hình ảnh bằng cách

import numpy as np
picture1 = np.random.rand(100,100)
picture2 = np.random.rand(100,100)
picture1_norm = picture1/np.sqrt(np.sum(picture1**2))
picture2_norm = picture2/np.sqrt(np.sum(picture2**2))

Sau khi xác định cả hai hình ảnh được định chuẩn (hoặc ma trận), bạn có thể chỉ cần tính tổng của phép nhân các hình ảnh bạn muốn so sánh:

1) Nếu bạn so sánh các hình ảnh tương tự, tổng sẽ trả về 1:

In[1]: np.sum(picture1_norm**2)
Out[1]: 1.0

2) Nếu chúng không giống nhau, bạn sẽ nhận được giá trị từ 0 đến 1 (tỷ lệ phần trăm nếu bạn nhân với 100):

In[2]: np.sum(picture2_norm*picture1_norm)
Out[2]: 0.75389941124629822

Xin lưu ý rằng nếu bạn có hình ảnh màu, bạn phải thực hiện điều này trong cả 3 chiều hoặc chỉ so sánh một phiên bản màu xám. Tôi thường phải so sánh số lượng lớn hình ảnh với nội dung tùy ý và đó là cách thực sự nhanh chóng để làm điều đó.


2
xin chào, tôi chỉ làm theo bước của bạn nhưng tôi thấy rằng phần bình thường hóa không thể có kết quả đúng. Kết quả cuối cùng lớn hơn nhiều so với 1.0. Bất kỳ ý tưởng?
G_cy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.