kcc__ kcc__ - 3 months ago 14
C++ Question

C++ data packing from uchar to int (both positive and negative numbers)

I have a OpenCV Mat of type CV_32S with contains integer values of >= -1.
I am trying to access the underlying data pointer which is a flat 1D array of type

uchar
.

I suppose that since
int
is 4 byte [32 bits] and
uchar
is 1 byte [8 bits] I need to unpack the data into int type which is initially provided in a OpenCV Mat structure.

cv::Mat opencv_data; //! data of type CV_32 with both negative and positive values.


I pass the
uchar *data
pointer of
opencv_data
to cuda kernel.
To unpack the four
uchars
into single
int
I doing the following.

int value = (uchar)opencv_data[index] |
(((uchar)opencv_data[index + 1]) << 8) |
(((uchar)opencv_data[index + 2]) << 16);


When the opencv_data has only positive values I get the correct unpack value in
value
. However if I put a single negative number in
opencv_data
the above unpacking produces
value = -1
.

I fail to understand the reason behind this problem and I need help with this.

EDIT: based on suggestion to use
reinterpret_cast
. The update code is below but for negative numbers the result is still not correct.

//! for test only
cv::Mat test = cv::Mat(40, 60, CV_32S);

for (int j = 0; j < test.rows; j++) {
for (int i = 0; i < test.cols; i++) {
test.at<int>(j, i) = -2;
}
}

int INDICES_BYTE = test.step * test.rows;
uchar *data = reinterpret_cast<uchar*>(test.data);
for (int i = 0; i < INDICES_BYTE; i += 4) {
int index = reinterpret_cast<uchar>(data[i]) |
(reinterpret_cast<uchar>(data[i + 1]) << 8) |
(reinterpret_cast<uchar>(data[i + 2]) << 16) |
(reinterpret_cast<uchar>(data[i + 3]) << 32);
std::cout << index << "\n";
}


The edited code produces correct result for positive number but not for negative numbers in
test
.

Eg: for -2 the result is 16777215

Answer

It would appear that there are a few concepts you have misunderstood here.

The openCV mat stores the address of the memory allocation which holds the matrix data in a uchar *. This doesn't mean that the data is in any way transformed. If you want to access the data associated with the matrix directly, you simply cast the pointer to the correct type and use that cast pointer. Like this:

#include <opencv2/core/core.hpp>
#include <iostream>

int main()
{
    cv::Mat test = cv::Mat(4, 6, CV_32S);
    for (int j = 0; j < test.rows; j++) {
       for (int i = 0; i < test.cols; i++) {
          test.at<int>(j, i) = -2*i;
       }
    }

    int *p = reinterpret_cast<int*>(test.data);
    for(int j=0; j<test.rows; ++j) {
        for(int i=0; i<test.cols; ++i) {
            std::cout << j << "," << i << " = " << p[i] << std::endl;
        }
        p += test.cols;
    }

    return 0;
}
Comments