Reputation: 11619
I would like to perform a element-wise division of two opencv CV_32S matrices (A & B).
I want C = A/B when B is not 0, 0 otherwise.
But I'm not sure to understand opencv documentation:
http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#divide
It says:
When src2(I) is zero, dst(I) will also be zero. Different channels of multi-channel arrays are processed independently.
Note Saturation is not applied when the output array has the depth CV_32S. You may even get result of an incorrect sign in the case of overflow.
What does the saturate() function? Can I use divide(A,B,C) safely with CV_32S matrices? How is divide() different from the / operator?
===== EDIT AFTER TEST =====
My test showed that the / operator does exactly what I want: C = A/B when B != 0, 0 otherwise.
Upvotes: 5
Views: 17682
Reputation: 1794
So, operator/
and cv::divide
should be actually the same, except that the operator will return a matrix expression, whose evaluation is delayed. Finally, also operator/
will call cv::divide
, as can be seen e. g. for a simple case here. Especially the results should be equal.
Still, the results can be surprising. Using two integer matrices for division, the result will be like done in floating point arithmetic followed by a round to nearest integer preferring even numbers (see also nearbyint()
). As an example, using two 6x6 integer matrices, you will get
0/0 == 0 1/0 == 0 2/0 == 0 3/0 == 0 4/0 == 0 5/0 == 0
0/1 == 0 1/1 == 1 2/1 == 2 3/1 == 3 4/1 == 4 5/1 == 5
0/2 == 0 1/2 == 0 2/2 == 1 3/2 == 2 4/2 == 2 5/2 == 2
0/3 == 0 1/3 == 0 2/3 == 1 3/3 == 1 4/3 == 1 5/3 == 2
0/4 == 0 1/4 == 0 2/4 == 0 3/4 == 1 4/4 == 1 5/4 == 1
0/5 == 0 1/5 == 0 2/5 == 0 3/5 == 1 4/5 == 1 5/5 == 1
Note the (as you stated from the documentation), but also note (rounding) and while (tie break to even).
Beware: Two floating point type matrices do not define any special behavior, but rather evaluate to -inf, nan or inf in case of division by zero. This even holds, when you divide two floating point matrices, but requesting an integer result. In that case -inf, nan and inf will translate to the minimum value, which might be a bug (or just not defined by OpenCV).
Code for integer division div.cpp
(compile with g++ -std=c++11 div.cpp -o div -lopencv_core
):
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdint>
int main() {
cv::Mat i1(6,6,CV_32S);
cv::Mat i2(6,6,CV_32S);
for (int y = 0; y < i1.rows; ++y) {
for (int x = 0; x < i1.cols; ++x) {
i1.at<int32_t>(y, x) = x;
i2.at<int32_t>(y, x) = y;
}
}
cv::Mat q;
cv::divide(i1, i2, q);
// q = i1 / i2;
for (int y = 0; y < q.rows; ++y) {
for (int x = 0; x < q.cols; ++x)
std::cout << x << "/" << y << " == " << q.at<int32_t>(y, x) << "\t";
std::cout << std::endl;
}
return 0;
}
Upvotes: 4
Reputation: 20130
saturate_cast prevents overflows for some data types, so that pixel values 200+200
are reduced to 255 for CV_8U
for example (otherwise there would be an overflow and maybe unexpected values occur).
Have a look at the link if you want to know more about saturate_cast. http://docs.opencv.org/modules/core/doc/intro.html#saturation-arithmetics
Since integer division always reduces the absolute values, there should no overflows occur in integer division (or am I missing something?), so you should be safe I guess.
Upvotes: 2