I have a image buffer stored as a linear array[640*480] of unsigned integer type, and I want to save this array as a bitmap image which can be viewed. I have captured an image from my camera and retrieved its image buffer from a GigE cable using in c++ code. So please tell me how to write an integer array of RGB values to Bitmap in C++ along with the header files required. I have stream buffer as
if (Result.Succeeded())
{
// Grabbing was successful, process image
cout << "Image #" << n << " acquired!" << endl;
cout << "Size: " << Result.GetSizeX() << " x "
<< Result.GetSizeY() << endl;
// Get the pointer to the image buffer
const unsigned int *pImageBuffer = (int *) Result.Buffer();
the pImagebuffer is the image Buffer and please ignore the Functions as they belong to a custom compiler. I just want to convert the RGB values to bitmap image and then save it
also the pImageBuffer is giving me the R=G=B as photo is mono chrome.
Save the pixel data together with a simple BMP-file header, appropriately initialized. See the format description here.
Related
I want to convert an SVG graphic to an OpenCV Mat object. Therefore the SVG graphic is loaded into a QSvgRenderer object and afterwards converted into a QImage object from which I use its raw data to create my final Mat object:
void scaleSvg(const cv::Mat &in, QSvgRenderer &svg, cv::Mat &out)
{
if (!svg.isValid())
{
return;
}
QImage image(in.cols, in.rows, QImage::Format_ARGB32);
// Get QPainter that paints to the image
QPainter painter(&image);
svg.render(&painter);
std::cout << "Image byte count: " << image.byteCount() << std::endl;
std::cout << "Image bits: " << (int*)image.constBits() << std::endl;
std::cout << "Image depth: " << image.depth() << std::endl;
uchar *data = new uchar[image.byteCount()];
memcpy(data, image.constBits(), image.byteCount());
out = cv::Mat(image.height(), image.width(), CV_8UC4, data, CV_AUTOSTEP);
std::cout << "New byte count: " << out.size() << std::endl;
std::cout << "New depth: " << out.depth() << std::endl;
std::cout << "First bit: " << out.data[0] << std::endl;
}
Unfortunately, I get a "memory access violation" error when writing my resulting object into a file:
std::cout << (int*)out.data << std::endl; // pointer can still be accessed without errors
cv::imwrite("scaled.png", out); // memory access error
The file which is being written gets to to size of 33 Bytes not more (header data only??).
On the Internet there is some explanation of pointer ownership in cv::Mat and I thought it would be released after the last reference to it is release which should not be the case since "out" is a reference. Btw. another way to convert an SVG into a cv::Mat is always welcome. As OpenCV seem to do not support SVGs this looked like a simple way to get it done.
As constBits does indeed not work and it is not always safe to assume that the number of bytes per line will be the same (it causes a segfault for me). I found the following suggestion in StereoMatching's anwser:
cv::Mat(img.height(), img.width(), CV_8UC4, img.bits(), img.bytesPerLine()).clone()
Baradé's concern about using bits is valid, but because you clone the result the Mat will copy the data from bits, so it will not be a issue.
usually, cv::Mat is refcounted, but this case is special. if you use an external / borrowed data pointer, you'll have to clone() the mat, to make sure it owns its own copy of the pixels, else, as soon as you leave the scope of 'scaleSvg()', the Mat 'out' holds a 'dangling pointer'.
you tried to 'new' the data to be copied, unfortunately, that does not solve it (you only added another problem there).
you also would have to delete[] the uchar *data pixels on your own, too, and you don't, so your code currently combines the worst of all worlds.
instead, try :
out = cv::Mat(image.height(), image.width(), CV_8UC4, image.constBits(), CV_AUTOSTEP).clone();
im trying to access to pixel value of depth map, using kinect, openni and opencv. im using this code
Mat depth;
VideoCapture capture1(CV_CAP_OPENNI);
capture1.grab();
capture1.retrieve(depth,CV_CAP_OPENNI_DEPTH_MAP);
imshow("depth",depth);
waitKey(0);
cout << depth.at<unsigned>(20,20);
system("PAUSE");
the program show me the depth map but when i tried to acccess to the value, produce an error. but if y put:
cout << depth;
then show me all the values.
Since you didn't specified the error, I'll give it a shot: the problem seems to be that you are trying to access elements from another Mat: the one you create is named depth, however the one referenced in the cout call is named depthshow.
According to the documentation for CAP_OPENNI_DEPTH_MAP, your Mat should have 16 bits unsigned integer data per pixel, rather than the 32-bits unsigned int you're trying to use. Therefore, use the following instead:
// uint16_t available in C++11
cout << depth.at<uint16_t>(20,20) << " millimetres";
or
// not 100% sure that all compilers produce 16 bits fields
cout << depth.at<unsigned short int>(20,20) << " millimetres";
CompVision once again, I'm working with jpeg images in my application. Just because I'm a bit familiar with MFC and ATL, I used CImage to access pixel values.
For my needs I calculate brightness matrix for the image during initialization. Function goes like this (Image is the name of my own class, unimportant, bright is float[][]):
void Image::fillBrightnessMatrix(){
COLORREF val;
for(int i=0;i<width;i++){
for(int j=0; j<height;j++){
val=src.GetPixel(i,j);
bright[i][j]=rgb_to_L(val);
}
}
}
Where src is an instance of CImage class, rgb_to_L - some function that calculates brightness of the color.
Examining the performance of my app, I discovered that GetPixel is the most expensive operation, and it significantly (really, ~700 times slower than any other operation) slows down the whole initializing of image. The question is, which library can you suggest for fast access to single pixel values? I don't need any other operations but loading jpeg image and accessing single pixels. Performance is important, because my application works with set of ~3000 images and I can't wait for hours to get results.
Use CBitmap::GetBits() to get a raw pointer to the pixel data. You can now directly party on the pixels without going through the expensive GetPixel() method. There are a number of things you need to be careful with when you do this:
You have to use CBitmap::GetPitch() to calculate the offset to the start of a line. The pitch is not the same as the width.
Lines in the bitmap are stored upside-down
You have to deal with the pixel format yourself. A 24bpp image stores 3 bytes per pixel. An indexed format like 8bpp requires looking up the color in the color table. 32bpp is the easy one, 4 bytes per pixel and the pitch is always the same as the width.
I always recommend OpenCV.
This is a humble code snippet to get you started:
IplImage* pRGBImg = cvLoadImage("c:\\test.jpg", CV_LOAD_IMAGE_UNCHANGED);
if (!pRGBImg)
{
std::cout << "!!! cvLoadImage failed !!!" << std::endl;
exit(1);
}
int width = pRGBImg->width;
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels;
for (int i=0; i < width*height*bpp; i+=bpp)
{
if (!(i % (width*bpp))) // print empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<
" G:" << (int) pRGBImg->imageData[i+1] <<
" B:" << (int) pRGBImg->imageData[i+2] << " ";
}
You should probably extract the jpeg to raw data, then access the raw data instead of GetPixel.
This is part of my program:
// let's get jpg image from socket
int iRcvdBytes=recvfrom(iSockFd, buff, bufferSize, 0,
(struct sockaddr*)&cliAddr, (socklen_t*)&cliAddrLen);
// buff now contains 30KB jpg image
// let's load the jpg image to IplImage
IplImage* fIplImageHeader;
fIplImageHeader = cvCreateImageHeader(cvSize(640, 480), 8, 1);
fIplImageHeader->imageData = (char *)buff;
// now let's check the size difference
cout << "Received " << iRcvdBytes << " bytes from the client" << endl;
cout << fIplImageHeader->imageSize << endl;
And the output is:
Received 31860 bytes from the client
307200
Now why is that? Is cvCreateImageHeader() converting the jpg image to RGB or something like that internally? I want it to stay JPG and show it with cvShowImage().
Please, any help would be welcome.
You are comparing the lenght of the compressed jpeg image data to the uncompressed pixel data.
In particular, given:
fIplImageHeader = cvCreateImageHeader(cvSize(width, height), depth, channels)
It will always be the case that fIplImageHeader->imageSize == width * height * (depth/8) * channels
Assigning the bytes recieved by the recvfrom() call to the imageData area doesn't work in the first place.
Jpeg does not represent an exact representation of an image. It's a "lossy" format (i.e. you lose some detail in exchange for a smaller size image). I'd bet you haven't specified the 'quality' of the image you want so it's using a default high quality. Look for a quality setting and set it for a lower value. You'll need to balance quality of image versus file size to suit your application.
I have a function that I would like to apply to each pixel in a YUN image (call it src). I would like the output to be saved to a separate image, call it (dst).
I know I can achieve this through pointer arithmetic and accessing the underlying matrix of the image. I was wondering if there was a easier way, say a predefined "map" function that allows me to map a function to all the pixels?
Thanks,
Since I don't know what a YUN image is, I'll assume you know how to convert RGB to that format.
I'm not aware of an easy way to do the map function you mentioned. Anyway, OpenCV has a few predefined functions to do image conversion, including
cvCvtColor(color_frame, gray_frame, CV_BGR2GRAY);
which you might want to take a closer look.
If you would like to do your own, you would need to access each pixel of the image individually, and this code shows you how to do it (the code below skips all kinds of error and return checks for the sake of simplicity):
// Loading src image
IplImage* src_img = cvLoadImage("input.png", CV_LOAD_IMAGE_UNCHANGED);
int width = src_img->width;
int height = src_img->height;
int bpp = src_img->nChannels;
// Temporary buffer to save the modified image
char* buff = new char[width * height * bpp];
// Loop to iterate over each pixel of the original img
for (int i=0; i < width*height*bpp; i+=bpp)
{
/* Perform pixel operation inside this loop */
if (!(i % (width*bpp))) // printing empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) src_img->imageData[i] <<
" G:" << (int) src_img->imageData[i+1] <<
" B:" << (int) src_img->imageData[i+2] << " ";
/* Let's say you wanted to do a lazy grayscale conversion */
char gray = (src_img->imageData[i] + src_img->imageData[i+1] + src_img->imageData[i+2]) / 3;
buff[i] = gray;
buff[i+1] = gray;
buff[i+2] = gray;
}
IplImage* dst_img = cvCreateImage(cvSize(width, height), src_img->depth, bpp);
dst_img->imageData = buff;
if (!cvSaveImage("output.png", dst_img))
{
std::cout << "ERROR: Failed cvSaveImage" << std::endl;
}
Basically, the code loads a RGB image from the hard disk and performs a grayscale conversion on each pixel of the image, saving it to a temporary buffer. Later, it will create another IplImage with the grayscale data and then it will save it to a file on the disk.