Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV Integer division in c++ not as expected

Tags:

c++

opencv

Given the following output:

[11233, 11345, 11434, 10897] [44, 44, 45, 43] [-31, 81, -86, -111]

from this code

std::cout << mat32sc1;
channels[1] = mat32sc1 / 256;
channels[0] = mat32sc1 - channels[1] * 256;
std::cout << channels[1];
std::cout << channels[0];

I would have expected 11233 / 256 to be 43, using integer division?

Is my assumption wronge that c++ always do integer division by flooring?

Update

Here is my current encoding function.

void encode(cv::Mat & src, cv::Mat & dst)
{
    cv::Mat_<int> mat32sc1;
    src.convertTo(mat32sc1, CV_32SC1, 10, 11000);

    std::vector<cv::Mat> channels;
    channels.resize(3);

//  bitwise_and(mat32sc1, cv::Scalar(255), channels[0]); // is this needed or will converTo truncate automaticly.
//  channels[0].convertTo(channels[0], CV_8UC1);
//  mat32sc1.convertTo(channels[1], CV_8UC1, 1.0 / (1 << 8));
    channels[2] = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);
    int flag = 256;
//  std::cout << mat32sc1;
    channels[1] = mat32sc1 / flag;
    channels[0] = mat32sc1 - channels[1] * flag;
    cv::Mat_<int> off = (channels[0] < 0) / 255;
    //std::cout << off;
    channels[1] -= off;
    channels[0] = mat32sc1 - channels[1] * flag;


    //std::cout << channels[1];
    //std::cout << channels[0];
    channels[0].convertTo(channels[0], CV_8UC1);
    channels[1].convertTo(channels[1], CV_8UC1);

    cv::merge(channels, dst);
}

Any smarter way to get the same result

like image 693
Poul K. Sørensen Avatar asked Sep 22 '14 06:09

Poul K. Sørensen


2 Answers

The division is indeed not an integer division. Most functions in OpenCV convert their input to Scalar, which is container for 1, 2, 3, or 4 doubles. And other functions in OpenCV that perform similar operations (scaleAdd, addWeighted, convertTo, etc...) all works with doubles as well. In other words, your code performing division by double and rounding of the result. This is why you got 44 instead of 43.

Edit:

As for the "encode" function you don't need to perform complex operations. The bytes for your new matrix are already there. You just need to create convenient way of accessing them:

Mat temp(src.size(), CV_8UC4, src.data);

This will create new matrix header (i.e. no copy of data) that point to the data of src. But instead of seeing the data as integer matrix with single channel, it will be 4-channel matrix of unsigned char (with same width and height). Than you can do anything with multi-channel matrix: split(), merge(), mixChannels(), etc...

like image 72
Michael Burdinov Avatar answered Oct 04 '22 20:10

Michael Burdinov


No, you're right, integer division is performed by flooring in C++. See [expr.mul]:

For integral operands the / operator yields the algebraic quotient with any fractional part discarded; 81

81) This is often called truncation towards zero.

like image 40
Fytch Avatar answered Oct 04 '22 21:10

Fytch