Display image in Qt that is coming from an unsigned char** - c++

I am trying to display an image in Qt that is coming in as data from another function.
That function stores the rows of an image as an unsigned char**
I read somewhere I could somehow store it as a QByteArray and then create a QPixMap then set the QPixMap of a label to display it, but I am not having much luck.
This is what I had:
unsigned char* fullCharArray = new unsigned char[imheight * imwidth];
for (int i = 0 ; i < imheight ; i++)
for (int j = 0 ; j < imwidth ; j++)
fullCharArray[i*j+j] = imageData[i ][j];
QPixmap *p = new QPixmap(reinterpret_cast<const char *>(fullCharArray));
ui->viewLabel->setPixMap(p);
But this seems to give me an error, and may be the wrong thing anyway. When i tried to call setPixMap(p[]) the error goes away, but the image does not get displayed in the label.
imageData is the 2D array that is populated by my other function. Best I figured in order to create a new QPixMap I had to convert that to a 1D array, and do the index calculations manually there. That is what the double For loop is doing.
So is there a better way of displaying this image data in Qt?

Use QImage. This constructor should help you: http://doc.qt.io/qt-5/qimage.html#QImage-4

Pixmaps are not 2D arrays of pixels. They are actually defined as an array of character strings describing the image.
For example, a 4x4 pixels image with center 4 pixels black, and 4 corner pixels red is:
/* XPM */
static char * sample_xpm[] = {
"4 4 3 1",
" c #FF0000",
". c #FFFFFF",
"+ c #000000",
" .. ",
".++.",
".++.",
" .. "};
It is a convenient file format to store small images (e.g. for toolbar buttons) that can be integrated as is into a C source file using a standard #include directive, to be compiled along with the rest of the program.

You use QPixmap if the data is already in an image format like PNG or jpeg with a header.
To create an image from pixel values use Qimage, then convert this to a pixmap (Qpixmap.fromImage() - if needed to save it or display it.

Related

SDL putting lots of pixel data onto the screen

I am creating a program that allows you to view fractals like the Mandelbrot or Julia set. I would like to render them as quickly as possible. I would love a way to put an array of uint8_t pixel values onto the screen. The array is formatted like this...
{r0,g0,b0,r1,g1,b1,...}
(A one dimensional array or RGB color values)
I know I have the proper data because before I just set individual points and it worked...
for(int i = 0;i < height * width;++i) {
//setStroke and point are functions that I made that together just draw a colored point
r.setStroke(data[i*3],data[i*3+1],data[i*3+2]);
r.point(i % r.window.w,i / r.window.w);
}
This is a pretty slow operation especially if the screen is big (which I would like it to be)
Is there any faster way to just put all the data onto the screen.
I tried doing something like this
void* pixels;
int pitch;
SDL_Texture* img = SDL_CreateTexture(ren,
SDL_GetWindowPixelFormat(win),SDL_TEXTUREACCESS_STREAMING,window.w,window.h);
SDL_LockTexture(img, NULL, &pixels, &pitch);
memcpy(pixels, data, window.w * 3 * window.h);
SDL_UnlockTexture(img);
SDL_RenderCopy(ren,img,NULL,NULL);
SDL_DestroyTexture(img);
I have no idea what I'm doing so please have mercy
Edit (thank you for comments :))
So here is what I do now
SDL_Texture* img = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGB888,SDL_TEXTUREACCESS_STREAMING,window.w,window.h);
SDL_UpdateTexture(img,NULL,&data[0],window.w * 3);
SDL_RenderCopy(ren,img,NULL,NULL);
SDL_DestroyTexture(img);
But I get this Image... which is not what it should look like
I am thinking that my data is just formatted wrong, right now it is formatted as an array of uint8_t in RGB order. Is there another way I should be formatting it (note I do not need an alpha channel)

Sending a stream of screen captures in C++

I'm looking for a way to convert a screen capture to a char* in an efficient way.
I thought about capturing the screen using a bitmap object, then converting the bitmap object to an array of bytes and then to a char*, but I couldn't find any way to convert then bitmap to an array of bytes.
I also thought about iterating every pixel in the screen capture and saving the RGB values in an array, but that creates an array that is too big for me.
The end goal is to return a char* object in the fastest way that doesn't return an object that is too large, and that char* contains the data of the screen captured.
You don't given enough info/code to understand what you're really trying to achieve by this. E.g. how are you planning to represent the colour coefficients? Anyway, a way to go would be to use the opencv library, e.g.:
cv::Mat mat = cv::imread("PATH/TO/YOUR/FILE.bmp");
char table[mat.rows * mat.cols * 3]; // assuming that we have 3 colour channels
unsigned int index = 0;
cv::MatIterator_<uchar> it, end;
for( it = mat.begin<uchar>(), end = mat.end<uchar>(); it != end; ++it)
table[index++] = *it;

Can you assign 3 channel image data to QCustomPlots ColorMap function?

I'm working on a program for image processing. At the present stage I split a CV_64FC3 into 3 colour channels, RGB, then use this as the data for a QCPColorMap.
The implementation is like this:
for(int col = 0; col < image.cols; ++col) {
for(int row = 0; row < image.rows; row++) {
colorMap->data()->setCell(row,col,rotated_matrix.at<double>(row,col));
}
}
Where rotated_matrix is a CV_64FC1 cv::Mat. This works fine and displays the colour map accordingly.
My question is can I pass through a 3 channel cv::Mat (CV_64FC3) and assign this to the data points in the QCPColorMap?
I've had a look at the documentation and as far as I can see the only variables that colorMap->data()->setCell or colorMap->data()->setData can accept are keyIndex, valueIndex, z which represent essentially x coordinate, y coordinate and then the colour value itself.
I can't seem to find a way to modify the number of channels/layers in the image to assign.
Am I missing something here?
Cheers
Mitch
Here's a somewhat painful way: put multiple instances of QPColorMap over each other and use the alpha channel to toggle off selected ones. I suppose one could sub-class QPColorMap and access QRgb that way, but that would be even harder.
This does seems like a target for modification in QCustomPlot. My sample application: show a grayscale image (e.g., a brain) with a color overlay indicating either a region of interest or an "activated" or somehow abnormal area. For this one needs access to the RBG fields.

Can't display a PNG using Glut or OpenGL

Code is here:
void readOIIOImage( const char* fname, float* img)
{
int xres, yres;
ImageInput *in = ImageInput::create (fname);
if (! in) {return;}
ImageSpec spec;
in->open (fname, spec);
xres = spec.width;
yres = spec.height;
iwidth = spec.width;
iheight = spec.height;
channels = spec.nchannels;
cout << "\n";
pixels = new float[xres*yres*channels];
in->read_image (TypeDesc::FLOAT, pixels);
long index = 0;
for( int j=0;j<yres;j++)
{
for( int i=0;i<xres;i++ )
{
for( int c=0;c<channels;c++ )
{
img[ (i + xres*(yres - j - 1))*channels + c ] = pixels[index++];
}
}
}
in->close ();
delete in;
}
Currently, my code produces JPG files fine. It has the ability to read the file's information, and display it fine. However, when I try reading in a PNG file, it doesn't display correctly at all. Usually, it kind of displays the same distorted version of the image in three separate columns on the display. It's very strange. Any idea why this is happening with the given code?
Additionally, the JPG files all have 3 channels. The PNG has 2.
fname is simply a filename, and img is `new float[3*size];
Any help would be great. Thanks.`
Usually, it kind of displays the same distorted version of the image in three separate columns on the display. It's very strange. Any idea why this is happening with the given code?
This reads a lot like the output you get from the decoder is in row-planar format. Planar means, that you get individual rows one for every channel one-after another. The distortion and the discrepancy between number of channels in PNG and apparent count of channels are likely due to alignment mismatch. Now you didn't specify which image decoder library you're using exactly, so I can't look up information in how it communicates the layout of the pixel buffer. I suppose you can read the necessary information from ImageSpec.
Anyway, you'll have to rearrange your pixel buffer rearrangement loop indexing a bit so that consecutive row-planes are interleaved into channel-tuples.
Of course you could as well use a ready to use imagefile-to-OpenGL reader library. DevIL is thrown around a lot, but it's not very well maintained. SOIL seems to be a popular choice these days.

embedding a PNG image in C++ as a vector or array

Can anyone point me in a direction so that I can take PNG images that I have and read them in and then store the data of the PNG Image into an array or vector (or some other data structure) so I can actually use that in my code instead of having to read in the PNG, etc?
I know I can use libPNG to read the image but once read in, I am a little stumped in how to take what is read in and convert it to a data structure I can use in my game.
So my thought is I can write a simple console program that I feed a list of PNG's, it reads them and spits out to a file the data for me to hardcode into a data structure in my actual game.
After you have read the data in like Jason has said you could use a struct to contain the data for each pixel .
struct RGBAQUAD
{
int Red;
int Green;
int Blue;
int Alpha;
}
And then you could create a 2D array like such to represent all of the pixel structs as one contiguous image. But a drawback in this is having to manage memory.
RGBQUAD **arr = 0;
arr = new RGBQUAD *[y];
for(int i = 0; i < y ; i++)
arr[i] = new RGBQUAD[x];
alternatively you could pack a pixel into a single int to conserve ram space.
Load the image; take its width, height and bit depth (and possibly more info, if you need); read its color data, and save the information you extracted.
Example of what a data structure could be:
int width;
int height;
int bits;
std::vector<int> data[width*height*bits];
When you use that data structure:
/*
Before these lines, you must get image dimensions and save them to width, height, depth variables. (either read them from somewhere or simply assign e.g. width=1024 if you know the width (I assume you do, as you're going to hardcode the image)).
*/
std::vector<int> sprite(width*height*depth);
for (int i = 0; i < width*height*depth; i++)
// sprite[i] = (read pixel i from somewhere...);