opengl pixel data to jpeg - opengl

Any C++ examples available to convert raw pixel data obtained from glReadPixels to JPEG format and back?

You can use ImageMagick library to convert raw data to the jpeg image data, and opposite. Using the same library, you can convert jpeg image data into raw (RGB) data.

Use an external library for that.
I'll recommend DevIL, your number one Swiss Army Knife for handling image files. You'll just need to
create an RGB image in memory via DevIL,
call glReadPixels to fill your DevIL image with pixels read from the GL framebuffer,
call ilSaveImage("foo.jpg") to save the file. You can also use bmp, png and a handful more - the format will get autodetected from the file name.
Simple.

I'm not sure if OpenGL has support for dealing with JPEG images. It's not what the library is really for.
Once you've got access to the pixel data, you should be able to use easily OpenCV to write the image to JPEG (or any other format), though. Here's some pseudo-code to get you going.
/*
* On Linux, compile with:
*
* g++ -Wall -ggdb -I. -I/usr/include/opencv -L /usr/lib -lm -lcv -lhighgui -lcvaux filename.cpp -o filename.out
*/
#include <cv.h>
#include <highgui.h>
/*
* Your image dimensions.
*/
int width;
int height;
CvSize size = cvSize(width, height);
/*
* Create 3-channel image, unsigned 8-bit per channel.
*/
IplImage *image = cvCreateImage(size, IPL_DEPTH_8U, 3);
for (int i = 0; i < width; ++i)
for (int j = 0; j < height; ++j)
{
unsigned int r;
unsigned int g;
unsigned int b;
/*
* Call glReadPixels, grab your RGB data.
* Keep in mind that OpenCV stores things in BGR order.
*/
CvScalar bgr = cvScalar(b, g, r);
cvSet2D(image, i, j, bgr);
}
cvSaveImage("filename.jpg", image);
cvReleaseImage(&image);
Other libraries for dealing with JPEG also exist, if you look around.

Related

uint8_t buffer to cv::Mat conversion results in distorted image

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

What is the preferred approach to display a Magick++ Image in a GTK+3 application?

I'm working on an C++ image viewer for Linux which is created using GTK+3 (gtkmm) for the GUI and Magick++ for image handling. My goal is to support as many image file formats as possible, including animated GIFs.
What is the best approach to take a Magick++ Image and draw it in a GTK+3 widget, such that it would work for (just about) any image file format?
What is the best approach to take a Magick++ Image and draw it in a GTK+3 widget, such that it would work for (just about) any image file format?
As long as ImageMagick has the format delegate, you should be able to draw the GtkWidget image.
image = Gtk::manage(new Gtk::Image());
// Load image into ImageMagick
Magick::Image img("wizard:");
/// Calculate how much memory to allocate
size_t to_allocate = img.columns() * img.rows() * 3;
// Create a buffer
guint8 * buffer = new guint8[to_allocate];
// Write pixel data to buffer.
img.write(0, 0, img.columns(), img.rows(), "RGB", Magick::CharPixel, buffer);
// Build a Pixbuf from pixel data in memory.
Glib::RefPtr<Gdk::Pixbuf> pBuff = Gdk::Pixbuf::create_from_data(buffer, Gdk::COLORSPACE_RGB, false, 8, img.columns(), img.rows(), img.columns()*3 );
// Set GtkImage from Pixbuf
image->set(pBuff);
Original Answer mixing C/C++ methods.
Use the following Magick++ method signature to export the pixel data into memory.
Magick::Image.write(const ssize_t x_,
const ssize_t y_,
const size_t columns_,
const size_t rows_,
const std::string &map_, //<= Usually "RGB"
const StorageType type_, //<= Usually CharType
void *pixels_) //<= Be sure to allocate _all_ the memory required (size of storage * number of channels * columns * rows)
Create a GdkPixBuf from the pixels exported above with the following GTK method.
GdkPixbuf *
gdk_pixbuf_new_from_bytes (GBytes *data, //<= Same as pixels_.
GdkColorspace colorspace, //<= Match colorspace channels from map_.
gboolean has_alpha, //<= Usually no.
int bits_per_sample, //<= Match StorageType bits
int width, //<= Same as columns_.
int height, //<= Same as rows_.
int rowstride); //<= size of data-type * number of channel * width.
Finally, build a GtkImage from the PixBuf with the following method.
GtkWidget * gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);
I suppose #emcconville is right for the ImageMagick part, as I have no clue about it.
For the GTKmm part, though, you'll want to stick to the C++ API, so use Gdk::Pixbuf::create_from_data to read the image from ImageMagick.
Also, as you're creating an image viewer, you will want to change the image shown by a Gtk::Image. So at startup just use an empty Gtk::Image created with Gtk::Image::Image (or Glade and Gtk::Builder), and later change the image displayed in it with Gtk::Image::set, passing it your pixbuf.

DevIL library: save gray scale image in three matrices instead one

I need to make a program that convert a RGB image to a GRAYSCALE image and save it in PGM format. I use DevIL library, but when I save the image, I obtain always a 3D image (3 matrix), in grayscale but, if I load it in MATLAB, I have 3 matrices instead of just one. How can I obtain just one matrix in my output file using DevIL?
int main()
{
ilInit();
ilEnable(IL_ORIGIN_SET);
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
ilEnable(IL_FILE_OVERWRITE);
ILuint ImageName; // The image name to return.
ilGenImages(1, &ImageName);
ilBindImage(ImageName);
if(!ilLoadImage("/home/andrea/Scrivania/tests/siftDemoV4/et000.jpg"))
{ printf("err");
exit;
}
else
printf("caricata\n");
ILuint width,height;
width = ilGetInteger(IL_IMAGE_WIDTH);
height = ilGetInteger(IL_IMAGE_HEIGHT);
double v[3]={0.2989360212937755001405548682669177651405334472656250000,0.5870430744511212495240215503145009279251098632812500000,0.1140209042551033058465748126764083281159400939941406250};
printf("%.55f %.55f %.55f",v[0],v[1],v[2]);
ILubyte *imgValue=ilGetData();
int i=0;
ILubyte imgNuova[width*height];
while( i < width*height)
{
imgNuova[i]=(char)round( ( (double)imgValue[3*i]*v[0])+ ( (double)imgValue[3*i+1]*v[1])+((double)imgValue[3*i+2]*v[2]));
i++;
}
ILuint ImageName2;
ilGenImages(2, &ImageName2);
ilBindImage(ImageName2);
ilTexImage(width, height, 1, 1, IL_LUMINANCE,
IL_UNSIGNED_BYTE, imgNuova);
iluFlipImage();
ilSave(IL_PNM,"/home/andrea/Scrivania/tests/siftDemoV4/et000new.pgm");
return 0;
}
Unfortunately, due to a bug in the PNM export, DevIL can and will only write PPM (Portable Pixmaps, 3 channel RGB) files regardless of the file extension. The only solution to this is to use a different file format, that supports single channel grayscale images, like PNG.
Matlab should be able to use that just as well. If you absolutely need or want files in the PGM format, you will have to use a converter like png2pnm.

Decode PNG image with Magick++

I need to put decoded RGBA data (from 32-bit PNG) in cl::Image2D, then (after some processing) write it back to Magick++ image with enqueueReadImage().
However, at the moment I do not see any way to access RGBA data directly in Magick++ image object. Is this possible? If not, what's the best way to get data in RGBA format from Magick++ object?
You can use the Magick::Image::write function
Magick::Image im;
// read image ....
// only for RGBA !!!
size_t im_size = im.columns() * im.rows() * 4;
uint8_t * pixels = new uint8_t[im_size];
im.write(0, 0, im.columns(), im.rows(), "RGBA", ::Magick::CharPixel, pixels);

WebP encoding - Segmentation Fault

So I'm trying to use the webp API to encode images. Right now I'm going to be using openCV to open and manipulate the images, then I want to save them off as webp. Here's the source I'm using:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cv.h>
#include <highgui.h>
#include <webp/encode.h>
int main(int argc, char *argv[])
{
IplImage* img = 0;
int height,width,step,channels;
uchar *data;
int i,j,k;
if (argc<2) {
printf("Usage:main <image-file-name>\n\7");
exit(0);
}
// load an image
img=cvLoadImage(argv[1]);
if(!img){
printf("could not load image file: %s\n",argv[1]);
exit(0);
}
// get the image data
height = img->height;
width = img->width;
step = img->widthStep;
channels = img->nChannels;
data = (uchar *)img->imageData;
printf("processing a %dx%d image with %d channels \n", width, height, channels);
// create a window
cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
cvMoveWindow("mainWin",100,100);
// invert the image
for (i=0;i<height;i++) {
for (j=0;j<width;j++) {
for (k=0;k<channels;k++) {
data[i*step+j*channels+k] = 255-data[i*step+j*channels+k];
}
}
}
// show the image
cvShowImage("mainWin", img);
// wait for a key
cvWaitKey(0);
// release the image
cvReleaseImage(&img);
float qualityFactor = .9;
uint8_t** output;
FILE *opFile;
size_t datasize;
printf("encoding image\n");
datasize = WebPEncodeRGB((uint8_t*)data,width,height,step,qualityFactor,output);
printf("writing file out\n");
opFile=fopen("output.webp","w");
fwrite(output,1,(int)datasize,opFile);
}
When I execute this, I get this:
nato#ubuntu:~/webp/webp_test$ ./helloWorld ~/Pictures/mars_sunrise.jpg
processing a 2486x1914 image with 3 channels
encoding image
Segmentation fault
It displays the image just fine, but segfaults on the encoding. My initial guess was that it's because I'm releasing the img before I try to write out the data, but it doesn't seem to matter whether I release it before or after I try the encoding. Is there something else I'm missing that might cause this problem? Do I have to make a copy of the image data or something?
The WebP api docs are... sparse. Here's what the README says about WebPEncodeRGB:
The main encoding functions are available in the header src/webp/encode.h
The ready-to-use ones are:
size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height,
int stride, float quality_factor, uint8_t** output);
The docs specifically do not say what the 'stride' is, but I'm assuming that it's the same as the 'step' from opencv. Is that reasonable?
Thanks in advance!
First, don't release the image if you use it later. Second, your output argument is pointing to non-initialized address. This is how to use initialized memory for the output address:
uint8_t* output;
datasize = WebPEncodeRGB((uint8_t*)data, width, height, step, qualityFactor, &output);
You release the image with cvReleaseImage before you try to use the pointer to the image data for the encoding. Probably that release function frees the image buffer and your data pointer now doesn't point to valid memory anymore.
This might be the reason for your segfault.
so it looks like the problem was here:
// load an image
img=cvLoadImage(argv[1]);
The function cvLoadImage takes an extra parameter
cvLoadImage(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR)
and when I changed to
img=cvLoadImage(argv[1],1);
the segfault went away.