如何在我的灰度8位图像上应用颜色表并在Qt中正确转换它? [英] How can I apply a colortable to my grayscale 8 bit image and convert it correctly in Qt?
问题描述
我想将我的grayscale_8 QImage转换为带有色表的Indexed_8.我发现已经找到并测试了可以准确生成颜色图(并通过眼睛检查生成的值.输出看起来合理(根据MatLab提供的快照).我认为那不是问题.
接下来我调查了
q = QImage((uchar *)p-> GetBuffer(),p-> GetWidth(),p-> GetHeight(),QImage :: Format_Grayscale8);QImage c = q.convertToFormat(QImage :: Format_Indexed8,colortable);ui-> imageLabel-> setPixmap(QPixmap :: fromImage(c));
文档.使用的函数
糟糕.中间图像(应该类似于OP的方法)看起来与OP样本中的预期有所不同.
但是,我的重新诠释"实现了最基本的图像方法看起来确实像预期的那样.
只是为了好玩,我在
啊哈!现在,中间图像的颜色类似于OP所描述的颜色.
注意:
实际上,灰度图像和索引图像可以共享相同的数据.这将使逐行复制变得过时.但是,在这种情况下,必须仔细考虑拥有数据的 QImage
和共享数据的 QImage
的生命周期.
I would like to convert my grayscale_8 QImage to an Indexed_8 with a colortable. I found have found and tested functions that generate a colormap (MATLAB jet) accurately -- here is my code:
for (double i = 0; i < 256; ++i) {
double hi = 255;
double lo = 0;
double r = -4.0 * std::abs(i - 255.0 * 3.0 / 4) + 255.0 * 3.0 / 2;
double g = -4.0 * std::abs(i - 255.0 * 2.0 / 4) + 255.0 * 3.0 / 2;
double b = -4.0 * std::abs(i - 255.0 * 1.0 / 4) + 255.0 * 3.0 / 2;
CP->colortable.append(qRgb(r < lo ? lo : r > hi ? hi : r, g < lo ? lo : g > hi ? hi : g, b < lo ? lo : b > hi ? hi : b));
}
The r,g,b doubles represent MATLAB's jet colormap, given inputs from 0 to 255 and outputs within the range (0,255). The ternary operators are equivalent to std::clamp, and limit values to between 0 and 255.
Then I convert the image as follows:
q = QImage((uchar*)p->GetBuffer(), p->GetWidth(), p->GetHeight(), QImage::Format_Grayscale8);
QImage c = q.convertToFormat(QImage::Format_Indexed8, colortable);
ui->imageLabel->setPixmap(QPixmap::fromImage(c));
You can see there is no red in this image
despite the fact that I know the value in the cyan section has pixel values of 255. It would appear that blue is added back in place of red. Is this a simple formatting error?
Here is what the MATLAB jet colormap looks like normalized
and
here is what my image should look like
.
At first, I checked whether OP's exposed algorithm for the color table provides reasonable values. For this, I wrote a small sample around the exposed code on coliru and checked generated values by eyes. The output looks reasonable (according to the presented snapshot from MatLab) – I assume that's not the issue.
Next I investigated into
q = QImage((uchar*)p->GetBuffer(), p->GetWidth(), p->GetHeight(), QImage::Format_Grayscale8);
QImage c = q.convertToFormat(QImage::Format_Indexed8, colortable);
ui->imageLabel->setPixmap(QPixmap::fromImage(c));
The doc. of the used function QImage::convertToFormat():
QImage QImage::convertToFormat(QImage::Format format, const QVector &colorTable, Qt::ImageConversionFlags flags = Qt::AutoColor) const
This is an overloaded function.
Returns a copy of the image converted to the given format, using the specified colorTable.
Conversion from RGB formats to indexed formats is a slow operation and will use a straightforward nearest color approach, with no dithering.
was no real help. The last sentence with the straightforward nearest color approach made me suspicious somehow.
So, I had some doubts whether it just re-uses the data values as indexes into the color table. But that's what OP actually intends to do.
Actually, I want something like a “reinterprete-cast” of the image.
So, I came up with this approach:
- create a
QImage
with width and height of original image, andQImage::Format_Indexed8
- set color table of this image as proposed by OP
- copy the data of original image into this image.
Sample testQImageGrayToRGB.cc
:
#include <vector>
#include <QtWidgets>
typedef unsigned char uchar;
QImage buildSample(const int w = 256, const int h = 32)
{
QImage qImg(w, h, QImage::Format_Grayscale8);
const int bpl = qImg.bytesPerLine();
for (int y = 0; y < h; ++y) {
uchar *row = qImg.bits() + y * bpl;
for (int x = 0; x < w; ++x) {
row[x] = (uchar)(x * 255 / (w - 1));
}
}
return qImg;
}
const QVector<QRgb> makeColorTable()
{
QVector<QRgb> qColTbl;
const double hi = 255;
const double lo = 0;
for (double i = 0; i < 256; ++i) {
double r = -4.0 * std::abs(i - 255.0 * 3.0 / 4) + 255.0 * 3.0 / 2;
double g = -4.0 * std::abs(i - 255.0 * 2.0 / 4) + 255.0 * 3.0 / 2;
double b = -4.0 * std::abs(i - 255.0 * 1.0 / 4) + 255.0 * 3.0 / 2;
qColTbl.append(
qRgb(
r < lo ? lo : r > hi ? hi : r,
g < lo ? lo : g > hi ? hi : g,
b < lo ? lo : b > hi ? hi : b));
}
return qColTbl;
}
QImage colorize(const QImage &qImg, const QVector<QRgb> &qColTbl)
{
const int w = qImg.width(), h = qImg.height();
QImage qImgDst(w, h, QImage::Format_Indexed8);
qImgDst.setColorTable(qColTbl);
const int bpl = qImg.bytesPerLine();
const int bplDst = qImgDst.bytesPerLine();
for (int y = 0; y < h; ++y) {
const uchar *row = qImg.bits() + y * bpl;
uchar *rowDst = qImgDst.bits() + y * bplDst;
std::copy(row, row + w, rowDst);
}
return qImgDst;
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// build contents
const QImage qImgGray = buildSample();
const QVector<QRgb> qColTbl = makeColorTable();
const QImage qImgColorOP
= qImgGray.convertToFormat(QImage::Format_Indexed8, qColTbl);
const QImage qImgColorDS
= colorize(qImgGray, qColTbl);
// build some GUI
QWidget win;
QVBoxLayout qVBox;
QLabel qLblGray(
QString::fromUtf8("QImage Source: (QImage::Format_Grayscale8)"));
qVBox.addWidget(&qLblGray);
QLabel qLblImgGray;
qLblImgGray.setPixmap(QPixmap::fromImage(qImgGray));
qVBox.addWidget(&qLblImgGray);
QLabel qLblColorOP(
QString::fromUtf8("QImage Colorized: (Attempt of OP)"));
qVBox.addWidget(&qLblColorOP);
QLabel qLblImgColorOP;
qLblImgColorOP.setPixmap(QPixmap::fromImage(qImgColorOP));
qVBox.addWidget(&qLblImgColorOP);
QLabel qLblColorDS(
QString::fromUtf8("QImage Colorized: (Attempt of DS)"));
qVBox.addWidget(&qLblColorDS);
QLabel qLblImgColorDS;
qLblImgColorDS.setPixmap(QPixmap::fromImage(qImgColorDS));
qVBox.addWidget(&qLblImgColorDS);
win.setLayout(&qVBox);
win.show();
// exec. application
return app.exec();
}
A minimal Qt-Project file testQImageGrayToRGB.pro
:
SOURCES = testQImageGrayToRGB.cc
QT += widgets
Output (VisualStudio 2013, Qt 5.9.2):
Oops. The middle image (which should resemble the approach of OP) looks a bit different than expected from OPs sample.
However, the bottom image achieved with my “reinterprete-cast” approach does look like expected.
Just for fun, I built the sample again in cygwin64:
$ qmake-qt5 testQImageGrayToRGB.pro
$ make && ./testQImageGrayToRGB
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQImageGrayToRGB.o testQImageGrayToRGB.cc
g++ -o testQImageGrayToRGB.exe testQImageGrayToRGB.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
Output (cygwin64, g++ (GCC) 7.4.0, Qt 5.9.4):
Aha! Now, the colors of middle image resembles what OP described.
Note:
Actually, graylevel and indexed image could share the same data. This would make the row-for-row copy obsolete. However, the life-times of the QImage
owning the data and the QImage
sharing the data have to be considered carefully in this case.
这篇关于如何在我的灰度8位图像上应用颜色表并在Qt中正确转换它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!