Programing

유사성을 위해 이미지를 비교하는 간단하고 빠른 방법

crosscheck 2020. 5. 17. 15:40
반응형

유사성을 위해 이미지를 비교하는 간단하고 빠른 방법


유사성을 위해 두 이미지를 비교하는 간단하고 빠른 방법이 필요합니다. 즉, 정확히 같은 것을 포함하지만 약간 다른 배경을 가질 수 있고 몇 픽셀만큼 이동 / 크기 조정 될 수 있다면 높은 가치를 얻고 싶습니다.

(더 구체적인 경우, 하나의 그림은 아이콘이고 다른 그림은 스크린 샷의 하위 영역이며 해당 하위 영역이 정확히 아이콘인지 여부를 알고 싶습니다.)

나는 OpenCV가지고 있지만 여전히 익숙하지 않습니다.

내가 지금까지 생각한 한 가지 가능성 : 두 그림을 10x10 셀로 나누고 그 100 셀 각각에 대해 색상 막대 그래프를 비교하십시오. 그런 다음 일부 구성 임계 값을 설정할 수 있으며 얻은 값이 해당 임계 값보다 높으면 비슷한 것으로 가정합니다.

나는 그것이 얼마나 잘 작동하는지 아직 시도하지 않았지만 충분할 것이라고 생각합니다. 이미지는 이미 사용 사례와 거의 비슷하므로 매우 높은 임계 값을 사용할 수 있습니다.

나는 이것에 대해 수십 가지 다른 가능한 해결책이 있다고 생각합니다 (작업이 매우 유사하기 때문에 유사성을 감지하고 싶기 때문에 작업 자체가 매우 간단하기 때문에). 무엇을 제안 하시겠습니까?


이미지에서 서명 / 지문 / 해시를 얻는 것과 관련하여 매우 관련이 있거나 유사한 몇 가지 질문이 있습니다.

또한 지문을 얻는 기능을 가진 이러한 구현을 우연히 발견했습니다.

지각 적 이미지 해시에 대한 몇 가지 토론 : here


약간의 주제 : 오디오 지문을 만드는 방법에는 여러 가지가 있습니다. 노래에 대한 지문 기반 조회를 제공하는 웹 서비스 인 MusicBrainz 는 Wiki에서 좋은 개요를 제공합니다 . 그들은 현재 AcoustID 를 사용 하고 있습니다. 일치하는 (또는 대부분 정확한) 일치를 찾기위한 것입니다. 유사한 일치 항목을 찾으려면 (또는 일부 스 니펫이나 노이즈가 높은 경우) Echoprint를 살펴 보십시오 . 관련 SO 질문이 있습니다 . 오디오에서 해결 된 것 같습니다. 이 모든 솔루션은 아주 잘 작동합니다.

퍼지 검색에 대한 일반적인 질문이 여기 있습니다 . 예를 들어 지역에 민감한 해싱가장 가까운 이웃 검색이 있습니다.


스크린 샷 또는 아이콘을 변형 (확장, 회전, 기울이기 등) 할 수 있습니까? 내 머리 위에 도움이 될만한 몇 가지 방법이 있습니다.

  • @carlosdc가 언급 한 간단한 유클리드 거리 (변환 된 이미지에는 작동하지 않으며 임계 값이 필요합니다).
  • (정규화 된) 상호 상관 -이미지 영역을 비교하는 데 사용할 수있는 간단한 메트릭입니다. 단순한 유클리드 거리보다 강력하지만 변환 된 이미지에서는 작동하지 않으므로 다시 임계 값이 필요합니다.
  • 히스토그램 비교 -정규화 된 히스토그램을 사용하는 경우이 방법이 효과적이며 아핀 변환의 영향을받지 않습니다. 문제는 올바른 임계 값을 결정하는 것입니다. 또한 색상 변화 (밝기, 대비 등)에 매우 민감합니다. 이전 두 가지와 결합 할 수 있습니다.
  • MSER (Maximally Stable Extremal Regions) , SURF 또는 SIFT 와 같은 주요 지점 / 영역 탐지기 . 이것들은 매우 강력한 알고리즘이며 간단한 작업에는 너무 복잡 할 수 있습니다. 좋은 점은 아이콘이 하나만있는 정확한 영역을 가질 필요가 없다는 것입니다. 이러한 탐지기는 올바른 일치를 찾을 수있을만큼 강력합니다. 이러한 방법에 대한 좋은 평가는이 백서에 있습니다 : 지역 불변 피처 탐지기 : 측량 .

이들 중 대부분은 이미 OpenCV로 구현되어 있습니다 (예 : cvMatchTemplate 메소드 (히스토그램 일치 사용) 참조 : http://dasl.mem.drexel.edu/~noahKuntz/openCVTut6.html) . 두드러진 점 / 영역 검출기도 사용할 수 있습니다 ( OpenCV 기능 감지 참조) .


나는 최근에 같은 문제에 직면 하여이 문제 (두 이미지를 비교하는 간단하고 빠른 알고리즘)를 해결하기 위해 img_hash 모듈 을 opencv_contrib에 기여합니다 . 이 링크 에서 세부 정보를 찾을 수 있습니다 .

img_hash 모듈은 사용하기 쉬운 6 개의 이미지 해시 알고리즘을 제공합니다.

코드 예

원산지 레나원산지 레나

블레나블레나

레나 크기 조정레나 크기 조정

교대 레나교대 레나

#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));
}

이 경우 ColorMomentHash는 최상의 결과를 제공합니다.

  • 가우스 블러 공격 : 0.567521
  • 시프트 어택 : 0.229728
  • 크기 조정 공격 : 0.229358

각 알고리즘의 장단점

다른 공격에서 성능

img_hash의 성능도 좋습니다

PHash 라이브러리와 속도 비교 (ukbench의 100 개 이미지) 계산 성능 비교 성능

If you want to know the recommend thresholds for these algorithms, please check this post(http://qtandopencv.blogspot.my/2016/06/introduction-to-image-hash-module-of.html). If you are interesting about how do I measure the performance of img_hash modules(include speed and different attacks), please check this link(http://qtandopencv.blogspot.my/2016/06/speed-up-image-hashing-of-opencvimghash.html).


Does the screenshot contain only the icon? If so, the L2 distance of the two images might suffice. If the L2 distance doesn't work, the next step is to try something simple and well established, like: Lucas-Kanade. Which I'm sure is available in OpenCV.


If you want to get an index about the similarity of the two pictures, I suggest you from the metrics the SSIM index. It is more consistent with the human eye. Here is an article about it: Structural Similarity Index

It is implemented in OpenCV too, and it can be accelerated with GPU: OpenCV SSIM with GPU


If you can be sure to have precise alignment of your template (the icon) to the testing region, then any old sum of pixel differences will work.

If the alignment is only going to be a tiny bit off, then you can low-pass both images with cv::GaussianBlur before finding the sum of pixel differences.

If the quality of the alignment is potentially poor then I would recommend either a Histogram of Oriented Gradients or one of OpenCV's convenient keypoint detection/descriptor algorithms (such as SIFT or SURF).


If for matching identical images - code for L2 distance

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

Fast. But not robust to changes in lighting/viewpoint etc. Source


If you want to compare image for similarity,I suggest you to used OpenCV. In OpenCV, there are few feature matching and template matching. For feature matching, there are SURF, SIFT, FAST and so on detector. You can use this to detect, describe and then match the image. After that, you can use the specific index to find number of match between the two images.

참고 URL : https://stackoverflow.com/questions/4196453/simple-and-fast-method-to-compare-images-for-similarity

반응형