Ask Your Question

Adding Matrices without saturation

asked 2013-05-23 03:38:13 -0600

xsmet gravatar image

Is it possible to add two matrices (with values in [0, 255]) and store the result in a matrix with values in [0, 510]?

I would be adding up to 100 matrices that way, and want to keep the high precision (which rules out the use of cv::addWeighted()). A 16-bit int per pixel should suffice to contain these values.

I hoped this would work:

Mat A(10, 10, CV_8UC1, 200);
Mat B(10, 10, CV_8UC1, 200);
Mat C(10, 10, CV_32S, 0);
cv::add(A, B, C);

But the values in C are saturated to 255 (rather than value 400 being stored in some 16-bit data type).

Any suggestions are highly appreciated!

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted

answered 2013-05-23 04:01:11 -0600

Guanta gravatar image

Afaik with cv::add or +-operator you'll always have a saturate cast, so if you want to use these functions you'd need to convert A and B to CV_32S first:

A.convertTo(C, CV_32S);
B.convertTo(B, CV_32S);
C += B;

However: What speaks really against cv::addWeighted? I don't get your reason. I doubt, that

cv::addWeighted(A, 1, B, 1, 0, C, C.type());

is less efficient than simple add.

At last, what you can always do: loop over the matrix-dimension by hand and add the matrix-values.

edit flag offensive delete link more



About addWeighted(): I was trying to work with integer numbers in [0, 255], and similarly integer numbers in [0, 100*255]. The code would run on an embedded platform, so I tried to do everything with plain 16-bit ints, and I could not tolerate any loss of precision (which might, theoretically, have been possible with CV_32F).

I didn't say that addWeighted() was less efficient, but I meant to say that it can be slightly less accurate.

xsmet gravatar imagexsmet ( 2013-05-27 09:40:09 -0600 )edit

answered 2013-05-23 04:16:03 -0600

berak gravatar image

updated 2013-05-23 04:24:12 -0600

void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)

if you don't specify the dtype arg in cv::add() the 3rd arg will get reallocated to the type(and size) of the input operands, and your initialization of C will get completely ignored. if you check C.type() after the add(A,B,C) you'll find, that it's type is CV_8UC1, not CV_32S.

so, give it an empty mask param, and specify dtype:

Mat A(4, 4, CV_8UC1, 200);
Mat B(4, 4, CV_8UC1, 200);
Mat C; //(4, 4, CV_32S, 0);  // allocation will get ignored anyway(OutputArray)
cv::add(A, B, C,Mat(),CV_32S);
cout << C.type() << endl;
cout << C << endl;


[400, 400, 400, 400;
 400, 400, 400, 400;
 400, 400, 400, 400;
 400, 400, 400, 400]
edit flag offensive delete link more


ah, didn't double-check the actual add-method :), seems the easiest solution

Guanta gravatar imageGuanta ( 2013-05-23 05:23:42 -0600 )edit

didn't knew that before, too ;)

berak gravatar imageberak ( 2013-05-23 05:26:12 -0600 )edit

answered 2013-05-27 09:39:24 -0600

xsmet gravatar image

Both solution work, thanks guys.

The first one (berak's) is more efficient without the conversions.

The second one (Guanta's) gets kudos for allowing the use of operator+ etc., looks better in code.

I also learned about OpenCV accumulator images meanwhile, worth a read for anyone interested.

edit flag offensive delete link more


+1 for the accumulator ;)

( was just scratching my head, how to get the mean of 500 face-images, when i saw your answer, so thanks ! )

berak gravatar imageberak ( 2013-05-27 09:48:00 -0600 )edit

Question Tools


Asked: 2013-05-23 03:38:13 -0600

Seen: 3,675 times

Last updated: May 27 '13