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

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?

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.

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
the templated pixel access function cv::Mat::at<T>()
img1.at<Vec4w>(y,x) = reinterpret_cast<Vec4w>(Processor.imgdata.image[i])
use the specialized class Mat4w img(height, width) and then operator(y,x)
img1(y,x) = reinterpret_cast<Vec4w>(Processor.imgdata.image[i])

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);

Related

binary copy data from struct to std::vector

I am using a lib which can load BMP images from memory.
I have a class which represents a BMP.
To load from memory I have to supply a pointer to some BMP formatted data in memory and a variable for the size of that data. (void* data, size_t length)
I want to store my data in a std::vector. (Avoids manual memory management)
I've attempted to write a function to return a std::vector<unsigned char>, but I don't think what I've got is very good.
std::vector<unsigned char> BMP::BITMAP::SaveMem() const
{
// memory storage
std::vector<unsigned char> memory;
BITMAPFILEHEADER f_head;
f_head.bfType = ushort_rev(((WORD)'B' << 0x08) | ((WORD)'M' << 0x00));
f_head.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_width_memory * m_height;
f_head.bfReserved1 = 0;
f_head.bfReserved2 = 0;
f_head.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// build standard bitmap file header
BITMAPINFOHEADER i_head;
i_head.biSize = sizeof(BITMAPINFOHEADER);
i_head.biWidth = m_width;
i_head.biHeight = m_height;
i_head.biPlanes = 1;
i_head.biBitCount = m_bit_count;
i_head.biCompression = 0;
i_head.biSizeImage = m_width_memory * m_height;
i_head.biXPelsPerMeter = 0;
i_head.biYPelsPerMeter = 0;
i_head.biClrUsed = 0;
i_head.biClrImportant = 0;
// alloc
memory.resize(f_head.bfSize);
std::copy(&f_head, &f_head + sizeof(f_head), memory.at(0));
std::copy(&i_head, &i_head + sizeof(i_head), memory.at(0) + sizeof(f_head));
// write data
for(unsigned int y = 0; y < m_height; ++ y)
{
std::copy(&m_data[y * m_width_memory], m_data[y * m_width_memory + 3 * m_size_x], memory.at(0) + sizeof(f_head) + sizeof(i_head));
}
}
Clearly this doesn't compile. I can't think of any alternative to std::copy. Is this really the right tool for the job?
To make it compile I think I should change memory.at(x) to memory.data() + x... By doing this I would be using raw pointers - which is why I don't think std::copy is any better than memcpy.
Could I have some advice on this? It's somewhat an illogical task and had I known about this requirement earlier I would have stored my pixel data in an unsigned char with the bitmap file headers preceeding the data. Unfortunatly it will be a lot of work to change the design now, so I'd rather not touch it.
Three problems:
You want to copy bytes, but the std::copy function is provided a pointer to a BITMAPFILEHEADER (or BITMAPINFOHEADER) structure. You need to convert the pointers to bytes, like reinterpret_cast<uint8_t*>(&f_head).
The previous leads to other problems with the end of the data, the expression &f_head + sizeof(f_head) which really is equal to (&f_head)[sizeof(f_head)], and is way beyond the end of the structure. You need to use bytes here as well, as in reinterpret_cast<uint8_t*>(&f_head) + sizeof f_head.
The last problem is the destination for the std::copy call, as it needs to be a similar type as the source, i.e. a pointer to uint8_t (in the case of my casts). You can easily get that by doing e.g. &memory[0]. And for the second call &memory[sizeof f_head].

Flatten array of structs efficiently

I'm looking for the most efficient way to flatten an array of structs in C++ for passing the flattend 1D array data as input to a cv::Mat. The struct looks as follows:
struct Color3
{
uint8_t red, green, blue;
}
My code then looks like this:
// Update color frame
cv::Mat colorMat = cv::Mat::zeros(cv::Size(1920, 1080), CV_8UC3)
const Color3* colorPtr = colorFrame->getData(); // Get Frame from Library
std::vector<uchar> vecColorData;
data.reserve(1920 * 1080 * 3);
for (int i = 0; i < 1920 * 1080; ++i)
{
auto color = *colorPtr;
vecColorData.push_back(color.red);
vecColorData.push_back(color.green);
vecColorData.push_back(color.blue);
vecColorData++;
}
colorMat.data = vecColorData.data();
Is there a more efficient way than creating an intermediate std::vector and looping over the entire array? I guess I'm looking for something like:
colorMat.data = colorFrame->getData()
However, I'm getting the following error: a value of type Color3* cannot be assigned to an entity of type uchar*.
you don't need an intermediate vector.
If I understood, you want to assign the same RGB triple to all data.
It is also unclear to me if you have to allocate colorMat.data on your own or not.
If this is the case, once colorMat.data is allocated and sized 1920 * 1080 * 3, you can do something like the following:
uchar * data = colorMat.data;
for (int i = 0; i < 1920 * 1080; ++i)
{
*data++ = (uchar)colorPtr->red;
*data++ = (uchar)colorPtr->green;
*data++ = (uchar)colorPtr->.blue;
}
The following answer is not technically portable but will work on the vast majority of platforms you will encounter in real life.
It is extremely likely that your Color3 struct has no padding. You can veryify this by using a static_assert:
static_assert(sizeof(Color3) == sizeof(uint8_t) * 3);
With this confirmed you can cast an array of Color3 to an array of uint8_t and pass it directly to colorMat.data (assuming that member actually accepts uint8_t).
Your code therefore becomes:
cv::Mat colorMat = cv::Mat::zeros(cv::Size(1920, 1080), CV_8UC3)
const Color3* colorPtr = colorFrame->getData(); // Get Frame from Library
colorMat.data = reinterpret_cast<const uint8_t*>(colorPtr);
Bear in mind I have never used the cv library and know nothing about the ownership requirements of the data pointer. The above just replicates what you're doing without the unnecessary std::vector.

Opening a 3d matlab file in C++ with Matio

So I have a matlab file that is a 3d matrix. I am using C++ to read in the file, specifically with matio.h but I am having some trouble/confusion with reading the actual data. I know how to find out how many dimensions, rank, and name of the data, but to actually read in the data is the hard part. Currently I have
mat_t *mat = Mat_Open(result, MAT_ACC_RDONLY);
matvar_t *matvar;
matvar = Mat_VarReadNExtInfo(mat);
int r = matvar->dims[0];
I guess I am confused as to how to use the matvar->data pointer.
You can select your variable by using:
matvar_t *matVar = NULL;
matVar = Mat_VarRead(mat, (char*)"VarName");
Reading the data is possible through:
unsigned Size = matVar->nbytes/matVar->data_size ;
const double *Data = static_cast<const double*>(matVar->data) ;
for(int i=0; i<Size; ++i)
{
std::cout<<"\t["<<i<<"] = "<<Data[i]<<"\n" ;
}
As it is C Code the values are behind each other in memory. With this solution you have to reshape the double array into an 3D Array on your own by using the dimensions.
Another solution could be using the function Mat_VarReadDataAll.

C++ - Convert uint8_t* image data to double** image data

I am working on a C++ function (inside my iOS app) where I have image data in the form uint8_t*.
I obtained the image data using the code using the CVPixelBufferGetBaseAddress() method of the iOS SDK:
uint8_t *bPixels = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
I have another function (from a third part source) that does some of the image processing functions I would like to use on my image data, but the input for the image data for these functions is double**.
Does anyone have any idea how to go about converting this?
What other information can I provide?
The constructor prototype for the class that use double** look like:
Image(double **iPixels, unsigned int iWidth, unsigned int iHeight);
Your uint8_t *bPixels seems to hold image data as 1-dimensional continuous array of height*width lenght. So to access pixel in the x-th row and y-th column you have to write bPixels[x*width+y].
Image() seems to work on 2-dimensional arrays. To access pixel like above you would have to write iPixels[x][y].
So you need to copy your existing 1-dimensional array to a 2-dimensional:
double **mypixels = new double* [height];
for (int x=0; x<height; x++)
{
mypixels[x] = new double [width];
for (int y=0; y<width; y++)
mypixels[x][y] = bPixels[x*width+y]; // attention here, maybe normalization is necessary
// e.g. mypixels[x][y] = bPixels[x*width+y] / 255.0
}
Because your 1-dimensional array has pixel of type uint8_t and the 2-dimensional one pixel of type double, you must allocate new memory. Otherwise, if both would have same pixel type, the more elegant solution (a simple map) would be:
uint8_t **mypixels = new uint8_t* [height];
for (int x=0; x<height; x++)
mypixels[x] = bPixels+x*width;
Attention: beside the problem of eventually necessary normalization, there is also a problem with the indices-compatibility! My examples assume that the 1-dimensional array is stored row-by-row and that the functions working on 2-dimensional index with [x][y] (that means first-row-then-column). The declaration of Image() however, could lead to the conclusion that it needs its arrays to be indexed with [y][x] maybe.
I'm going to take a giant bunch of guesses here in hopes that this will lead you towards getting at the documentation and answering back. If there's no further documentation, well, here's a starting point.
Guess 1) The Image constructor requires a doubly dimensioned array where each component is an R,G,B,Alpha channel in that order. So iPixels[0] is the red data, iPixels[1] is the green data, etc.
Guess 2) Because it's not integer data, the values range from 0 to 1.
Guess 3) All of this must be pre-allocated.
Guess 4) Image data is row-major
Guess 5) Source data is BRGA
So with that in mind, starting with bPixels
double *redData = new double[width*height];
double *greenData = new double[width*height];
double *blueData = new double[width*height];
double *alphaData = new double[width*height];
double **iPixels = new double*[4];
iPixels[0] = redData;
iPixels[1] = greenData;
iPixels[2] = blueData;
iPixels[3] = alphaData;
for(int y = 0;y < height;y++)
{
for(int x = 0;x < width;x++)
{
int alpha = bPixels[(y*width + x)*4 + 3];
int red = bPixels[(y*width +x)*4 + 2];
int green = bPixels[(y*width + x)*4 + 1];
int blue = bPixels[(y*width + x)*4];
redData[y*width + x] = red/255.0;
greenData[y*width + x] = green/255.0;
blueData[y*width + x] = blue/255.0;
alphaData[y*width + x] = alpha/255.0;
}
}
Image newImage(iPixels,width,height);
some of the things that can go wrong.
Source is not BGRA but RGBA, which will make the colors all wrong.
Not row major or destination is not in slices which will make things look all screwed up and/or seg-fault

Texture Array, creating the texture

I'm working on a section of someone else's code and hence have been limited to the amount of modification I can do. Anyway, I'm currently trying to create a texture array and have become stuck with a problem:
What I need to support is n textures being individually loaded and stored as GLubytes in a vector. I then need to take all of the data stored in that vector and store it in a single GLubyte object. Currently my code looks something like this:
vector<GLubyte*> vecPixelData;
GLubyte* puData;
for(int i = 0; i < NumberOfTextures; i++)
{
GLubyte* pixData;
LoadTexture(&pixData);
vecPixelData.push_back(pixData);
}
int puDataSize = nWidth * nHeight * 4 * NumberOfTextures;
puData = new GLubyte[puDataSize];
for(int i = 0; i < NumberOfTextures; i++)
*puData += *vecPixelData[i];
Now I'm sure I'm missing some fundamental points on how to copy memory from vecPixelData to puData, and if not, can anyone give me a 'pointer' as to somewhere to begin on how to check if puData is actually storing the data required. (I've tried using the memory window but the data in puData doesn't seem to get altered.)
EDIT:
The Solution in the end was:
int puDataSize = nWidth * nHeight * 4;
puData = new GLubyte[puDataSize * NumberOfTextures];
for(int i = 0; i < NumberOfTextures.size(); i++)
memcpy(puData + (puDataSize * i), vecPixelData[i], puDataSize);
If I understand your problem correctly you need to use std::copy. Something along the lines of std::copy(*vecPixelData[i], *vecPixelData[i] + imageSize, puData + offstet) (leaving the calculations of imageSize and offset to you) inside your last for loop.