convert an rgb image into a matrix using C++ and Cimg library - c++

I have this project in blind source seperation where I need to represent a RGB image in a matrix using Cimg. but I can't actually understand how to use Cimg.. I've looked through the documentation in
But there are TOO many functions and I wasn't able to know which one to use! really too many of them. I have never used Cimg, so if anyone could explain to me what should my procedure be please do!
I am programming with C++ and using eclipse.
Thanks!

First define your image :
CImg<float> img(320,200,1,3); // Define a 320x200 color image (3 channels).
Then fill it with your data :
cimg_forXYC(img,x,y,c) { // Do 3 nested loops
img(x,y,c) = pixel_value_at(x,y,c);
}
Then you can do everything you want with it.
img.display("Display my image");
when c==0, you will fill the red channel of your image, when c==1, the green one and when c==2 the blue one. Nothing really hard.
I have experimented a lof of image processing libraries, and CImg is probably one of the easiest to use. Look at the provided example files (folder CImg/examples/) to see how the whole thing is working (particularly CImg/examples/tutorial.cpp).

Getting started with any 3rd party library, I find it useful to start with a tutorial, like this one: CImg Tutorial
Especially if you are new to C++/programming in general.
Don't get frustrated with the wealth of the interface or magnitude of code. Stick to what you are looking for and let Google be your friend.
To get you started, **get acquainted with the CImg class. Then advance as your need dictates...

If you're not forced with CImg, I suggest you to use DevIL, an example of a working code looks like:
ilLoad();
ILuint image = 0;
ilGenImages(1,&image);
if(!image)
{
// Error
}
ilBindImage(image);
if(!ilLoadImage("yourimage.png"))
{
// Error
}
// 4-bytes per pixel for RGBA
ILuint width = ilGetInteger(IL_IMAGE_WIDTH);
ILuint height = ilGetInteger(IL_IMAGE_HEIGHT);
unsigned char* data=width*height*4;
ilCopyPixels(0,0,0,width,height,1,IL_RGBA,IL_UNSIGNED_BYTE,data);
ilDeleteImages(1,&image);
image = 0;
// now you can use 'data' as a pointer to all your required data.
// You can access from data[0] up to data[ (width*height*4) - 1].
// First pixel's red value: data[0]
// Second pixel's green value: data[1 + (4 * 1)]
// Third pixel's alpha value: data[3 + (4 * 2)]
// Once you're done...
delete[] data;
data = 0;

Related

How to use CImg functions with pixel data?

I am using Visual Studio and looking to find a useful image processing library that will take care of basic image processing functions such as rotation so that I don't have to keep coding them manually. I came across CImg and it supports this, as well as many other useful functions, along with interpolation.
However, all the examples I've seen show CImg being used by loading and using full images. I want to work with pixel data. So my loops are the typical:
for (x=0;x<width; x++)
for (y=0;y<height; y++)
I want to perform bilinear or bicubic rotation in this instance and I see CImg supports this. It provides a rotate() and get_rotate function, among others.
I can't find any examples online that show how to use this with pixel data. Ideally, I could simply pass it the pixel color, x, y, and interpolation method, and have it return the result.
Could anyone provide any helpful suggestions? If CImg is not the right library for this type of this, could anyone recommend a simple, light-weight, easy-to-use one?
Thank you!
You can copy pixel data to CImg class using iterators, and copy it back when you are done.
std::vector<uint8_t> pixels_src, pixels_dst;
size_t width, height, n_colors;
// Copy from pixel data
cimg_library::CImg<uint8_t> image(width, height, 1, n_colors);
std::copy(pixels_src.begin(), pixels_src.end(), image.begin());
// Do image processing
// Copy to pixel data
pixels_dst.resize(width * height * n_colors);
std::copy(image.begin(), image.end(), pixels_dst.begin());

Train skin pixels using Opencv CvNormalBayesClassifier

I'm very new to OpenCV. I am trying to use the CvNormalBayesClassifier to train my program to learn skin pixel colours.
Currently I have got around 20 human pictures (face/other body parts) under different light conditions and backgrounds. I have also got 20 corresponding responses in which the skin parts are marked red and everything else marked green.
I have problem understanding how to use the function
bool CvNormalBayesClassifier::train(const CvMat* _train_data, const CvMat* _response, const Cv*Mat _var_idx = 0, const CvMat* _sample_idx=0,, bool update=false);
How should I use the current two picture libraries I have got to prepare the values that can be passed in as _train_data and _responses?
Many thanks.
You need to put in train_data the pixel values from your training image, and in responses an index corresponding to the class of this pixel (e.g. 1 for class skin, 0 for class non-skin). var_idx and sample_idx can be left as is, they are used to mask out some of the descriptors or samples in your training set. Set update to true/false depending on wether you get all the descriptors (all the pixels of all your training images) at once in case you can let it to false, or you process your training images incrementally (which might be better for memory issues), in which case you need to update your model.
Let me clarify you with the code (not checked, and using the C++ interface to OpenCV which I strongly recommand instead of the old C)
int main(int argc, char **argv)
{
CvNormalBaseClassifier classifier;
for (int i = 0; i < argc; ++i) {
cv::Mat image = // read in your training image, say cv::imread(argv[i]);
// read your mask image
cv::Mat mask = ...
cv::Mat response = mask == CV_RGB(255,0,0); // little trick: you said red pixels in your mask correspond to skin, so pixels in responses are set to 1 if corresponding pixel in mask is red, 0 otherwise.
cv::Mat responseInt;
response.convertTo(responsesInt, CV_32S); // train expects a matrix of integers
image = image.reshape(0, image.rows*image.cols); // little trick number 2 convert your width x height, N channel image into a witdth*height row matrix by N columns, as each pixel should be considere as a training sample.
responsesInt = responsesInt.reshape(0, image.rows*image.cols); // the same, image and responses have the same number of rows (w*h).
classifier.train(image, responsesInt, 0, 0, true);
}
I did a google search on this class but didn't find much information, and actually even the official opencv document does not provide direct explanation on the parameters. But I did notice one thing in opencv document
The method trains the Normal Bayes classifier. It follows the
conventions of the generic CvStatModel::train() approach with the
following limitations:
which direct me to CvStatModel class and from there I found something useful. And probably you can also take a look on the book from page 471 which gives you more details of this class. The book is free from google Books.

Creating a Grayscale image in Visual C++ from a float array

I have an array of grayscale pixel values (floats as a fraction of 1) that I need to display, and then possibly save. The values just came from computations, so I have no libraries currently installed or anything. I've been trying to figure out the CImage libraries, but can't make much sense of what I need to do to visualize this data. Any help would be appreciated!
Thank you.
One possible approach which I've used with some success is to take D3DX's texture functions to create a Direct3D texture and fill it. There is some overhead in starting up D3D, but it provides you with multi-thread-able texture creation and built-in-ish viewing, as well as saving to files without much more fuss.
If you're not interested in using D3D(X), some of the specifics here won't be useful, but the generator should help figure out how to output data for any other library.
For example, assuming an existing D3D9 device pDevice and a noise generator (or other texture data source) pGen:
IDirect3DTexture9 * pTexture = nullptr;
D3DXCreateTexture(pDevice, 255, 255, 0, 0, D3DFMT_R8G8B8, D3DPOOL_DEFAULT, &pTexture);
D3DXFillTexture(pTexture, &texFill, pGen);
D3DXSaveTexture("texture.png", D3DXIFF_PNG, pTexture, NULL);
The generator function:
VOID WINAPI texFill(
D3DXVECTOR4* pOut,
CONST D3DXVECTOR2* pTexCoord,
CONST D3DXVECTOR2* pTexelSize,
LPVOID pData,
) {
// For a prefilled array:
float * pArray = (float *)pData;
float initial = pArray[(pTexCoord->y*255)+pTexCoord->x];
// For a generator object:
Generator * pGen = (Generator*)pData; // passed in as the third param to fill
float initial = pGen->GetPixel(pTexCoord->x, pTexCoord->y);
pOut->x = pOut->y = pOut->z = (initial * 255);
pOut->w = 255; // set alpha to opaque
}
D3DXCreateTexture: http://msdn.microsoft.com/en-us/library/windows/desktop/bb172800%28v=vs.85%29.aspx
D3DXFillTexture: http://msdn.microsoft.com/en-us/library/windows/desktop/bb172833(v=vs.85).aspx
D3DXSaveTextureToFile: http://msdn.microsoft.com/en-us/library/windows/desktop/bb205433(v=vs.85).aspx
Corresponding functions are available for volume/3D textures. As they are already set up for D3D, you can simply render the texture to a flat quad to view, or use as a source in whatever graphical application you may want.
So long as your generator is thread-safe, you can run the create/fill/save in one thread per texture, and generate multiple slices or frames simultaneously.
I found that the best solution for this problem was to use the SFML library (www.sfml-dev.org). Very simple to use, but must be compiled from source if you want to use it with VS2010.
You can use the PNM image format without any libraries whatsoever. (The format itself is trivial). However it's pretty archaic and you'll have to have an image viewer that supports it. IvanView, for example, supports it on Windows.

A simple PNG wrapper that works. Anybody have a snippet to share?

I'm looking for a way to get a buffer of image data into a PNG file, and a way to get a PNG file into a buffer.
There are just these two things I want to do.
It would be a dead simple wrapper that uses png.h. Well, not exactly dead simple because of the horribly complex libpng API, but the concept of it is.
I tried DevIL before. It is much easier to use than libpng. Still, I have had issues with it. Also, DevIL does too much. I only need lean and mean basic PNG format support, not 20 other formats as well.
Then I find this page. I praised the Pixel Fairy and the Almighty Google for giving me an implementation on a silver platter... Then it turns out this screws up the image: in the processed image every fourth pixel in each scanline goes missing. I am fairly certain from reading the source that this is not meant to happen! It's supposed to zero out red and set green to blue. That didn't happen either.
I have also tried png++. The issue I had with it is that I couldn't get data out of a PNG in a format compatible for loading into OpenGL, I would have to construct another buffer. It just looked ugly, but I will definitely try png++ again before I even think about giving DevIL another shot. Because png++ worked, at least. It's also got the header-only aspect going for it. Still, it did produce a bunch of compiler warnings.
Are there any other contenders? Anybody who has worked with directly using libpng would know how to make what I am asking for: one function that takes a filename and fills a 32-bpp buffer and sets two resolution integers; one function that takes a 32-bpp buffer, two resolution integers, and a filename.
Update-edit: I found this. Might be something there.
This tutorial seems to have what you want.
From the link:
//Here's one of the pointers we've defined in the error handler section:
//Array of row pointers. One for every row.
rowPtrs = new png_bytep[imgHeight];
//Alocate a buffer with enough space.
//(Don't use the stack, these blocks get big easilly)
//This pointer was also defined in the error handling section, so we can clean it up on error.
data = new char[imgWidth * imgHeight * bitdepth * channels / 8];
//This is the length in bytes, of one row.
const unsigned int stride = imgWidth * bitdepth * channels / 8;
//A little for-loop here to set all the row pointers to the starting
//Adresses for every row in the buffer
for (size_t i = 0; i < imgHeight; i++) {
//Set the pointer to the data pointer + i times the row stride.
//Notice that the row order is reversed with q.
//This is how at least OpenGL expects it,
//and how many other image loaders present the data.
png_uint_32 q = (imgHeight- i - 1) * stride;
rowPtrs[i] = (png_bytep)data + q;
}
//And here it is! The actuall reading of the image!
//Read the imagedata and write it to the adresses pointed to
//by rowptrs (in other words: our image databuffer)
png_read_image(pngPtr, rowPtrs);
I'd add CImg to the list of options. While it is an image library the API is not so high level as most (devil/imagemagick/freeimage/GIL). It is also header only.
The image class has simple width height and data members with public access. Under the hood it uses libpng (if you tell it to with preprocessor directive). The data is cast to whatever type you chose for the templated image object.
CImg<uint8_t>myRGBA("fname.png");
myRGBA._data[0] = 255; //set red value of first pixel
Sean Barrett has written two public-domain files for PNG image reading/writing.

Converting image to pixmap using ImageMagic libraries

My assignment is to get "images read into pixmaps which you will then convert to texture maps". So for the pixmap part only, hear me out and tell me if I have the right idea and if there's an easier way. Library docs I'm using: http://www.imagemagick.org/Magick++/Documentation.html
Read in image:
Image myimage;
myimage.read( "myimage.gif" );
I think this is the pixmap I need to read 'image' into:
GLubyte pixmap[TextureSize][TextureSize][3];
So I think I need a loop that, for every 'pixmap' pixel index, assigns R,G,B values from the corresponding 'image' pixel indices. I'm thinking the loop body is like this:
pixmap[i][j][0] = myimage.pixelColor(i,j).redQuantum(void);
pixmap[i][j][1] = myimage.pixelColor(i,j).greenQuantum(void);
pixmap[i][j][2] = myimage.pixelColor(i,j).blueQuantum(void);
But I think the above functions return Quantums where I need GLubytes, so can anyone offer help here?
-- OR --
Perhaps I can take care of both the pixmap and texture map by using OpenIL (docs here: http://openil.sourceforge.net/tuts/tut_10/index.htm). Think I could simply call these in sequence?
ilutOglLoadImage(char *FileName);
ilutOglBindTexImage(ILvoid);
You can copy the quantum values returned by pixelColor(x,y) to ColorRGB and you will get normalized (0.0,1.0) color values.
If you don't have to stick with Magick++ maybe you can try OpenIL, which can load and convert your image to OpenGL texture maps without too much hassle.