5

Say I have a very simple image or shape such as this stick man drawing:

enter image description here

I also have a library of other simple images which I want to compare the first image to and determine the closest match:

enter image description here

Notice that the two stick men are not completely identical but are reasonably similar.

I want to be able to compare the first image to each image in my library until a reasonably close match is found. If necessary, my image library could contain numerous variations of the same image in order to help decide which type of image I have. For example:

enter image description here

My question is whether this is something that OpenCV would be capable of? Has it been done before, and if so, can you point me in the direction of some examples? Many thanks for your help.

Edit: Through my searches I have found many examples of people who are comparing images, or even people that are comparing images which have been stretched or skewed such as this: Checking images for similarity with OpenCV . Unfortunately as you can see, my images are not just translated (Rotated/Skewed/Stretched) versions of one another - They actually different images although they are very similar.

Community
  • 1
  • 1
user1636130
  • 1,615
  • 5
  • 29
  • 47
  • try "Scale invariant and deformation tolerant partial shape matching" by Damien Michel, Iasonas Oikonomidis and Antonis Argyros : http://www.sciencedirect.com/science/article/pii/S0262885611000151 – Micka Feb 02 '15 at 14:15

6 Answers6

2

You should be able to do it using feature template match function of OpenCV. You can use matchTemplate function to look for the feature and then, minMaxLoc to find its location. Check out the tutorial on OpenCV web site for matchTemplate.

unxnut
  • 8,509
  • 3
  • 27
  • 41
  • Does Template Matching work when the images are rotated slightly from one another? The examples in the OpenCV documentation and from searching google all seem to be using images which are orientated the same direction. – user1636130 Feb 02 '15 at 14:23
  • Should work for small rotation (like 5-10 degrees or so) but beyond that, it may not give very good results. – unxnut Feb 02 '15 at 17:09
1

seems you need feature points detections and matching. Check these docs from OpenCV:

http://docs.opencv.org/doc/tutorials/features2d/feature_detection/feature_detection.html http://docs.opencv.org/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html

iwlagn
  • 477
  • 3
  • 10
1

For your particular type of images, you might get good results by using moments/HuMoments for the connected components (which you can find with findContours).

bjoernz
  • 3,852
  • 18
  • 30
1

since there is a rotation involved, I dont think template matching would work well. You probably need to use Feature point detection such as SIFT or SURF.

Samer
  • 1,923
  • 3
  • 34
  • 54
  • You should be careful with SURF in commercial applications since it's descriptor is patented – iwlagn Feb 02 '15 at 15:15
  • @iwlagn, true. I wonder how did it make it is way to be implemented in opencv? – Samer Feb 02 '15 at 15:53
  • SURF is a good algorithm and no one forbids you from implementing it or using in your research purposes. Implementing patented algorithm is no against BSD license (which is used by OpenCV). So why SURF should not be implemented in OpenCV? – iwlagn Feb 02 '15 at 15:59
  • @iwlagn, am not saying SURF is not a good algorithm, otherwise I won't promote it in the first place. I was wondering how a patented algorithm does not violate BSD licence which allows redistribution of binaries of opencv. – Samer Feb 02 '15 at 16:07
  • There two things here. First is BSD license, which says "do whatever you want but do not remove author information". Second is patented descriptor of SURF (algorithm is not patented as far, as I know). Nothing forbids you from IMPLEMENTING any of algorithms, no matter how many patents do they have (which is done in OpenCV). But patented algorithm can limit USE of this implementation, and this should care only OpenCV users. – iwlagn Feb 02 '15 at 16:32
1

EDIT: This won't work with rotation. Same for matchTemplate. I am yet to try the findContours + moments as in bjoernz answer which sounds promising.

Failed Solution: I tried using ShapeContextDistanceExtractor(1) available in OpenCV 3.0 along with findContours on your sample images to get good results. The sample images were cropped to same size as original image(128*200). You can could as well use resize in OpenCV.


Code below compares images in images folder with 1.png as the base image.

#include "opencv2/shape.hpp"
#include "opencv2/opencv.hpp"
#include <iostream>
#include <string>

using namespace std;
using namespace cv;

const int MAX_SHAPES = 7;

vector<Point> findContours( const Mat& compareToImg )
{
    vector<vector<Point> > contour2D;
    findContours(compareToImg, contour2D, RETR_LIST, CHAIN_APPROX_NONE);

    //converting 2d vector contours to 1D vector for comparison
    vector <Point> contour1D;
    for (size_t border=0; border < contour2D.size(); border++) {
        for (size_t p=0; p < contour2D[border].size(); p++) {
            contour1D.push_back( contour2D[border][p] );
        }
    }

    //limiting contours size to reduce distance comparison time
    contour1D.resize( 300 );
    return contour1D;
}

int main()
{
    string path = "./images/";
    cv::Ptr <cv::ShapeContextDistanceExtractor> distanceExtractor = cv::createShapeContextDistanceExtractor();

    //base image
    Mat baseImage= imread( path + "1.png", IMREAD_GRAYSCALE);

    vector<Point> baseImageContours= findContours( baseImage );

    for ( int idx = 2; idx <= MAX_SHAPES; ++idx ) {

        stringstream imgName;
        imgName << path << idx << ".png";
        Mat compareToImg=imread( imgName.str(), IMREAD_GRAYSCALE ) ;

        vector<Point> contii = findContours( compareToImg );
        float distance = distanceExtractor->computeDistance( baseImageContours, contii );

        std::cout<<" distance to " << idx << " : " << distance << std::endl;
    }

    return 0;
}

Result

distance to 2 : 89.7951
distance to 3 : 14.6793
distance to 4 : 6.0063
distance to 5 : 4.79834
distance to 6 : 0.0963184
distance to 7 : 0.00212693

kiranpradeep
  • 10,859
  • 4
  • 50
  • 82
  • Why did this solution fail? – Alex L Jun 03 '15 at 01:54
  • @AlexL If you check the revision history for his answer, he says it "failed" because it doesn't work with rotations. [For me, that's not a problem, since my images are never rotated.] – Venryx Nov 30 '16 at 21:35
0

Do three things: 1. Forget about image comparison since you really comparing stroke symbols. 2. Download and play wth a Gesture Search app from google store; 3. Realize that for good performance you cannot recognize your strokes without using timestamp information about stroke drawing. Otherwice we would have a successful handwriting recognition. Then you can research Android stroke reco library to write your code properly.

Vlad
  • 4,425
  • 1
  • 30
  • 39