I am trying to load an image that is given to me as a BITMAPINFO* and a uchar array.
The documentation states that it is a standard Microsoft device independent bitmap (DIB) with 8-bit pixels and a 256-entry color table.
I am curently able to open this image through:
BITMAPINFO* bmih = givenBITMAPINFO;
uchar* data = givenData;
QImage img = QImage(data, bmih->biWidth, bmih->biHeight, QImage::Format_Grayscale8);
But I have two problems with that:
the image is in QImage::Format_Grayscale8 when the documentation states an 8-bit pixels and a 256-entry color table;
the image is upside down and mirrored. This come from the way the bitmap data is stored in Win32.
Anyone knows how I can load properly this image?
By casting the provided header to a BITMAPINFO instead of a BITMAPINFOHEADER I have access to the color table and then apply a trasformation to get a streight image:
BITMAPINFO* bmi = givenHeader;
uchar* data = givenData;
QImage img = QImage(data, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, QImage::Format_Indexed8);
img.setColorCount(256);
for (int i=0; i<256; ++i){
RGBQUAD* rgbBmi = bmi->bmiColors;
img.setColor(i, qRgb(rgbBmi[i].rgbRed, rgbBmi[i].rgbGreen, rgbBmi[i].rgbBlue))
}
img = img.mirrored(false, true);
Related
I'm trying to change the brightness of an image by coverting it from BGR to LAB and changing the L parameter to L+brightness. It works to change the brightness but the output image is blue , why?
void MainWindow::BrightnessSlider(cv::Mat image)
{
cv::Mat image2;
cv::cvtColor(image,image2,cv::COLOR_BGR2Lab);
for (int i=0; i < image2.rows; i++)
{
for (int j=0; j < image2.cols; j++)
{
image2.at<cv::Vec3b>(i,j)[0] = cv::saturate_cast<uchar>(image2.at<cv::Vec3b>(i,j)[0] + brightness);
}
}
cv::cvtColor(image2,image2,cv::COLOR_Lab2BGR);
QImage imageupdate= QImage((const unsigned char*)(image2.data), image2.cols,image2.rows,QImage::Format_RGB888);
int w = ui->label->width();
int h =ui-> label->height();
ui->label->setPixmap(QPixmap::fromImage(imageupdate.scaled(w,h,Qt::KeepAspectRatio)));
}
The main problem here is that 3-channel color images in OpenCV use BGR memory layout, while in Qt they use RGB memory layout. That's why your image shown in QLabel looks "blue".
To fix the memory layout problem, you should change cv::COLOR_Lab2BGR to cv::COLOR_Lab2RGB in the second cv::cvtColor():
cv::cvtColor(image2, image2, cv::COLOR_Lab2RGB);
Or append .rgbSwapped() to imageupdate (note that imageupdate will not share memory block with image2):
QImage imageupdate = QImage((const unsigned char*)(image2.data),
image2.cols, image2.rows, QImage::Format_RGB888).rgbSwapped();
BTW, you can just use Mat::operator+(const Scalar&) to change the value for all pixels, the color conversion and for-loops are unnecessary:
cv::Mat image2 = image + cv::Scalar::all(brightness);
// convert BGR to RGB if you don't want to allocate additional memory
// for imageupdate with QImage::rgbSwapped():
cv::cvtColor(image2, image2, cv::COLOR_BGR2RGB);
With Qt, I am trying to convert a Format_Indexed8 image to Format_RGB30 by using a custom conversion rule defined by a color table. I thought this would be simple, since QImage::convertToFormat can take a color table as an argument, but I can't make it work.
Here is my code:
QImage image = QImage(data, width, height, QImage::Format_Indexed8);
QVector<QRgb> colorTable(256);
for (int i = 0; i < 255; i++)
colorTable[i] = qRgb(255 - i, i, i);
image = image.convertToFormat(QImage::Format_RGB30, colorTable);
This code just gives me an image that is in RGB format, but that looks identical to the eye to the grayscale image.
I think the color table argument in QImage::convertToFormat is required to convert from RGB to indexed, while you're converting the other way around.
I would try setting the color table directly in the indexed file (source), using QImage::setColorTable, then call convertToFormat passing the format argument only:
QImage image = QImage(data, width, height, QImage::Format_Indexed8);
image.setColorTable(colorTable);
image = image.convertToFormat(QImage::Format_RGB30);
This is not necessary since Qt 5.5 (released in July of 2015). You can now use QImage::Format_Grayscale8. Your code would be simply:
QImage image{data, width, height, QImage::Format_Grayscale8};
If I load an image into ImageMagick with the read function like so:
Magick::Image image;
image.read(filename);
how can I tell if the loaded image has an alpha channel? I want to direct my program to a different algorithm when I manipulate the pixels of a PNG with transparency vs when I load an opaque JPG.
Is there a simple yes/no test I can do?
The reason I am asking is because a code snippet like the following seems to assign random opacities if the loaded image does not have them, rather than assuming the pixel is completely opaque:
// transform the pixels to something GL can use
Magick::Pixels view(image);
GLubyte *pixels = (GLubyte*)malloc( sizeof(GLubyte)*width*height*4 );
for ( ssize_t row=0; row<height; row++ ) {
const Magick::PixelPacket *im_pixels = view.getConst(0,row,width,1);
for ( ssize_t col=0; col<width; col++ ) {
*(pixels+(row*width+col)*4+0) = (GLubyte)im_pixels[col].red;
*(pixels+(row*width+col)*4+1) = (GLubyte)im_pixels[col].green;
*(pixels+(row*width+col)*4+2) = (GLubyte)im_pixels[col].blue;
*(pixels+(row*width+col)*4+3) = 255-(GLubyte)im_pixels[col].opacity;
}
}
*pTex = pContext->LoadTexture( pixels, width, height );
free(pixels);
You can use the matte() property to determine if your image supports transparency.
Magick::Image image;
image.read(filename);
if (image.matte())
executeMethod(image);
I'm having a one Channel image, and want to display it in a QImage
IplImage *img=cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);
Knowing that When converting from an IplImage* to QImage, I did what is follow:
uchar* img_d=(uchar*) img->imageData;
QImage img_direction((uchar*)img_d, img->width, img->height, QImage::Format_Mono);
I'm not pretty sure about the Mono format that I have set, even the displayed QImage would be scrambled!
What would be the suitable QImage format for the case of a B&W image?
Qt's Mono format is 1-bit per pixel.
The only 8-bit format is QImage::Format_Indexed8, so you'll need to create a color table with the 256 grays and pass it to QImage::setColorTable.
The table could be filled like this:
QVector<QRgb> colorTable;
for(int i=0; i<256; ++i)
colorTable << qRgb(i,i,i);
I have been able to display an image in a label in Qt using something like the following:
transformPixels(0,0,1,imheight,imwidth,1);//sets unsigned char** imageData
unsigned char* fullCharArray = new unsigned char[imheight * imwidth];
for (int i = 0 ; i < imheight ; i++)
for (int j = 0 ; j < imwidth ; j++)
fullCharArray[(i*imwidth)+j] = imageData[i][j];
QImage *qi = new QImage(fullCharArray, imwidth, imheight, QImage::Format_RGB32);
ui->viewLabel->setPixmap(QPixmap::fromImage(*qi,Qt::AutoColor));
So fullCharArray is an array of unsigned chars that have been mapped from the 2D array imageData, in other words, it is imheight * imwidth bytes.
The problem is, it seems like only a portion of my image is showing in the label. The image is very large. I would like to display the full image, scaled down to fit in the label, with the aspect ratio preserved.
Also, that QImage format was the only one I could find that seemed to give me a close representation of the image I am wanting to display, is that what I should expect? I am only using one byte per pixel (unsigned char - values from 0 to 255), and it seems liek RGB32 doesnt make much sense for that data type, but none of the other ones displayed anything remotely correct
edit:
Following dan gallaghers advice, I implemented this code:
QImage *qi = new QImage(fullCharArray, imwidth, imheight, QImage::Format_RGB32);
int labelWidth = ui->viewLabel->width();
int labelHeight = ui->viewLabel->height();
QImage small = qi->scaled(labelWidth, labelHeight,Qt::KeepAspectRatio);
ui->viewLabel->setPixmap(QPixmap::fromImage(small,Qt::AutoColor));
But this causes my program to "unexpectedly finish" with code 0
Qt doesn't support grayscale image construction directly. You need to use 8-bit indexed color image:
QImage * qi = new QImage(imageData, imwidth, imheight, QImage::Format_Indexed8);
for(int i=0;i<256;++i) {
qi->setColor(i, qRgb(i,i,i));
}
QImage has a scaled member. So you want to change your setPixmap call to something like:
QImage small = qi->scaled(labelWidth, labelHeight, Qt::KeepAspectRatio);
ui->viewLabel->setPixmap(QPixmap::fromImage(small, Qt::AutoColor);
Note that scaled does not modify the original image qi; it returns a new QImage that is a scaled copy of the original.
Re-Edit:
To convert from 1-byte grayscale to 4-byte RGB grayscale:
QImage qi = new QImage(imwidth, imheight, QImage::Format_RGB32);
for (int i = 0; i < imheight; i++)
{
for (int j = 0; j < imwidth; j++)
{
qi->setPixel(i, j, QRgb(imageData[i][j], imageData[i][j], imageData[i][j]));
}
}
Then scale qi and use the scaled copy as the pixmap for viewLabel.
I've also faced similar problem - QImage::scaled returned black images. The quick work-around which worked in my case was to convert QImage to QPixmap, scale and convert back then. Like this:
QImage resultImg = QPixmap::fromImage(image)
.scaled( 400, 400, Qt::KeepAspectRatio )
.toImage();
where "image" is the original image.
I was not aware of format-problem, before reading this thread - but indeed, my images are 1-Bit black-white.
Regards,
Valentin Heinitz