首页 > 编程知识 正文

Qt 2D绘7QImage类操纵像素扫描线像转换

时间:2023-05-03 19:31:56 阅读:226985 作者:4767

Qt 2D绘图(7):QImage类(操纵像素、扫描线、图像转换)

本文为原创文章,转载请注明出处,或注明转载自“甜美的大地帅(原名:wjdxd)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

QImage的基本函数的使用与QPixmap类似,对这些函数的讲解本文从略。

1、QImage图像的存储
存储为QImage的图像,每个像素使用一个整数表示,QImage默认支持的文件格式与QPixmap相同。
单色图像的存储:具有1位深度的图像(即单色图像)被存储到最多拥有两种颜色的颜色表中。单色图像有两种类型:大端(MSB)或小端(LSB)位顺序。
8位深度图像的存储:使用一个8位的索引把8位图像存储到颜色表中,因此8位图像的每个像素占据一字节(8位)的存储空间,即每个像素的颜色与颜色表中某个索引号的颜色相对应。
颜色表使用QVector存储,QRgb类型是使用typedef定义的一个unsigned int类型,该类型包含一个0xAARRGGBB格式的四元组ARGB格式。
32位图像没有颜色表,每个像素直接包含一个QRgb类型的值,共有3种类型的32位图像,分别是RGB(即0xffRRGGBB),ARGB和预乘的ARGB,在预乘格式中,红、绿、蓝通道需乘以alpha分量除以255(详见下一点对alpha的讲解)。
2、对alpha通道的处理(预乘alpha)
带alpha通道的图像有两种处理alpha通道的方法,一种是直接alpha,别一种是预乘alpha,使用预乘alpha通道的图像通常会更快。
直接alpha图像的RGB数值是原始的数值,而预乘alpha图像的RGB数值是乘以alpha通道后得到的数值,比如ARGB = (a , r , g, b);则预乘alpha后的值为(a, a * r, a * g, a * b);

Qt 预乘alpha通道图像的算法是把红、绿、蓝通道的数值乘以alpha通道的数值再除以255,比如使用ARGB32格式表示的0x7F00004E,使用预乘ARGB32格式应表示为0x7F000027,算法为(0x4E * 0x7F) / 0xFF ≈ 0x27,把(0x4E * 0x7F) / 0xFF 变换一下为0x4E * ( 0x7F / 0xFF ) 其中 0x7F / 0xFF是以小数表示的alpha值。再如对于透明度为80% (1-33/FF)的ARGB32格式表示的 0x3337304B,使用预乘ARGB32格式应为0x330B170F,以0x37 为例计算0x37 * (0x33/0xFF),转换为10进制后为55 * 0.2 = 11=0xB。
3、表12-26为QImage类需要使用到的描述图像格式的枚举QImage::Format(完整的枚举可参阅帮助文档)

8、与颜色表和操控像素有关的函数
QRgb类型与qRgb()函数:QRgb类型相当于是使用typedef重命名的unsigned int类型,该类型用于保存颜色,其格式为#AARRGGBB的ARGB四元组。qRgb()是一个用于设置QRgb类型颜色的全局函数,比如qRgb(111,1,1)表示返回一个红色的QRgb类型的颜色。


示例12.36:颜色表及像素操控(结果见图12-76)

//m.h文件的内容#ifndef M_H#define M_H#include<QtWidgets>class B:public QWidget{ Q_OBJECTpublic:B(QWidget *p1=0):QWidget(p1){}void paintEvent(QPaintEvent *e){ QPainter pr; QImage pi(200,200,QImage::Format_Mono);//创建一个单色图像) QRgb r1=qRgb(111,1,1); //红色,注意:颜色是使用qRgb()创建的 QRgb r2=qRgb(1,111,1); //绿色 QRgb r3=qRgb(111,111,1);//黄色 //绘制单色图未填充时的默认样式 pr.begin(this); pr.drawImage(11,11,pi); pr.end(); qDebug()<<pi.colorTable();//输出默认颜色表QVector(4278190080, 4294967295),其中//4278190080=0xFF00 0000,4294967295=0xFFFF FFFF pi.fill(Qt::color1); //使用单色图的颜色表中的索引为1的颜色(绿色)填充图像pi。 //以下步骤用于设置颜色表 QVector<QRgb> v; v.append(r1); v.append(r2); pi.setColorCount(2); //设置颜色表中的颜色数量 pi.setColorTable(v); //设置一个新颜色表(包含红色和绿色)//使用单色图的新颜色表逐像素绘制一个矩形(22,22,128,100) pr.begin(&pi); for(int j=22;j<122;j++) for(int i=22;i<150;i++){ pi.setPixel(i,j,0);}//使用新颜色表中索引为0的颜色(红色)填充位于(i,j)处的像素。 pr.end(); pr.begin(this); pr.drawImage(222,11,pi); //在QWidget中绘制pi qDebug()<<pi.colorTable();//输出新设置的颜色表QVector(4285464833, 4278284033),//其中4285464833=0xFF6F 0101,4278284033=0xFF01 6F01,0x6F=111 pi.setColor(1,r3); //把新颜色表中索引为1的颜色更改为r3(黄色),注意:setColor()函数//改变的是颜色表中的颜色,setPixel()才能改变图像中某个位置的像素颜色。 pr.drawImage(444,11,pi); //在QWidget重新绘制pi qDebug()<<pi.colorTable();//输出更改后的颜色表QVector(4285464833, 4285492993) //其中4285492993=0xFF6F 6F01,0x6F=111 pr.end();}};#endif // M_H//m.cpp文件内容#include "m.h"int main(int argc, char *argv[]){ QApplication app(argc,argv); B w; w.resize(444,333); w.show(); return app.exec(); }

9、与扫描线有关的函数
扫描线是指把图像按水平方向分割成很多条线,每条线就是一条扫描线,说简单点,一条扫描线就是图像中的一行,比如对于300*200的图像,共有200条扫描线(即,有200行)。
注:以下各函数的区别为,返回类型包含const的函数未使用隐式共享,未包含const的函数使用了隐式共享。

示例12.37:扫描线的使用(结果见图12-77)

void paintEvent(QPaintEvent *e){ QPainter pr; QImage pi(200,200,QImage::Format_ARGB32); QImage pi1(200,200,QImage::Format_ARGB32); pi.fill(qRgb(1,111,1)); pi1.fill(qRgb(1,111,1)); //使用绿色填充背景//使用扫描线函数返回的指针逐像素绘制一个矩形//获取指向第一行第一个像素的指针,并将其强制转换为QRgb*以方便修改。 QRgb *pu=(QRgb*)pi.bits();for(int i=0;i<20000;i++) //逐像素设置每个像素的颜色,pi每行有200个像素,//循环2万次意味着设置100行像素的颜色。 { *pu=qRgb(111,1,1);pu++; } QRgb *pu1=(QRgb*)pi1.scanLine(19); //获取第20行扫描线第一个元素的指针 for(int i=0;i<20000;i++){ *pu1=qRgb(111,1,1);pu1++; } pr.begin(this); pr.drawImage(11,11,pi); pr.drawImage(222,11,pi1);qDebug()<<pi1.bytesPerLine(); //输出800(字节),因为pi是32位的ARGB图像,//每个像素占据4字节,每一行有200个像素,//因此每个扫描线占据800个字节大小。 pr.end();}

10、与图像格式或类型转换有关的函数

示例12.38:图像转换(结果见图12-78)

void paintEvent(QPaintEvent *e){ QPainter pr(this); QImage pi2("F:/1z.png"); qDebug()<<pi2.format(); //输出5(即ARGB32格式) pr.drawImage(11,11,pi2); //绘制原始图像 QImage pi3= pi2.convertToFormat(QImage::Format_Grayscale8); //转换为灰度图 pr.drawImage(11,222,pi3); QImage pi4= pi2.rgbSwapped(); //交换红色和蓝色通道 pr.drawImage(222,222,pi4);pi2.invertPixels(); //反转所有像素的颜色,注意,该函数会破坏pi2(但不会破坏原始文件1z.png) pr.drawImage(222,11,pi2); pr.end();}

本文作者:甜美的大地帅(原名:wjdxd)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。