[SOLVED] how to average N matrices into 1?

Hello, this is probably pretty straightforward, but I am very new to OpenCV.

I have a camera frame grabber application where the user is allowed to "average" N frames into a single frame (as a way to reduce signal to noise ratio)

So I have 3 (or N) Mat's all the same size (16bit grayscale) and I want to combine them all into one such that the result is the "average" of the 3.. So this isn't really a blending of unique images, each frame is going to be nearly identical, the goal is to average them to reduce the signal to noise.

What's the best way to do this?

edit: I tried cvAccumulate, but it fails, I'm thinking because the documentation says it works only for 8 or 32bit images.

I did make this work by brute-force (non OpenCV) looping, summing, averaging and then setting those values into my final/averaged matrix.. but is there a better way with OpenCV?

Thanks

edit retag close merge delete

Sort by » oldest newest most voted

this is a bit tricky. since adding up 8 or 16 bit images might lead to overflow, you need an image with a type larger than your single pics to hold the accumulated values.

Mat img = imread("lena.jpg", 0); // grayscale for simplicity
Mat acc(img.size(), CV_64F, Scalar(0)); // all black, *double* image
accumulate(img,acc);
accumulate(img,acc);
accumulate(img,acc);
accumulate(img,acc);
Mat avg;
acc.convertTo(avg, CV_8U, 1.0/4); // back to u8 land, divide by count
imshow("average", avg);
waitKey();
more

Thank you for the reply. This is interesting. But I don't follow how the overflow may happen. I'm not summing the images, I want to produce one that is the average of 3. So if my pixel values all fit in the 16bit matrix, the average value of 3 16bit values is still a 16bit value, no?

the average sure fits, but to achieve that, you have to take the (temporary) sum, which will not.

1

if you don't care about that, it would be just : Mat a,b,c,d; Mat avg = (a+b+c+d)/4; // nice & short, but suffers heavily from saturation

oh I see. And then to convert my accumulated (CV_64F) matrix back to 16bit (not 8) does this still apply: acc.convertTo(avg, CV_16UC, 1.0/4)

yea, sorry. the 8bit example was more for reading 8bit grayscale imread() examples.

the scale factor here is just 1/count, so : acc.convertTo(avg, CV_16U, 1.0/4);

sorry I just noticed your earlier comment about just (a+b+c+d)/4 and suffering heavily from saturation.. I had tried that, and noticed the ugliness, but can you explain why that was the case and why cvAccumulate solves that problem?

(sorry for making it an 8bit example again, it's just easier to demonstrate)

sum=0; // as long as sum can't be larger than 255(has to fit into 8bit), we got a problem

a=125; // fictional pixel value

sum += a // sum is 125, still fits into 8bit

b = 132; // it get's hot

sum += b:

sum == 125 + 132 == 257; // opencv will saturate to the largest valid value(255) here

c = 5;

sum += c; // whatever you add here, it's already lost. sum just *can't get larger than 255

...

(it's all about getting enough leeway for the summation)

1. sure, feel free to add anything helpful to others (that's the purpose of this site, no ?) ;)
2. would this answer it ?

Stats

Asked: 2014-09-25 10:51:04 -0500

Seen: 1,360 times

Last updated: Sep 25 '14