Andrei
Andrei

Reputation: 993

Why is cv::Mat::data always pointing to a uchar?

I try to read a NEF file using LibRaw and then put it in a cv::Mat. The NEF file stores data as 12bit, this means I need 16 bit, so I ought to use CV_16UC4 like this:

Mat img1(height, width, CV_16UC4);

Libraw stores data as ushort*[4], so I thought that this should work:

for (i = 0; i < iwidth*height; i++) {       
    img1.data[4*i+1] = Processor.imgdata.image[i][0];
    img1.data[4*i+2] = Processor.imgdata.image[i][1];
    img1.data[4*i+3] = Processor.imgdata.image[i][2];
    img1.data[4*i+4] = Processor.imgdata.image[i][3];
}

I also get a build error that data may be lost since a ushort to uchar conversion is going to take place, which makes sense, but still, how do I put data bigger than uchar in the data?

Upvotes: 7

Views: 2679

Answers (3)

Kai Wang
Kai Wang

Reputation: 3361

Mat.data looks like a uchar, but actually it contains all the ushort data in the memory. You can simply copy the memory to your ushort array, like this:

memcpy(your_array, img.data, your_array_size);

Upvotes: 0

akarsakov
akarsakov

Reputation: 2154

If you need pointer to raw data of specific type, using cv::Mat::ptr() is the best practice:

ushort* ptr = img1.ptr<ushort>();
for (i = 0; i < iwidth*height; i++) {       
    ptr[4*i+1] = Processor.imgdata.image[i][0];
    ptr[4*i+2] = Processor.imgdata.image[i][1];
    ptr[4*i+3] = Processor.imgdata.image[i][2];
    ptr[4*i+4] = Processor.imgdata.image[i][3];
}

Please see documentation.

Upvotes: 3

nils
nils

Reputation: 2534

cv::Mat::data uses uchar in order avoid being a template class. In order to fill it with other image data you'll need to cast the data pointer. In your case try something like this:

Mat img1(height, width, CV_16UC4);
ushort * data = reinterpret_cast< ushort* >( img1.data );

for (i = 0; i < iwidth*height; i++) {
...
}

Alternatively, instead of changing the data pointer img1.data directly in your for-loop, you could consider using

  1. the templated pixel access function cv::Mat::at<T>()

    img1.at<Vec4w>(y,x) = reinterpret_cast<Vec4w>(Processor.imgdata.image[i])
    
  2. use the specialized class Mat4w img(height, width) and then operator(y,x)

    img1(y,x) = reinterpret_cast<Vec4w>(Processor.imgdata.image[i])
    

Upvotes: 1

Related Questions