Сначала я проверил, предоставляет ли алгоритм OP для таблицы цветов приемлемые значения. Для этого я написал небольшой пример вокруг открытого кода на coliru и проверил сгенерированные значения глазами. Вывод выглядит разумно (в соответствии с представленным снимком от 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));
Док. используемой функции QImage :: convertToFormat () :
QImage QImage :: convertToFormat (QImage :: Format format, const QVector & colorTable, Qt:: ImageConversionFlags flags = Qt :: AutoColor) const
Это перегруженная функция.
Возвращает копию изображения, преобразованного в заданный формат, используя указанную таблицу цветов.
Преобразование из RGB-форматов в индексированные форматы - это медленная операция, в которой будет использован простой подход с использованием ближайшего цвета без сглаживания.
не помогло. Последнее предложение с простым подходом ближайшего цвета вызвало у меня какие-то подозрения.
Итак, у меня возникли некоторые сомнения, не использует ли он просто значения данных в качестве индексов для таблицы цветов. Но это именно то, что OP на самом деле намеревается сделать.
На самом деле, я хочу что-то вроде «повторной интерпретации» изображения.
Итак, я пришел к такому подходу:
- создайте
QImage
с шириной и высотой исходного изображения и QImage::Format_Indexed8
- задайте таблицу цветов этого изображения в соответствии с предложением OP
- скопируйте данные исходного изображения
Пример 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();
}
Минимальный файл Qt-Project testQImageGrayToRGB.pro
:
SOURCES = testQImageGrayToRGB.cc
QT += widgets
Вывод (VisualStudio 2013, Qt 5.9.2):
Упс. Среднее изображение (которое должно напоминать подход OP) выглядит немного иначе, чем ожидалось от образца OP.
Однако нижнее изображение, полученное с помощью моего подхода «повторного интерпретации», выглядит ожидаемым.
Просто для удовольствия, я снова построил образец в 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
Вывод (cygwin64, g ++ (GCC) 7.4.0, Qt 5.9.4):
Ага! Теперь цвета среднего изображения напоминают то, что описано в OP.
Примечание:
На самом деле, уровень зернистости и индексированное изображение могут использовать одни и те же данные. Это сделает копию строки за строкой устаревшей. Однако время жизни QImage
, владеющего данными, и QImage
, совместно использующего данные, должно быть тщательно рассмотрено в этом случае.