image comparisson

Pages: 12
ive made a program in vc++ 2010 that automaticly takes a photo with my webcam every 2 seconds. i did this using opencv.
now i need to compare the 2 images to see how similar they are. the result should be something like an integer (eg: 98 is nearly the same photos, 26 is very different photos)

anyone an idea??
You can do pixel by pixel comparisons, but it could take a lot of processing power if images are large.
I would scale the image down to say a 16x12 pixel image (or more or less), using a linear interpolation, and then compare the pixels in the resulting images. According to the amount of delta between the RGB values, you can find out how different the images are.
the default images are 640*480. i could use opencv's cvResize (http://www.seas.upenn.edu/~bensapp/opencvdocs/ref/opencvref_cv.htm#cv_imgproc_resampling and scroll down a little) but i have no idea of wich resize method i should use.

another thing, im from belgium (speaking dutch) and i dont understand what a linear interpolation is. i tried to understand it using wikipedias article about it...

thanks for the help so far
http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
It's a technical term, not your fault.
The resize method is not absolutely important, as your primary target is comparing the images and both images are scaled down in the same manner. Even nearest-neighbor interpolation could work, but I don't recommend doing that, since a lot of pixels would be omitted... which is bad.
thanks. i used
1
2
rframe1 = cvCreateImage(cvSize(32, 24), frame1->depth, frame1->nChannels),
cvResize(frame1, rframe1, CV_INTER_LINEAR);

to resize the images to a smaller variant

since they are bitmaps i could just compare the them with something like this
1
2
3
4
5
6
7
8
9
10
11
12
13
ifstream img1("photo1.bmp", ios::in|ios::binary|ios::ate);
...
s = (int)img1.tellg();
        img1data = new char [s];
        img1.seekg (0, ios::beg);
        img1.read (img1data, s);
        img1.close();
...
for(int i=0; i<s; i++)
    {
        if (img1data[i]==img2data[i]) y++;
        else n++;
    }

then i could just look at how many percent matches...

or is there another simple but better way of doing this??
You need to provide a 'distance' definition.
I think that an 'exact match' is asking for too much. Your image could be a little darker and it will get 0 points.
I suggest to use the euclidean norm: \sum (x_j - y_j)^2

Make sure that you've got a good sampling.
You should use an array of colors, for easier pixel recognition:
img1data=new int [s/4];but make sure that you skip the file header (usually 0x36 bytes), so there should be a s-=0x36; and img1.seekg(0x36,ios::beg); unless of course you have a 24-bit bmp, which has a slight different header size.
After you input all the pixel data using reinterpret_cast, you can make another array of the same size (ex. diff) and store the values of abs(img1[i]-img2[i]). Then you can add up all the values inside diff, so you have a general value of "difference". From that, calculations are very easy to perform.
Last edited on
i understand why you skip the header. but your mehtod doesnt work i always get this when debugging

Windows has triggered a breakpoint in CameraGuard.exe.

This may be due to a corruption of the heap, which indicates a bug in CameraGuard.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while CameraGuard.exe has focus.

The output window may have more diagnostic information.


also i dont really understand what you are doing after that (cast and after)
another thing

on stackoverflow there was someone saying you should do this (http://stackoverflow.com/questions/2644787/precisely-compare-2-images-for-differences-using-opencv)
double ln = cvNorm(frame1, frame2, CV_L2);

but it always return 0...why is that?
i understand why you skip the header. but your mehtod doesnt work i always get this when debugging

What's your code right now?
this is probably the part you wanted to see
some things have dutch names cause im belgian...(eg "vergelijk" is compare)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
int vergelijk(int p)
{
	char *img1data, *img2data, fname[15];
	int s, n = 0, y = 0;

	sprintf(fname, "photo%d.bmp", p - 1);
	cout << "\n" << fname;
	ifstream img1(fname, ios::in|ios::binary|ios::ate);
	sprintf(fname, "photo%d.bmp", p);
	cout << "\n" << fname;
	ifstream img2(fname, ios::in|ios::binary|ios::ate);

	if (img1.is_open() && img2.is_open())
    {
		s = (int)img1.tellg();
		img1data = new char [s];
		img1.seekg (0, ios::beg);
		img1.read (img1data, s);
		img1.close();

		img2data = new char [s];
		img2.seekg (0, ios::beg);
		img2.read (img2data, s);
		img2.close();
	}
	
	for(int i=0; i<s; i++)
        if (img1data[i]==img2data[i]) y++;

	return (y);
}

int main()
{
	void stuurmail();
	int vergelijk(int);

	cvNamedWindow("CameraGuard Snapshots", CV_WINDOW_AUTOSIZE);
    CvCapture *capture = cvCaptureFromCAM(CV_CAP_ANY);
    IplImage *frame1, *rframe1, *frame2, *rframe2;

    int i = 1, key = 0, t, v;

    char fname[15];

	cout << "Running... (ESC to exit)";
	
    while (key != 27)
	{
        frame1 = cvQueryFrame(capture);

		cvShowImage("CameraGuard Snapshots", frame1);

		//rframe1 = cvCreateImage(cvSize(32, 24), frame1->depth, frame1->nChannels);
		//cvResize(frame1, rframe1, CV_INTER_LINEAR);

		sprintf(fname, "photo%d.bmp", i);
		cvSaveImage(fname, frame1);
		
		key = cvWaitKey(2000);

		frame2 = cvQueryFrame(capture);

		//rframe2 = cvCreateImage(cvSize(32, 24), frame2->depth, frame2->nChannels);
		//cvResize(frame2, rframe2, CV_INTER_LINEAR);

		i++;

		sprintf(fname, "photo%d.bmp", i);
		cvSaveImage(fname, frame2);

		cout << "\nvergelijk: " << vergelijk(i);
    }
    cvReleaseCapture(&capture);

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int vergelijk(int p)
{
	char *img1data, *img2data, fname[15];
	int *img1pixels, *img2pixels, *delta;
	int s, n = 0, y = 0;

	sprintf(fname, "photo%d.bmp", p - 1);
	cout << "\n" << fname;
	ifstream img1(fname, ios::in|ios::binary|ios::ate);
	sprintf(fname, "photo%d.bmp", p);
	cout << "\n" << fname;
	ifstream img2(fname, ios::in|ios::binary|ios::ate);

	if (img1.is_open() && img2.is_open())
    {
		s = (int)img1.tellg()-0x36;
		img1data = new char [s];
		img1pixels = new int [s/4];
		img1.seekg (0x36, ios::beg);
		img1.read (img1data, s);
		img1pixels = reinterpret_cast<int*>(img1data);
		img1.close();

		img2data = new char [s];
		img2pixels = new int [s/4];
		img2.seekg (0x36, ios::beg);
		img2.read (img2data, s);
		img2pixels = reinterpret_cast<int*>(img2data);
		img2.close();

		delta = new int [s/4];
	}

	for(int i=0; i<s/4; i++){
	    delta[i] = abs (img1data[i]-img2data[i]);
	    y += delta[i];
    };

	return (y);
}

In fact, the delta array is not even needed, unless you want to keep the data for later processing.
thanks, i used the code but changed the 0x36 into 0x54 (thats the header size for my bmps)
and it works

but theres a problem
if i just put the camera somewhere and i run the program, i can see that the return values are more or less the same...but when i put my hand lets say 0.5m in front of the camera, the return values don't change much more than they normally do...the only thing i can do to make a big difference in the return values is to put my hand 10cm or closer in front of camera

so actually the program isnt sensitive enough for what it should do...
thanks, i used the code but changed the 0x36 into 0x54 (thats the header size for my bmps)
I think it's not. 0x36 is a hexadecimal representation for the decimal number 54. When you say 0x54, in decimal it's actually 84. 0x is the C++ hex prefix. As an example, the hexadecimal code 0x0014A2FF means 1352447 in decimal. As you can see, it's entirely different. Sorry if I confused you.

so actually the program isnt sensitive enough for what it should do...
What range of values do you get? Have you been doing a few *manual* debugging to make sure that the program returns values correctly?
Last edited on
oh yes ur right...stupid of me (the hex thingy)

the range depends on where i place the camera but usually the normal min to max is about 7% difference

oh yes another thing, i just discoverd that it doesnt quit when i ESC
the range depends on where i place the camera but usually the normal min to max is about 7% difference
I'm not sure which exactly is the percent calculation; using the raw value might be easier to debug.
I think the maximum value returned by the vergjilk function should be 12884901120, which is the difference between a full black and a full white image. Try that. And you might want to resize the images to a larger size to create more precision.
you can leave the sensivity thing...i found out that when i leave the camera for about 30s or more that the return values are closer if everything is ok. if i now put for example my finger also on the photo, i can see large enough difference in the return values
thank you very much for helping me so far!!
oh yes another thing, i just discoverd that it doesnt quit when i ESC
What's the code for it?

You're welcome mate!
i use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while (key != 27)
{
        frame1 = cvQueryFrame(capture);
        // capture frame
	cvShowImage("CameraGuard Snapshots", frame1);
        // show frame
        ...
        cvSaveImage(fname, frame1);
        // save frame
        key = cvWaitKey(2000);
        // should wait 2s for keypress and store keypress in var
        frame2 = cvQueryFrame(capture);
        // capture frame2
        ...
        cvSaveImage(fname, frame2);
        // save frame2
        vergelijk(i);
        // the compare function
} // end of the while loop 


the strange thing is that ive used the while with the cvwaitkey before and that it has worked....
ooh ive found it. there are 2 windows open and when i was testing it the focus was on the wrong window

guess i can finish my program now
thanks for the help ;)
Pages: 12