使用指针设置 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;
}
我有这个代码:
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;
}