使用指针设置 8 位灰度图像的像素颜色

Setting pixel color of 8-bit grayscale image using pointer

我有这个代码:

QImage grayImage = image.convertToFormat(QImage::Format_Grayscale8);
int size = grayImage.width() * grayImage.height();
QRgb *data = new QRgb[size];
memmove(data, grayImage.constBits(), size * sizeof(QRgb));

QRgb *ptr = data;
QRgb *end = ptr + size;
for (; ptr < end; ++ptr) {
    int gray = qGray(*ptr);
}

delete[] data;

基于此:

如何使用该指针设置像素的颜色?

此外,使用 qGray() 并加载“更大”的图像似乎会导致崩溃。

这个有效:

int width = image.width();
int height = image.height();
for (int y = 0; y < height; ++y) {
    for (int x = 0; x < width; ++x) {
        image.setPixel(x, y, qRgba(0, 0, 0, 255));
    }
}

但与显式操作图像数据相比,速度较慢。

编辑

好的,我现在有这个代码:

for (int y = 0; y < height; ++y) {
    uchar *line = grayImage.scanLine(y);
    for (int x = 0; x < width; ++x) {
        int gray = qGray(line[x]);
        *(line + x) = uchar(gray);
        qInfo() << gray;
    }
}

它似乎有效。但是,当我使用只有黑白颜色的图像并打印灰度值时,黑色为 0,白色为 39。如何获得 0-255 范围内的灰度值?

首先,您在这一行中复制了太多数据:

memmove(data, grayImage.constBits(), size * sizeof(QRgb));

ob Qrgb 的大小是 4 个字节,但是根据文档,一个 Format_Grayscale8 像素的大小只有 8 位或 1 个字节。如果你删除 sizeof(QRgb) 你应该复制正确数量的字节,假设位图中的所有行都是连续的(根据文档,它们不是 - 它们至少对齐到 32 位,所以你必须在 size 中考虑到这一点)。数组 data 不应是 Qrgb[size] 类型,而是 ucahr[size] 类型。然后,您可以根据需要修改 data。最后,您可能必须使用接受图像位作为 uchar 并将新图像分配给旧图像的构造函数之一创建一个新的 QImage:

auto newImage = QImage( data, image.width(), image.height(), QImage::Format_Grayscale8, ...);
grayImage = std::move( newImage );

但是您可以通过 bits() 访问其数据直接修改 grayImage,而不是复制图像数据,或者更好的是,通过 scanLine(),可能是这样的:

int line, column;
auto pLine = grayImage.scanLine(line);
*(pLine + column) = uchar(grayValue);

编辑:

根据 scanLine 文档,图像至少是 32 位对齐的。因此,如果您的 8 位灰度图像的宽度为 3 个像素,则新的扫描线将每 4 个字节开始一次。如果您有一张 3x3 的图像,则保存图像像素所需的内存总大小为 12。以下代码显示了所需的内存大小:

int main() {
   auto image = QImage(3, 3, QImage::Format_Grayscale8);
   std::cout << image.bytesPerLine() * image.height() << "\n";
   return 0;
}

fill方法(将所有灰度值设置为0xC0)可以这样实现:

   auto image = QImage(3, 3, QImage::Format_Grayscale8);
   uchar gray = 0xc0;
   for ( int i = 0; i < image.height(); ++i ) {
      auto pLine = image.scanLine( i );
      for ( int j = 0; j < image.width(); ++j )
         *pLine++ = gray;
   }