Как я могу применить colortable к моему 8-битному изображению в градациях серого и правильно преобразовать его в Qt? - PullRequest
1 голос
/ 02 ноября 2019

Я хотел бы преобразовать свой QImage в градациях серого_8 в Indexed_8 с цветовой таблицей. Я обнаружил, нашел и протестировал функции, которые точно генерируют цветовую карту ( MATLAB jet ) - вот мой код:

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));


}

Двойные числа r, g, b представляют цветовую карту струи MATLAB,заданные входы от 0 до 255 и выходы в пределах диапазона (0,255). Тернарные операторы эквивалентны std :: Clamp и ограничивают значения от 0 до 255.

Затем я преобразую изображение следующим образом:

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));

Вы можете видеть, что нет красногона этом изображении

, несмотря на тот факт, что я знаю, что значение в голубом сечении имеет значения в пикселях 255. Кажется, что синий цвет добавляется вместо красного. Это простая ошибка форматирования?

Вот как выглядит нормализованная цветовая карта струи MATLAB

и

, вот мое изображениедолжен выглядеть как

.

1 Ответ

0 голосов
/ 02 ноября 2019

Сначала я проверил, предоставляет ли алгоритм 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 на самом деле намеревается сделать.

На самом деле, я хочу что-то вроде «повторной интерпретации» изображения.

Итак, я пришел к такому подходу:

  1. создайте QImage с шириной и высотой исходного изображения и QImage::Format_Indexed8
  2. задайте таблицу цветов этого изображения в соответствии с предложением OP
  3. скопируйте данные исходного изображения

Пример 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):

testQImageGrayToRGB.exe (built with VS 2013)

Упс. Среднее изображение (которое должно напоминать подход 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):

testQImageGrayToRGB.exe (built with g++ in cygwin)

Ага! Теперь цвета среднего изображения напоминают то, что описано в OP.


Примечание:

На самом деле, уровень зернистости и индексированное изображение могут использовать одни и те же данные. Это сделает копию строки за строкой устаревшей. Однако время жизни QImage, владеющего данными, и QImage, совместно использующего данные, должно быть тщательно рассмотрено в этом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...