打开Qt帮助文档,会看到有关于QImage的描述如下:The QImage class provides a hardware-independent image representation that allows direct access to the pixel data, and can be used as a paint device。即QImage类是设备无关的图像,可以进行像素级操作,也可以被用作绘图设备,因为QImage继承于QPaintDevice。
Format:
打开enum QImage::Format,会看到如下信息:
注意:Drawing into a QImage with QImage::Format_Indexed8 is not supported,即对于Format_Indexed8这种格式是不支持绘图的。
只分析几个常用的格式,Format_Indexed8
1 QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);//转成灰度图
2 image.setColorCount(256); // 灰度级数256
3 for (int i = 0; i < 256; i++)
4 {
5 image.setColor(i, qRgb(i, i, i));
6 }
7 uchar *pSrc = mat.data; // 复制mat数据
8 for (int row = 0; row < mat.rows; row++)
9 {
10 uchar *pDest = image.scanLine(row);
11 memcpy(pDest, pSrc, mat.cols);
12 pSrc += mat.step;
13 }
14 return image;
补充两个函数: setPixel( )和setColor( )
对于32位图,每一个像素拥有一个自己的rgb值(RGB、ARGB、premultiplied ARGB),可以使用setPixel( )函数更改任一坐标的ARGB值,例如:
而对于基于索引的单色图和8位图像,需要使用颜色查找表(color table)来操作像素。8-bit图像的每一个像素的值是color。此类图像的像素值只是图像颜色表中的索引。因此,setPixel( )函数只能用于将给定坐标下的像素颜色更改为图像颜色表中的预定义颜色,即它只能更改像素的索引值。要更改图像的颜色表或者向其中添加颜色,可以使用setColor( )函数。例如:
补充:α \alphaα通道:
阿尔法通道(α Channel或Alpha Channel)是指一张图片的透明和半透明度。例如:一个使用每个像素16比特存储的位图,对于图形中的每一个像素而言,可能以5个比特表示红色,5个比特表示绿色,5个比特表示蓝色,最后一个比特是阿尔法。在这种情况下,它要么表示透明要么不是,因为阿尔法比特只有0或1两种不同表示的可能性。又如一个使用32个比特存储的位图,每8个比特表示红绿蓝,和阿尔法通道。在这种情况下,就不光可以表示透明还是不透明,阿尔法通道还可以表示256级的半透明度,因为阿尔法通道有8个比特可以有256种不同的数据表示可能性。
以上说的ARGB值,是关于四通道图片的,其中A代表的就是Alpha值,有时也写作RGBA。例如:以上color table中的0xffbd9527(十六进制)表示不透明的颜色,oxff是255,bd是189,95是149,27是39。即(0xffRRGGBB)。
1、setPixel()函数
void QImage::setPixel(const QPoint &position, uint index_or_rgb)
将给定位置的像素索引或颜色设置为索引或rgb。
如果图像的格式为单色或调色板,则给定的索引或rgb值必须是图像颜色表中的索引,否则该参数必须是QRgb值。
如果position不是图像中的有效坐标对,或者如果index_或_rgb>=colorCount()(对于单色和调色板图像),则结果未定义。
Warning:由于在中调用了内部detach()函数,因此此函数的开销较大;如果性能是一个问题,我们建议使用**scanLine()或bits()**直接访问像素数据。
官方也不推荐以上函数来访问QImage像素,因为效率极低,开销较大。
2、pixel()函数
QRgb QImage::pixel(const QPoint &position) const
返回指定位置的像素颜色
同样有Warning: This function is expensive when used for massive pixel manipulations. Use constBits() or constScanLine() when many pixels needs to be read.
3、scanLine()函数
uchar *QImage::scanLine(int i)
返回索引为i的扫描线处的像素数据指针。第一条扫描线位于索引0处。
4、bits()函数
uchar *QImage::bits()
返回指向第一个像素数据的指针。这相当于scanLine(0)。
Note that QImage uses implicit data sharing. This function performs a deep copy of the shared pixel data, thus ensuring that this QImage is the only one using the current return value.
Implicit Sharing:
Qt中的许多C++类使用隐式数据共享来最大化资源使用和最小化复制。隐式共享类在作为参数传递时既安全又高效,因为只传递指向数据的指针,并且仅当函数写入数据时(即,写入时复制)才会复制数据。在使用=操作符的时候浅复制。
5、constScanLine()函数
const uchar *QImage::constScanLine(int i) const
返回索引为i的扫描线处的像素数据指针。第一条扫描线位于索引0处。
6、constBit()函数
const uchar *QImage::constBits() const
返回指向第一个像素数据的指针。
请注意,QImage使用隐式数据共享,但此函数不执行共享像素数据的深度复制,因为返回的数据是常量。
7、setColor()函数
void QImage::setColor(int index, QRgb colorValue)
将颜色表中给定索引处的颜色设置为给定的colorValue,colorValue是一个ARGB四元组。如果索引超出颜色表的当前大小,则会使用 setColorCount()函数扩展。
8、setColorCount()函数
void QImage::setColorCount(int colorCount)
调整颜色表的大小以包含colorCount个条目,如果颜色表是可扩展的,所有额外颜色将设置为透明(即qRgba(0,0,0,0))。
使用图像时,颜色表必须足够大,以包含图像中所有像素/索引值的条目,否则结果将无法定义。
9、colorCount()函数
int QImage::colorCount() const
返回图像颜色表的大小。注意,对于32 bpp图像,colorCount()返回0,因为这些图像不使用颜色表,而是将像素值编码为ARGB四元组。
10、color()函数
QRgb QImage::color(int i) const
返回索引i处颜色表中的颜色。第一种颜色位于索引0处。
图像颜色表中的颜色指定为ARGB四元组(QRgb)。使用qAlpha()、qRed()、qGreen()和qBlue()函数获取颜色值组件。
11、setColorTable()函数
void QImage::setColorTable(const QVector<QRgb> colors)
将用于将颜色索引转换为QRgb值的颜色表设置为指定的颜色。
使用图像时,颜色表必须足够大,以包含图像中所有像素/索引值的条目,否则结果将无法定义。
12、colorTable()函数
QVector<QRgb> QImage::colorTable() const
返回图像颜色表中包含的颜色列表,如果图像没有颜色表,则返回空列表
有的时候只看注释也不能完全搞懂函数的意思,举一些实例吧
以上部分函数的使用举例(主要代码): 直接建立一个Indexed8格式的QImage,并读入数据
1 QImage Qimg(imgWidth,imgHeight,QImage::Format_Indexed8);
2 //QImage(int width, int height, QImage::Format format)
3 Qimg.setColorCount(256); // 灰度级数256
4 for (int i = 0; i < 256; i++)
5 {
6 Qimg.setColor(i, qRgb(i, i, i));
7 }
8 uchar tempData[imgWidth];
9 for (int i = 0; i < imgHeight; i++)
10 {
11 for (int j = 0; j < imgWidth; j++)
12 {
13 tempData[j] = Hidata[i*imgWidth + j]/16;//将第i+1行的数据复制给一维数组tempdata
14 //Hidata[]为图像数据,事先将图像数据读入该一维数组中,该图像的高为imgWidth、宽为imgHeight
15 }
16 uchar *pDest = Qimg.scanLine(i);
17 memcpy(pDest, tempData, imgWidth);
18 }
19 *qimgHi = Qimg;
20
21 int pixelindexValue = qimgHi->pixelIndex(304,236); //分析图像中点(304,236)处的坐标
22 qDebug() << "像素值索引pixelIndex()为:" << pixelindexValue << Qt::endl;
23
24 QRgb mRgb = qimgHi->pixel(304,236);
25 QColor mColor = QColor(mRgb);
26
27 qDebug() << "QColor,即pixel()为:" << mColor << Qt::endl;
28 qDebug() << mColor.red() << mColor.green() << mColor.blue() << Qt::endl;
29 qDebug() << "QRgb为:" << mRgb << Qt::endl;
运行结果如下:
1 像素值索引pixelIndex()为: 13
2 QColor,即pixel()为: QColor(ARGB 1, 0.0509804, 0.0509804, 0.0509804) // 13/255=0.0509804
3 13 13 13
4 QRgb为: 4279045389
此时对应的图像如下:(工作原因,本次所展示图像均为部分图像)
可以看出pixelIndex()返回当前位置的索引值,而索引值13正好在ColorTable中对应的QRgb也是(13,13,13),而4279045389对应的十六进制为: ff0d0d0d。为了证明pixelIndex()返回的就是索引,可以将上述程序做一变化,如下:
1 for (int i = 0; i < 256; i++)
2 {
3 Qimg.setColor(i, qRgb(255-i, 255-i, 255-i));
4 }
此时的程序输出结果如下,pixelIndex()依然返回当前位置的索引值,但是该索引对应的颜色变成了(242,242,242)
1 像素值索引pixelIndex()为: 13
2 QColor,即pixel()为: QColor(ARGB 1, 0.94902, 0.94902, 0.94902) // (255-13)/255=0.94902
3 242 242 242
4 QRgb为: 4294111986
对应的图像为:
用不同的QImage格式,即使用Qimg.convertToFormat(QImage::Format_Grayscale8)语句,得到不同格式的QImage,并取图像中16个点的pixelIndex和pixel矩阵进行分析,得到列表如下,可见不同格式对图像还是有一定影响的,不展开分析了。