Moving my array to Mat and showing image with open CV - c++

I am having problems using opencv to display an image. As my code is currently working, I have function that loads 78 images of size 710X710 of unsigned shorts into a single array. I have verified this works by writing the data to a file and reading it with imageJ. I am now trying to extract a single image frame from the array and load it into a Mat in order to perform some processing on it. Right now I have tried two ways to do this. The code will compile and run if I do not try to read the output, but if I cout<
My question would be, how do I extract the data from my large, 1-D array of 78images of size 710*710 into single Mat images. Or is there an more efficient way where I can load the images into a 3-D mat of dimensions 710X710X78 and operate on each 710X710 slice as needed?
int main(int argc, char *argv[])
{
Mat OriginalMat, TestImage;
long int VImageSize = 710*710;
int NumberofPlanes = 78;
int FrameNum = 150;
unsigned short int *PlaneStack = new unsigned short int[NumberofPlanes*VImageSize];
unsigned short int *testplane = new unsigned short int[VImageSize];
/////Load PlaneStack/////
Load_Vimage(PlaneStack, Path, NumberofPlanes);
//Here I try to extract a single plane image to the mat testplane, I try it two different ways with the same results
memcpy(testplane, &PlaneStack[710*710*40], VImageSize*sizeof(unsigned short int));
//copy(&PlaneStack[VImageSize*40],&PlaneStack[VImageSize*41], testplane);
// move single plane to a mat file
OriginalMat = Mat(710,710,CV_8U, &testplane) ;
//cout<<OriginalMat;
namedWindow("Original");
imshow("Original", OriginalMat);
}

The problem is you are using the constructor Mat::Mat(int rows, int cols, int type, void* data) with a pointer to 16 bit data (unsigned short int) but you are specifying the type CV_8U (8 bit).
Therefore the first byte of your 16 bit pixel becomes the first pixel in OriginalMat, and the second byte of the first pixel becomes the second pixel in OriginalMat, etc.
You need to create a 16 bit Mat, then convert it to 8 bit if you want to display it, e.g.:
int main(int argc, char *argv[])
{
long int VImageSize = 710*710;
int NumberofPlanes = 78;
int FrameNum = 150;
/////Load PlaneStack/////
unsigned short int *PlaneStack = new unsigned short int[NumberofPlanes*VImageSize];
Load_Vimage(PlaneStack, Path, NumberofPlanes);
// Get a pointer to the plane we want to view
unsigned short int *testplane = &PlaneStack[710*710*40];
// "move" single plane to a mat file
// actually nothing gets moved, OriginalMat will just contain a pointer to your data.
Mat OriginalMat(710,710,CV_16UC1, &testplane) ;
double scale_factor = 1.0 / 256.0;
Mat DisplayMat;
OriginalMat.convertTo(DisplayMat, CV_8UC1, scale_factor);
namedWindow("Original");
imshow("Original", DisplayMat);
}

Related

How to copy cv::Mat & Img to unsigned char* img?opencv

How to copy "Mat& imgSrc" to "unsigned char* imgSrc"?
void BGR2NV21( unsigned char* bgrData, int w, int h, unsigned char* nv21Data)
{.............}
int enhanceRGB( cv::Mat& fieldFaceImgSrc, int iWidth,int iHeight, cv::Mat& faceImgDst)
{
cv::imwrite("enhanceInput.jpg", fieldFaceImgSrc); //it's ok
cv::Mat faceBackupData;
faceBackupData = fieldFaceImgSrc.clone(); //it's ok
cv::imwrite("enhanceput.jpg", faceBackupData); //it's ok
unsigned char*pcfieldFaceDataNV21 = (unsigned char*)faceBackupData .data;
BGR2NV21(pcfieldFaceDataNV21, //it's bad,pcfieldFaceDataNV21 is bad data;
iWidth, iHeight, pcfieldFaceDataNV21);
}
Thanks for your help.
Is there an error message or is the image just "wrong"?
Two obvious things to check, have you passed image width and height the right way around? It's a constant source of pain in image between camera APIs (x,y) and image processing matrix APIs (row,col)
And opencv pads rows of an image to 32bit (4byte boundaries) see Stride on image using Opencv C++
One of the reason why it may failed is about the management of the channels.
OpenCV's Mat object store the data continuously if they are not a submatrix.
This storage follow the raw line ordering that mean:
The matrix :
|1 2 3|
|4 5 6|
|7 8 9|
will be stored a a linear pointer in that order : 1,2,3,4,5,6,7,8,9.
That is also true for the channels i.e. let supose two pixel with the value [255,64,128] and [64,12,34] corresponding the the coordinate row = 0, col =0 and row =0 col = 1 they will stored in memory continuously (the six first values of the data will be 255,64,128,64,12,34)
Now the easiest way to copy the data pointer of Mat object to another data pointer can:
std::memcpy(dst,src,rows*cols*elemsize); or if you pass the Mat object:
if(obj.isContiguous())
std::memcpy(dst,src.ptr(),src.rows*src.step); // if you data are of type unsigned char src.step == src.cols otherwise src.step = src.cols*src.elemSize()
else
for(int r=0;r<src.rows;r++,dst+=src.step)
std::memcpy(dst,src.ptr(r),src.step);
so sorry,it always some questions,code is :
int enhanceRGB( cv::Mat fieldFaceImgSrc, int iWidth,int iHeight, cv::Mat& faceImgDst)
{
cv::imwrite("enhanceInput.jpg", fieldFaceImgSrc); //it's ok
cv::Mat faceBackupData;
faceBackupData = fieldFaceImgSrc.clone();
cv::imwrite("enhanceput.jpg", faceBackupData); //it's ok
unsigned char *testdata = (unsigned char*)malloc(iWidth * iHeight * 3 * sizeof(unsigned char));
memcpy(testdata, faceBackupData.ptr(), iWidth * iHeight * 3);
cv::Mat FaceData(iHeight , iWidth, CV_8UC3, testdata);
cv::imwrite("testput.jpg", FaceData); //it's bad
}

DevIL/OpenIL isn't loading alpha channel

I am having an issue where the .png image that I want to load as a byte array using DevIL is not having an alpha channel.
A complete black image is also appearing as having alpha channel values as 0.
This is my image loading function:
DevILCall(ilGenImages(1, &m_ImageID));
DevILCall(ilBindImage(m_ImageID));
ASSERT("Loading image: " + path);
DevILCall(ilLoadImage(path.c_str()));
GraphicComponents::Image image(
ilGetData(),
ilGetInteger(IL_IMAGE_HEIGHT),
ilGetInteger(IL_IMAGE_WIDTH),
ilGetInteger(IL_IMAGE_BITS_PER_PIXEL)
);
return image;
The Image object I am using is as follows:
struct Image
{
ILubyte * m_Image;
const unsigned int m_Height;
const unsigned int m_Width;
const unsigned int m_BPP;
Image(ILubyte imageData[ ], unsigned int height, unsigned int width, unsigned int bpp);
~Image();
};
And this is how I am printing out the image data for now:
for(unsigned int i = 0; i < image->m_Height*image->m_Width*4; i+=4)
{
LOG("Red:");
LOG((int) image->m_Image[i]);
LOG("Green:");
LOG((int) image->m_Image[i+1]);
LOG("Blue:");
LOG((int) image->m_Image[i+2]);
LOG("Alpha:");
LOG((int) image->m_Image[i+3]);
}
I also tried using the ilTexImage() to format the loaded image to RGBA format but that also doesn't seem to work. The printing loop starts reading garbage values when I change the maximum value of the loop variable to 4 times the number of pixels in the image.
The image is also confirmed to have an alpha channel.
What might be going wrong here?
EDIT: ilGetInteger(IL_IMAGE_BPP) is returning 3, which should mean RGB for now. When I use the ilTexImage() to force 4 channels, then ilGetInteger(IL_IMAGE_BPP) returns 4 but I still see garbage values popping up at the std output
The problem was fixed by a simple ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE) call after loading the image.
I suppose DevIL loads the image in RGB mode with unsigned byte values by default and to use otherwise, you need to convert the loaded image using ilConvertImage().

Convert a cv::Mat to a pangolin::Image?

I have an application that takes in pangolin::Image format rgbd images. I would like to send in a cv::Mat. How can I convert a cv::Mat to a pangolin::Image?
(pangolin: https://github.com/stevenlovegrove/Pangolin)
Image header:
https://github.com/stevenlovegrove/Pangolin/blob/master/include/pangolin/image/image.h
currently the format is:
pangolin::ManagedImage<unsigned short> firstData(640, 480);
pangolin::Image<unsigned short> firstRaw(firstData.w, firstData.h, firstData.pitch, (unsigned short*)firstData.ptr);
where firstRaw is then sent through the application.
If I now have:
cv::Mat frame = cv::imread(filepath,0);
What is the conversion from frame to firstRaw?
I start like this:
int loadDepthFromMat(cv::Mat filepath, pangolin::Image<unsigned short> & depth)
{
int width = filepath.cols;
int height = filepath.rows;
pangolin::ManagedImage<unsigned short> depthRaw(width, height);
pangolin::Image<unsigned short> depthRaw16((unsigned short*)depthRaw.ptr, depthRaw.w, depthRaw.h, depthRaw.w * sizeof(unsigned short));
//copy data
}
Thank you.
So, assuming you have converted your cv::Mat to unsigned short format with the correct pitch (or channels, in OpenCV), you just use memcpy.
(I've renamed your cv::Mat from filepath to mat (why is it called filepath?)):
memcpy((void*)depthRaw16.begin(), (void*)mat.data, mat.total() * mat.elemSize());
Again, be sure your pangolin image has identical dimensions and be sure the cv::Mat is converted to unsigned short.

Transpose a 1D byte-wise array to a 2D array

I am reading a 64x128 grayscale image in an array, one line at a time. Each pixel is 8-bit wide. The read operation is done in a byte addressable manner. Now I want to transpose each line and store it in a 2D array. This architecture is designed towards memory optimization on a specific device. Once the 2D array is filled, I need to read it byte-by-byte such that each of the 8 bits lie in a different row of the array. Can anyone give a sample code?
Thanks!
sample
#include <stdio.h>
#include <string.h>
int main(void){
unsigned char a[64*128];
int i,r,c;
for(i=0;i<64*128;i++){
a[i]=i;
}
//not fill
unsigned char (*b)[64][128] = (unsigned char (*)[64][128])a;
for(r=0;r<64;++r){
for(c=0;c<128;++c){
printf("%i,", (*b)[r][c]);
}
printf("\n");
}
//FILL
unsigned char b2[64][128];
memcpy(b2, a, sizeof(b2));
printf("\nFill ver\n");
for(r=0;r<2;++r){
for(c=0;c<16;++c){
printf("%i,", b2[r][c]);
}
printf("\n");
}
return 0;
}
just construct a Mat from your array:
uchar array[w*h];
// read bytes:
Mat m( h, w, CV_8U, array );
or start with a Mat in the 1st place, and read into it's data member:
Mat m(h, w, CV_8U);
// read into m.data
if you have a 1d Mat, you can just reshape it:
Mat m( 1, w*h, CV_8U );
// make it 2d HxW now:
m = m.reshape(1, w);

OpenCV Mat object - get data length

In OpenCV, I'm able to capture frames using VideoCapture in C++, however, when I try to get the data from a frame and calculate length, it just returns me 0.
Below is my sample code:
VideoCapture cap(0);
for(;;) {
Mat frame;
cap >> frame;
int length = strlen((char*) frame.data); // returns 0
}
As I mentioned above that if I save the frame in a PNG file, I can actually see the image so I'm not able to understand why the data length is coming out to be zero.
Any clue?
You can also do:
Mat mat;
int len = mat.total() * mat.elemSize(); // or mat.elemSize1()
The strlen method only works on strings, which are arrays of chars terminated by a special character:
http://www.cplusplus.com/reference/cstring/strlen/
You have cast a Mat type as a char*, so it is not a string.
Building on the solution here, try:
Mat mat;
int rows = mat.rows;
int cols = mat.cols;
int num_el = rows*cols;
int len = num_el*mat.elemSize1();
to get the size of one channel in bytes. Also, use elemSize() if you want all the channels (i.e. you'll get 3 times the value of elemSize1() if the Mat is a 3 channel image).
Take a look here for discussion of the various types Mat can contain:
http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-type