I have a strange problem in transform a stack of bmp images to raw file (unsigned char array) .This is the code :
for(int i=365;i<=385;i++)
{
sprintf(secondname,"C:\\tr\\tr_");
sprintf(secondtemp,"_%04d.bmp",i);
strcat(secondname,secondtemp);
cvSaveImage( secondname,out);
cvReleaseImage( &out );
IplImage* img2 = cvLoadImage( secondname,0);
memcpy(&im[xsize*ysize*(i-365)],img2->imageData,xsize*ysize);
}
outfile=fopen("C:\\Histo_Registration\\a.raw","wb");
fwrite((unsigned char*)im,1,(xsize)*(ysize)*(zsize),outfile);
fclose(outfile);
The problem is that when the images that i load is for example 512x512 the result raw is ok .When the images is 426x425 the result raw is strange is not for sure the correct one.Any idea?
Your code doesn't work with bitmap line alignment. See IplImage::widthStep member. You cannot copy the whole image in one memcpy call, if widthStep is not equal to (pixel size in bytes * line width in pixels).
Windows bitmaps are 32-bit aligned, this is why 512x512 image is OK, and 426x425 is wrong. For example, if image width = 11, and every pixel is 1 byte length, actual line width (widthStep) will be 12 (4 bytes alignment).
The length of each row in a BMP is a multiple of 4, if necessary the remaining bytes will be filled with 0. You need to take that into account.
See the Wikipedia article about the BMP file format for details.
Related
I have a Mipi camera that captures frames and stores them into the struct buffer that you can see below. Once the frame is stored I want to convert it into a cv::Mat, the thing is that the Mat ends up looking like the first pic.
The var buf.index is just part of the V4L2 API, useful to understand which buffer I'm using.
//The structure where the data is stored
struct buffer{
void *start;
size_t length;
};
struct buffer *buffers;
//buffer->mat
cv::Mat im = cv::Mat(cv::Size(width, height), CV_8UC3, ((uint8_t*)buffers[buf.index].start));
At first I thought that the data might be corrupted but storing the image with lodepng results in a nice image without any distortion.
unsigned char* out_buf = (unsigned char*)malloc( width * height * 3);
for(int pix = 0; pix < width*height; ++pix) {
memcpy(out_buf + pix*3, ((uint8_t*)buffers[buf.index].start)+4*pix+1, 3);
}
lodepng_encode24_file(filename, out_buf, width, height);
I bet it's something really silly.
the picture you post has oddly colored pixels and the patterns look like there's more information than simply 24 bits per pixel.
after inspecting the data, it appears that V4L gives you four bytes per pixel, and the first byte is always 0xFF (let's call that X). further, the channel order seems to be XRGB.
create a cv::Mat using 8UC4 to contain the data.
to use the picture in OpenCV, you need BGR order. cv::split the received data into its four color planes which are X,R,G,B. use cv::merge to reassemble the B,G,R planes into a picture that OpenCV can handle, or reassemble into R,G,B to create a Mat for other purposes (that other library you seem to use).
I have problem. When I'm loading mat from byte array there is a big problem; extra bytes cause mat to load wrong. If I send byte array ( width: 4-8-12-16-20 etc) It's not a problem because width and stride is equal. But If I byte array with extra stride bytes Image is corrupted. Is there a way to make it right ?
Function that I'm using:
Mat bytesToMat(byte * bytes,int height,int width)
{
Mat image = Mat(height,width,CV_8UC3,bytes).clone(); // make a copy
return image;
}
Example)
23 width image loaded as:
24 width image loaded (Correctly):
The link format was messed up in the comment, so I'll write an answer.
See the constructor step and steps parameters in the documentation. It lets you tell OpenCV how many bytes are in each row (including padding).
You'll also have to check if the byte array you're using as input has any added padding.
I have a byte array of 80*60 bytes that represent a picture with resolution 80x60 (1 byte per pixel). How do I convert it into picture that could be then used in OpenCV?
I work in Linux with C++
This can be done with the cv::Mat constructor, and then reshape it using the number of rows.
// data is your byte* and sizeOfData is its size in bytes (80x60 in your case I believe)
cv::Mat imageWithData = cv::Mat(sizeOfData, 1, CV_8U, data).clone();
Mat reshapedImage = imageWithData.reshape(0, numberOfRows);
I am trying to move image data from Magick++ to tesseract.
I have the PNG data and some info about it.
And the signature for the tesseract method is:
void SetImage(const unsigned char* imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line);
The first three arguments I can supply just fine. But bytes_per_pixel and bytes_per_line I'm not so sure about. The image itself has 11564 pixels but the length of the data is only 356 bytes... It's mostly a white image with some text. 11564/356 = 32.48 which obviously is not the correct bytes per pixel. How can I get the right bytes / pixel information? It's ok to just get that for one image on my desktop or something and set it as a constant, all the images I'm processing will have the same format.
Then as far as bytes per line, would that just be image width in pixels * bytes per pixel?
bytes_per_pixel can be obtained from PNG data. They are usually 8, 24 or 32.
bytes_per_line too, but you can compute it doing: bytes_per_pixel * width / 8
I have a raw file which contains a header of 5 bytes containing the number of rows and columns in first two bits each . The 5th byte contains the number of bits for each pixel in the image which is 8 bits in all cases. The image data follows after that.
Since I am new to openCV, i want to ask how to view this RAW image file as an greyscale image using C++?
I know how to read binary data in C++ and have stored the image as a 2-D unsigned char array (since each pixel is 8 bit).
Can anyone please tell me how to view this data as image using openCV ?
I am using the below code , but getting a completely weird image :
void openRaw() {
cv::Mat img(numRows, numCols,CV_8U,&(image[0][0]));
//img.t();
cv::imshow("img",img);
cv::waitKey();
}
Any help will be greatly appreciated.
Thanks,
Rohit
You have to convert it to an IplImage.
If you want to see it as a pure grey-scale image, its actually rather easy.
Example code I use in one application:
CvSize mSize;
mSize.height = 960;
mSize.width = 1280;
IplImage* image1 = cvCreateImage(mSize, 8, 1);
memcpy( image1->imageData, rawDataPointer, sizeOfImage);
cvNamedWindow( "corners1", 1 );
cvShowImage( "corners1", image1 );
At that point you have a valid IplImage, which you can then display. (last 2 lines of code display it)
If the image is bayer-tiled, you will have to convert to RGB.
c++ notation:
cv::Mat img(rows,cols,CV_8U,ptrToDat);
cv::imwhow("img",img);
cv::waitkey();
*data should be saved columwise, otherewise use:
cv::Mat img(cols,rows,CV_8U,ptrToDat);
img=img.t();
cv::imwhow("img",img);
cv::waitkey();