divide two matrices in opencv

14,252

Solution 1

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.

Solution 2

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 div-by-0-equals-0 (as you stated from the documentation), but also note rounding (rounding) and tie-break-1-2 while tie-break-3-2 (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;
}
Share:
14,252
arthur.sw
Author by

arthur.sw

Here is what I really enjoy about computer science, and how I participate: Computer vision &amp; IA: I work at INRIA, a public research body dedicated to digital science and technology. Digital art: I am one of the engineers of La Sophiste

Updated on June 08, 2022

Comments

  • arthur.sw
    arthur.sw almost 2 years

    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.