Qt - Cannot export QImage to 16bit bmp - qt

I have created a simple application and I need export from pixmap to the 16-bit bmp image. I have several pixmap items so I have the for loop like this where I first create QImage and convert it to Format_RGB16:
for(QList<image_handler * >::iterator it=imageItems->begin(); it!=imageItems->end(); it++)
{
...
// image_handler inherits QPixmap
QFile export_image(path+"/img_"+code+".bmp");
QImage export_img = (*it)->toImage().convertToFormat(QImage::Format_RGB16);
export_img.save(&export_image, "BMP");
...
}
where image_handler is my custom QPixmap. Images are exported at path given, with correct filename. However when I look at properties of file (in windows) I can see that image depth is 24-bit. Unfortunately I need them to be 16-bit.
What I am doing wrong here? Or is this a bug in Qt? Then how can I export 16-bit bmps from pixmap?

Turns out, that Qt forcibly converts image, before saving it to bmp.
qt-src/src/gui/image/qbmphandler.cpp:777:
bool QBmpHandler::write(const QImage &img)
{
QImage image;
switch (img.format()) {
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_ARGB6666_Premultiplied:
case QImage::Format_ARGB4444_Premultiplied:
image = img.convertToFormat(QImage::Format_ARGB32);
break;
case QImage::Format_RGB16:
case QImage::Format_RGB888:
case QImage::Format_RGB666:
case QImage::Format_RGB555:
case QImage::Format_RGB444:
image = img.convertToFormat(QImage::Format_RGB32);
break;
default:
image = img;
}
...
So, if you need to save bmp 16bit, you'll have to do it manually, filling header and using QImage::bits() and QImage::byteCount().

Related

Use QPixmap instead of QImage?

I have an application where I copy some raw image data into a QImage directly:
QImage* img = new QImage(desc.Width, desc.Height, QImage::Format_RGB32);
for (y = 0; y < img->height(); y++)
{
memcpy(img->scanLine(y), &rawData[y * pRes->RowPitch], pRes->RowPitch);
}
return img;
Later this QImage is drawn via a call
painter.drawPixmap();
Unfortunately drawPixmap() cannot handle a QImage directly, so it first has to be converted:
m_bgImage = new QPixmap();
m_bgImage->convertFromImage(image);
Due to timing reasons I would like to drop this additional conversion step.
Thus my question: are there any function in QPixmap that allow direct image data manipulation right as in QImage?
My idea would be to start with a QPixmap from the very beginning, copy the raw image data into the QPixmap object and then use it directly.
Thanks :-)
First of all you won't need that loop to create the QImage. You can:
QImage* img = new QImage(&rawData, desc.Width, desc.Height, pRes->RowPitch * 4, QImage::Format_RGB32);
Then you can
painter.drawImage(QPointF(0,0),*img);
If there is any specific reason to use QPixmap (like QPixmap caching) you will have no other choice than convert it to QPixmap first.

set image raw data buffer to QMediaPlayer

I want to get a screen shot of the widget application and then set its raw data buffer to QMeidaPlayer with setMedia(). What I have done so far is to receive the image, SAVE it, and then read from it. However, I would like to ask you how to read raw data directly without saving it into media player:
QPixmap originalPixmap = QPixmap::grabWidget(this);
QImage *image = new QImage(originalPixmap.toImage());
QByteArray ba;
QBuffer buffer(&ba);
buffer.setBuffer(&ba);
buffer.open(QIODevice::WriteOnly);
image->save(&buffer); // writes image into ba in PNG format
image->save(image Path);
mediaPlayer.setMedia(QUrl::fromLocalFile(image path)); //I want this to read from raw data
mediaPlayer.play();
I want this to take the minimum CPU usage. However, saving and reading from file consumes lots of CPU,47%.
Cheers,
Update: I tested the program with this code snippet as well. But it does not draw the buffer contents on video widget.
QBuffer *buffer = new QBuffer(image_ba);
QMediaContent media;
mediaPlayer.setMedia(media, buffer);
mediaPlayer.play();
Any ideas how I can resolve this to input image raw data to video widget?
here's how you can do it:
QPixmap originalPixmap = QPixmap::grabWidget(this);
QBuffer *buffer = new QBuffer(); // make sure that your buffer has the same life span as your media player, or otherwise the media player would try to read data from non-existing buffer. (the setMedia() and play() methods are non-blocking)
buffer.open(QIODevice::ReadWrite);
originalPixmap.save(buffer, "PNG"); // can be any other format, not just PNG
mediaPlayer.setMedia(QUrl(), buffer);
mediaPlayer.play();

cv::Mat to QImage conversion

I've found very similiar topic: how to convert an opencv cv::Mat to qimage , but it does not solve my problem.
I have function converting cv::Mat to QImage
QImage cvMatToQImg(cv::Mat& mat)
{
cv::Mat rgb;
if(mat.channels()==1)
{
cv::cvtColor(mat,rgb,CV_GRAY2BGR);
cv::cvtColor(rgb,rgb,CV_BGR2BGRA);
QImage temp = QImage((unsigned char*)(rgb.data), rgb.cols,
rgb.rows,QImage::Format_ARGB32 );
QImage returnImage = temp.copy();
return returnImage;
}
And it's works for my but I want to make it more efficient.
First: why changing 2 cvtColor functions with:
cv::cvtColor(mat,rgb,CV_GRAY2BGRA)
fails on
QImage returnImage = temp.copy()
with segfault.
Then how to eliminate copying of QImage. When I simply return temp image, I'm getting segfault.
Any other optimalizations can be done there? It's very often used function so I want to make it as fast as possible.
Your solution to the problem is not efficient, in particular it is less efficient then the code I posted on the other question you link to.
Your problem is that you have to convert from grayscale to color, or RGBA. As soon as you need this conversation, naturally a copy of the data is needed.
My solution does the conversion between grayscale and color, as well as between cv::Mat and QImage at the same time. That's why it is the most efficient you can get.
In your solution, you first try to convert and then want to build QImage around OpenCV data directly to spare a second copy. But, the data you point to is temporary. As soon as you leave the function, the cv::Mat free's its associated memory and that's why it is not valid anymore also within the QImage. You could manually increase the reference counter of the cv::Mat beforehand, but that opens the door for a memory leak afterwards.
In the end, you attempt a dirty solution to a problem better solved in a clean fashion.
It may be easiest to roll your own solution. Below is the current OpenCV implementation for going from gray to RGBA format:
template<typename _Tp>
struct Gray2RGB
{
typedef _Tp channel_type;
Gray2RGB(int _dstcn) : dstcn(_dstcn) {}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
if( dstcn == 3 )
for( int i = 0; i < n; i++, dst += 3 )
{
dst[0] = dst[1] = dst[2] = src[i];
}
else
{
_Tp alpha = ColorChannel<_Tp>::max();
for( int i = 0; i < n; i++, dst += 4 )
{
dst[0] = dst[1] = dst[2] = src[i];
dst[3] = alpha;
}
}
}
int dstcn;
};
Here is where the actual cvtColor call occurs:
case CV_GRAY2BGR: case CV_GRAY2BGRA:
if( dcn <= 0 ) dcn = 3;
CV_Assert( scn == 1 && (dcn == 3 || dcn == 4));
_dst.create(sz, CV_MAKETYPE(depth, dcn));
dst = _dst.getMat();
if( depth == CV_8U )
CvtColorLoop(src, dst, Gray2RGB<uchar>(dcn));
This code is contained in the color.cpp file in the imgproc library.
As you can see, since you are not setting the dstCn parameter in your cvtColor calls, it defaults to dcn = 3. To go straight from gray to BGRA, set dstCn to 4. Since OpenCV's default color order is BGR, you'll still need to swap the color channels for it to look right (assuming you get your image data from an OpenCV function). So, it may be worth it to implement your own converter possibly following the above example, or using ypnos answer here.
Also, have a look at my other answer involving how to integrate OpenCV with Qt.
The problem is that both the cv::Mat and QImage data isn't necessarily contiguous.
New data rows in opencv start on a 32bit boundary (not sure about QImage - I think it's system dependant) so you can't copy a memeory block unless your rows happen to be exact multiples of 4bytes
See How to output this 24 bit image in Qt

Problem with QT save() function for QImage

I have a problem which I have been trying to figure out for few days now. I am using OpenCV to get frames from a camera and then I am converting it to QImage and trying to save the frame on a disk. The problem I am facing is that if I compile/run the code in release/debug mode in visual studio then it works fine. If I run the executable created by visual studio for debug mode then it runs fine. But if I run the executable created by visual studio in release mode, the gui works well except that the QImage save() function doesn't work anymore. If I use OpenCV function for saving the frame then it works well in all modes. The QImage that I am trying to save is notNull because my comments text box displays the line I print inside but the save function returns false. I would really appreciate help.
Here is a little code:
Code for conversion between IplImage and QImage (I have also used another code, with the same result)
QImage A::IplImage2QImage(const IplImage *iplImage)
{
int height = iplImage->height;
int width = iplImage->width;
if (iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 3) {
const uchar *qImageBuffer = (const uchar*)iplImage->imageData;
QImage img(qImageBuffer, width, height, QImage::Format_RGB888);
return img.rgbSwapped();
}
else {
// qWarning() << "Image cannot be converted.";
return QImage();
}
}
void A::getFrame()
{
commentsTextBox->setText("getFrame");
if (VI.isFrameNew(device1)) {
VI.getPixels(device1, (unsigned char *)frame->imageData, false, true);
}
QImage qimg2 = IplImage2QImage(frame);
m_Label->setPixmap(QPixmap::fromImage(qimg2));
if (!qimg2.isNull()) {
x = qimg2.save("C:\\Data\\test.jpg");
commentsTextBox->append("notEmpty33");
}
}
I had the same problem to QImage::load(). I will post a copy of the solution pointed out in the link of alexisdm, in order to make it clearer.
Under windows the qjpeg4.dll must in a imageformats directory under
the application's directory by default.
Thank you!
Try something like this,
// Prepare the url,
QUrl url("file:///home/ubuntu/Desktop/image.jpg");
// Get the path,
QString path = url.path();
// Save the image,
myQimage.save(path);

Cannot see IplImage in QGraphicsView

I'm trying to display a 3D scene(OpenGL-OpenCV) in a QGraphicsView object in QT. The scene has 5 planes: top, bottom, right, left and front. I'm taking images from my webcam and mapping them to the front plane. I have successfully displayed 4 of 5 planes, the front plane is missing.
I followed this tutorial to load the OpenGL scene: http://doc.trolltech.com/qq/qq26-openglcanvas.html
However, I don't know how to treat the IplImage to be displayed in the QT Object. Do you guys have any suggestion?
This is something that I salvaged out of a blog posting,
This will provide you with a QImage that you can display using Qt.
you should tailor it to fit your needs.
QImage img;
constructor()
{
// setup capture device
CvCapture *cvCapture = cvCreateCapture(0);
}
getQImageFromIplImage()
{
// this frame gets a frame from capture device
IplImage *frame = new IplImage();
frame = cvQueryFrame(cvCapture);
// create an IplImage with 8bit color depth
IplImage *iplImg = cvCreateImage(cvSize(frame->width, frame->height),IPL_DEPTH_8U, 3);
// copy image captured from capture device to new image, converting pixel data from OpenCV's default BGR format to Qt's RGB format
cvCvtColor(frame, iplImg, CV_BGR2RGB);
// create a this newly converted RGB pixel data with a QImage
qImg = QImage((uchar *)iplImg->imageData, iplImg->width, iplImg->height, QImage::Format_RGB888);
}
for full code, check out:
http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/

Resources