如何在我的灰度8位图像上应用颜色表并在Qt中正确转换它? [英] How can I apply a colortable to my grayscale 8 bit image and convert it correctly in Qt?

查看:184
本文介绍了如何在我的灰度8位图像上应用颜色表并在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:

  1. create a QImage with width and height of original image, and QImage::Format_Indexed8
  2. set color table of this image as proposed by OP
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆