我有以下代码:
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;
它基于此:https : //stackoverflow.com/a/40740985/8257882
如何使用该指针设置像素的颜色?
另外,使用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 );
但是除了复制图像数据外,你可能还可以grayImage
直接通过bits()
,甚至更好地通过来访问其数据,直接进行修改scanLine()
,如下所示:
int line, column;
auto pLine = grayImage.scanLine(line);
*(pLine + column) = uchar(grayValue);
编辑:
根据scanLine文档,图像至少32位对齐。因此,如果8位grayScale图像的宽度为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;
}
“假定位图中的所有行都是连续的(根据文档,它们不是连续的-至少以32位对齐)。但是当每个像素为8位时,它们现在不应该连续吗?尤其是,当我们将数据更改为uchar类型时,如果我理解正确,那么如果每个像素都是32位,则必须将大小乘以4才能正确对齐数据。
还要这样:“但是,正如评论者所指出的那样,由于数据取决于计算机的体系结构和映像,因此您不应直接使用uchar *。” stackoverflow.com/a/2095127/8257882
stackoverflow.com/a/2095127/8257882中的答案不适用-它仅适用于RGBA(32位)图像,但是您具有8位图像。
uchar
是8位的,因此不需要转换。您不是说3x3图像的大小是9个字节,而不是8位图像的12个字节吗?
32位(4字节)对齐意味着两个连续扫描线的地址差可被4划分。这意味着单个行所需的内存量可被4划分。如果图像有3列,像素需要3个字节,对齐需要1个额外的字节,因此需要4个字节。3x4是12。