Phương pháp đơn giản và nhanh chóng để so sánh hình ảnh cho giống nhau


192

Tôi cần một cách đơn giản và nhanh chóng để so sánh hai hình ảnh cho giống nhau. Tức là tôi muốn nhận được một giá trị cao nếu chúng chứa chính xác cùng một thứ nhưng có thể có một số nền hơi khác nhau và có thể được di chuyển / thay đổi kích thước bởi một vài pixel.

(Cụ thể hơn, nếu đó là vấn đề: Một hình ảnh là một biểu tượng và hình ảnh kia là một hình ảnh con của ảnh chụp màn hình và tôi muốn biết liệu hình ảnh đó có chính xác là biểu tượng hay không.)

Tôi có OpenCV trong tay nhưng tôi vẫn chưa quen với nó.

Một khả năng tôi nghĩ đến cho đến nay: Chia cả hai hình ảnh thành các ô 10 x 10 và cho mỗi 100 ô đó, hãy so sánh biểu đồ màu. Sau đó, tôi có thể đặt một số giá trị ngưỡng tạo thành và nếu giá trị tôi nhận được vượt quá ngưỡng đó, tôi giả sử rằng chúng tương tự nhau.

Tôi chưa thử nó hoạt động tốt như thế nào nhưng tôi đoán nó sẽ đủ tốt. Các hình ảnh đã khá giống nhau (trong trường hợp sử dụng của tôi), vì vậy tôi có thể sử dụng giá trị ngưỡng khá cao.

Tôi đoán có hàng tá giải pháp khả thi khác cho việc này sẽ hoạt động ít nhiều (vì bản thân nhiệm vụ này khá đơn giản vì tôi chỉ muốn phát hiện sự tương tự nếu chúng thực sự rất giống nhau). Bạn đề nghị điều gì?


Có một vài câu hỏi rất liên quan / tương tự về việc lấy chữ ký / dấu vân tay / hàm băm từ một hình ảnh:

Ngoài ra, tôi tình cờ phát hiện ra những triển khai có chức năng như vậy để lấy dấu vân tay:

Một số thảo luận về băm hình ảnh tri giác: ở đây


Một chút không chính thống: Tồn tại nhiều phương pháp để tạo dấu vân tay âm thanh. MusicBrainz , một dịch vụ web cung cấp tra cứu dựa trên dấu vân tay cho các bài hát, có một cái nhìn tổng quan tốt trong wiki của họ . Họ đang sử dụng AcoustID ngay bây giờ. Điều này là để tìm kết quả chính xác (hoặc chủ yếu là chính xác). Để tìm các kết quả tương tự (hoặc nếu bạn chỉ có một số đoạn hoặc độ ồn cao), hãy xem Echoprint . Một câu hỏi SO liên quan ở đây . Vì vậy, có vẻ như điều này được giải quyết cho âm thanh. Tất cả các giải pháp này hoạt động khá tốt.

Một câu hỏi hơi chung chung hơn về tìm kiếm mờ nói chung là ở đây . Ví dụ băm nhạy cảm địa phươngtìm kiếm hàng xóm gần nhất .


1
Có lẽ hình ảnh dấu vân tay có thể giúp đỡ? stackoverflow.com/questions/596262/
Mạnh

Số liệu Wasserstein, còn được gọi là Khoảng cách của Earth Mover (EMD), là thứ mà mọi người dường như không biết, nhưng sẽ cung cấp khá nhiều thứ bạn muốn ở đây.
mmgp


Xin chào, tôi đã đưa ra cải tiến dHash - Tôi gọi nó là IDHash: github.com/Nakilon/dhash-vips
Nakilon

Câu trả lời:


107

Ảnh chụp màn hình hoặc biểu tượng có thể được chuyển đổi (thu nhỏ, xoay, nghiêng ...) không? Có khá nhiều phương pháp trên đầu tôi có thể giúp bạn:

  • Khoảng cách euclide đơn giản như được đề cập bởi @carlosdc (không hoạt động với hình ảnh được chuyển đổi và bạn cần một ngưỡng).
  • (Chuẩn hóa) Tương quan chéo - một số liệu đơn giản mà bạn có thể sử dụng để so sánh các khu vực hình ảnh. Nó mạnh hơn khoảng cách euclide đơn giản nhưng không hoạt động trên các hình ảnh được chuyển đổi và bạn sẽ lại cần một ngưỡng.
  • So sánh biểu đồ - nếu bạn sử dụng biểu đồ chuẩn hóa, phương pháp này hoạt động tốt và không bị ảnh hưởng bởi các biến đổi affine. Vấn đề là xác định ngưỡng chính xác. Nó cũng rất nhạy cảm với sự thay đổi màu sắc (độ sáng, độ tương phản, v.v.). Bạn có thể kết hợp nó với hai phần trước.
  • Máy dò các điểm / khu vực nổi bật - chẳng hạn như MSER (Vùng cực hạn ổn định tối đa) , SURF hoặc SIFT . Đây là những thuật toán rất mạnh mẽ và chúng có thể quá phức tạp cho nhiệm vụ đơn giản của bạn. Điều tốt là bạn không cần phải có một khu vực chính xác chỉ với một biểu tượng, những máy dò này đủ mạnh để tìm ra kết quả phù hợp. Một đánh giá tốt đẹp của các phương pháp này là trong bài báo này: Máy dò tính năng bất biến cục bộ: một cuộc khảo sát .

Hầu hết những điều này đã được triển khai trong OpenCV - xem ví dụ phương thức cvMatchTemplate (sử dụng kết hợp biểu đồ): http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html . Các máy dò điểm / khu vực nổi bật cũng có sẵn - xem Phát hiện tính năng OpenCV .


1
Nó có thể được thu nhỏ hoặc di chuyển một chút. Ngoài ra nền của biểu tượng sẽ khác nhau. Tôi đã thử so sánh biểu đồ nhưng tôi nhận được nhiều kết quả dương tính giả. Tôi cũng đã thử khoảng cách euclide nhưng điều đó cũng cho quá nhiều kết quả dương tính giả (nhưng có lẽ tôi có thể làm cho điều đó tốt hơn một chút để xử lý giá trị alpha trong biểu tượng). Tôi sẽ thử thêm một chút nữa, nếu không tôi sẽ kiểm tra MSER, SURF hoặc SIFT.
Albert

1
Một ý tưởng khác - nó sẽ không hoạt động nếu bạn sử dụng so sánh biểu đồ của hình ảnh sau khi áp dụng toán tử sobel? Điều đó sẽ chỉ so sánh sự giống nhau của các cạnh. Có thể hoặc có thể không hoạt động, tùy thuộc vào mức độ "sắc nét" của nền.
Karel Petranek

44

Tôi phải đối mặt với cùng một vấn đề gần đây, để giải quyết vấn đề này (thuật toán đơn giản và nhanh chóng để so sánh hai hình ảnh) một lần và mãi mãi, tôi đóng góp một mô-đun img_hash cho opencv_contrib, bạn có thể tìm thấy các chi tiết từ liên kết này .

Mô-đun img_hash cung cấp sáu thuật toán băm hình ảnh, khá dễ sử dụng.

Mã ví dụ

nguồn gốc lenanguồn gốc lena

lena mờlena mờ

thay đổi kích thước lenathay đổi kích thước lena

ca làm việcca làm việc

#include <opencv2/core.hpp>
#include <opencv2/core/ocl.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/img_hash.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>

void compute(cv::Ptr<cv::img_hash::ImgHashBase> algo)
{
    auto input = cv::imread("lena.png");
    cv::Mat similar_img;

    //detect similiar image after blur attack
    cv::GaussianBlur(input, similar_img, {7,7}, 2, 2);
    cv::imwrite("lena_blur.png", similar_img);
    cv::Mat hash_input, hash_similar;
    algo->compute(input, hash_input);
    algo->compute(similar_img, hash_similar);
    std::cout<<"gaussian blur attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after shift attack
    similar_img.setTo(0);
    input(cv::Rect(0,10, input.cols,input.rows-10)).
            copyTo(similar_img(cv::Rect(0,0,input.cols,input.rows-10)));
    cv::imwrite("lena_shift.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"shift attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;

    //detect similar image after resize
    cv::resize(input, similar_img, {120, 40});
    cv::imwrite("lena_resize.png", similar_img);
    algo->compute(similar_img, hash_similar);
    std::cout<<"resize attack : "<<
               algo->compare(hash_input, hash_similar)<<std::endl;
}

int main()
{
    using namespace cv::img_hash;

    //disable opencl acceleration may(or may not) boost up speed of img_hash
    cv::ocl::setUseOpenCL(false);

    //if the value after compare <= 8, that means the images
    //very similar to each other
    compute(ColorMomentHash::create());

    //there are other algorithms you can try out
    //every algorithms have their pros and cons
    compute(AverageHash::create());
    compute(PHash::create());
    compute(MarrHildrethHash::create());
    compute(RadialVarianceHash::create());
    //BlockMeanHash support mode 0 and mode 1, they associate to
    //mode 1 and mode 2 of PHash library
    compute(BlockMeanHash::create(0));
    compute(BlockMeanHash::create(1));
}

Trong trường hợp này, ColorMomentHash cho chúng ta kết quả tốt nhất

  • tấn công mờ gaussian: 0,567521
  • tấn công thay đổi: 0.229728
  • Thay đổi kích thước cuộc tấn công: 0.22958

Ưu và nhược điểm của từng thuật toán

Hiệu suất dưới các cuộc tấn công khác nhau

Hiệu suất của img_hash cũng tốt

So sánh tốc độ với thư viện PHash (100 hình ảnh từ ukbench) hiệu suất tính toán hiệu suất so sánh

Nếu bạn muốn biết ngưỡng giới thiệu cho các thuật toán này, vui lòng kiểm tra bài đăng này ( http://qtandopencv.blogspot.my/2016/06/int sinhtion-to-image-time-module-of.html ). Nếu bạn thấy thú vị về cách tôi đo hiệu suất của các mô-đun img_hash (bao gồm tốc độ và các cuộc tấn công khác nhau), vui lòng kiểm tra liên kết này ( http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of -opencvimghash.html ).


11

Có phải ảnh chụp màn hình chỉ chứa biểu tượng? Nếu vậy, khoảng cách L2 của hai hình ảnh có thể đủ. Nếu khoảng cách L2 không hoạt động, bước tiếp theo là thử một thứ đơn giản và được thiết lập tốt, như: Lucas-Kanade . Mà tôi chắc chắn có sẵn trong OpenCV.


Subarea chỉ chứa chính xác biểu tượng (với một số nền ngẫu nhiên) hoặc một cái gì đó khác nhau. Tôi muốn xem đó là trường hợp nào. Mặc dù, nó có thể thay đổi hoặc thay đổi kích thước một chút, đó là lý do tại sao tôi không chắc liệu tôi có thể nhìn vào khoảng cách (theo bất kỳ quy tắc nào). Nhưng tôi sẽ thử với một phiên bản thu nhỏ.
Albert

6

Nếu bạn muốn có được một chỉ số về sự giống nhau của hai bức ảnh, tôi đề nghị bạn từ số liệu chỉ số SSIM. Nó phù hợp hơn với mắt người. Đây là một bài viết về nó: Chỉ số tương tự cấu trúc

Nó cũng được triển khai trong OpenCV và nó có thể được tăng tốc với GPU: OpenCV SSIM với GPU


5

Nếu bạn có thể chắc chắn có sự căn chỉnh chính xác của mẫu (biểu tượng) của mình với khu vực thử nghiệm, thì mọi sự khác biệt về pixel cũ sẽ hoạt động.

Nếu việc căn chỉnh sẽ chỉ là một chút nhỏ, thì bạn có thể vượt qua cả hai hình ảnh với cv :: GaussianBlur trước khi tìm ra tổng số chênh lệch pixel.

Nếu chất lượng của căn chỉnh có khả năng kém thì tôi sẽ đề xuất Biểu đồ các Lớp định hướng hoặc một trong các thuật toán phát hiện / mô tả điểm chính thuận tiện của OpenCV (như SIFT hoặc SURF ).


4

Nếu phù hợp với hình ảnh giống hệt nhau - mã cho khoảng cách L2

// 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
}

Nhanh. Nhưng không mạnh mẽ để thay đổi ánh sáng / quan điểm, vv Nguồn


2

Nếu bạn muốn so sánh hình ảnh cho giống nhau, tôi khuyên bạn nên sử dụng OpenCV. Trong OpenCV, có một vài tính năng khớp mẫu và khớp mẫu. Để khớp tính năng, có SURF, SIFT, FAST, v.v. Bạn có thể sử dụng điều này để phát hiện, mô tả và sau đó khớp với hình ảnh. Sau đó, bạn có thể sử dụng chỉ mục cụ thể để tìm số lượng khớp giữa hai hình ảnh.


1
bạn nói "Sau đó, bạn có thể sử dụng chỉ mục cụ thể để tìm số lượng khớp giữa hai hình ảnh." những gì có thể là số lượng phù hợp tối thiểu giữa hai hình ảnh để nói rằng chúng "contais" cùng một đối tượng?
Inês Martins
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.