4

I want to subtract two images. My problem ist that the cvSub()-function saturates. What I want to do is:

1) Convert the original images to grayscale.

2) Take the grayscale-images (values from 0-255).

3) Subtract the images (values from -255 to 255) -> problem of rescaling using cvSub().

4) Rescale by multiplying with 0.5 and adding 128.

I thought of changing the gray-scale images from 8bit to 16bit, but then everything got worse and it became many lines of code and in the end it didn't work out.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
supergranu
  • 91
  • 2
  • 3
  • 9
  • The ugly solution is just to loop over the images and do it yourself per pixel. That's basically just translating your question in C++ (should even be shorter). – mb14 Sep 07 '10 at 08:55

2 Answers2

5

Using openCV you could do the following:

  • scale both source images (1 and 2) by factor 0.5. Both images are now in range [0..127]
  • shift image 1 by 128. It now is in the range [128..255]
  • subtract image 2 from image 1

This way, no range conversion is needed and the result is fully scaled to 8 bit. Use the cvConvertScale for the first two operations.

Something like this:

//...
cvConvertScale(src1, tmp1, 0.5, 128);
cvConvertScale(src2, tmp2, 0.5, 0);
cvSub(tmp1, tmp2, dst);

EDIT:

To your comment on loosing information(precision), you are right, but you always do when dividing using integer math. And scaling in your case is just that. Simply think of it as shifting all the bits to the right by one place. So the last bit of information is lost.

On the other hand, the order of the applied operations is also important. By dividing by 2 you introduce a rounding (or truncation) error of 0.5 for every pixel. If you scale both input images before subtracting them, the rounding error adds up to 1.0. This shows up in the result image as some pixels being off by 1 compared to the result you would get with your initial and Alexanders approach. But that is the tradeoff for the simpler solution without expanding the image to 16-bit or floating point.

See this example:

real numbers:
(200 - 101) / 2 = 99 / 2 = 49.5

Alexanders solution (integer math):
(200 - 101) / 2 = 99 /2 = 49

my Solution (integer math):
(200 / 2) - (101 / 2) = 100 - 50 = 50

Frank Bollack
  • 24,478
  • 5
  • 49
  • 58
  • 1
    Thanks for the simple solution!!! It worked out! - Good idea to do the scaling first and then subtract the pictures. – supergranu Sep 08 '10 at 12:07
  • The only problem is that one looses information. In that case it's better to choose the version of Alexander Rafferty. – supergranu Sep 09 '10 at 06:59
  • Can you tell me where do you think, you loose information? Do you mean precision? – Frank Bollack Sep 09 '10 at 07:01
  • 1
    I think it's an 8bit image. If I multiply by 0.5 I can only use 128 values to store the image's information. 256 values are reduced to 128. I will loose resolution of the original image. - Tell me if this thought is wrong. – supergranu Sep 09 '10 at 07:59
1

You need to convert from 8bit to 16bit. Then add 255 to the first image, then subtract the second image from it. Then divide by two and convert back to 8bit.

Tell me how this goes, it should work.

Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55