当前位置: 首页>开发笔记>正文

QImage 图像格式小结 Format_RGB32

QImage 图像格式小结 Format_RGB32

原文链接
嗯,这个QImage的问题研究好久了,有段时间没用,忘了,已经被两次问到了,突然有点解释不清楚,我汗颜,觉得有必要重新总结下了,不然无颜对自己了。

图像的数据是以字节为单位保存的,每一行的字节数必须是4的整数倍,不足的补0。

(因为我们使用的是32操作系统,因此数据是按照32位对齐的,所以每行的字节数必须是4的整数倍也就是说每行的数据位必须是32位的整数倍。)这里是按照我的理解的,貌似错了,修正一下,最近在看数据对齐,这段话先忽略了,没有删掉,是因为,想留个足迹,等我找到合适的答案再贴上来。不过,图像的数据确实是按32位对齐的。

如果不是整数倍,则根据公式: W = ( w * bitcount + 31 )/32 * 4;

注: w是图像的宽度,bitcount是图像的位深,即32、24等, 计算得到的W是程序中图像每行的字节数。

这里讲述QImage的32、24、8位图。

图像格式:QImage::Format_RGB32 ,QImage::Format_RGB888,QImage::Format_Indexed8。

构造图像:

(1)、QImage myImage1 = QImage(filename);  根据文件名打开图像,如果图像本身是32、24位的,程序中图像是32位的,如果图像本身是8位、1位的,程序中对应为8位、1位。

(2)、QImage myImage2 = QImage(width, height, QImage::Format_…); 根据图像宽高来构造一幅图像,程序会自动根据图像格式对齐图像数据。

操作图像:按照(2)的方式构造图像,在Debug下,如果不给图像myImage2初值,图像不是黑的, 但release下,则构造好的图像默认为黑色。

好了,现在我们需要对图像数据操作,32位图像无疑是最简单的,因为它数据是对齐的。用width表示图像宽度,height表示图像高度。

首先熟悉几个函数:

a、uchar* bits(); 可以获取图像的首地址

b、int byteCount(); 图像的总字节数

c、int bytesPerLine(); 图像每行字节数

1、QImage::Format_RGB32,存入格式为B,G,R,A 对应 0,1,2,3

QImage::Format_RGB888,存入格式为R, G, B 对应 0,1,2QImage::Format_Indexed8,需要设定颜色表,QVector<QRgb>灰度图像颜色表设定:QVector<QRgb>  colorTable;for(int k=0;k<256;++k)
{colorTable.push_back( qRgb(k,k,k) );}

2、QImage p_w_picpath32 = QImage(width, height, QImage::Format_32);

 QImage  p_w_picpath24 = QImage(width, height, QImage::Format_24);QImage  p_w_picpath8 = QImage(width, height, QImage::Format_8);p_w_picpath8.setColorTable(colorTable);

3、需要取每个像素处理,采用指针取值,行扫的方式:

int  lineNum_32 = 0;     //行数int  pixelsub_32 = 0;    //像素下标uchar*    p_w_picpathbits_32 = p_w_picpath32.bits();         //获取图像首地址,32位图uchar*    p_w_picpathbits24 = p_w_picpath24.bits();uchar*    p_w_picpathbits8 = p_w_picpath8.bits();for(int i=0; i<height; ++i){   //按照通常的理解,我们会如下处理,取每行lineNum_32 = i * width * 4;                  //对于任意图像,这句没有问题// lineNum_24 = i * width * 3;             //??当width不是4的整数倍时,这句取不到每行开头// lineNum_8 = i * width;                 //??当width不是4的整数倍时,这句取不到每行开头for(int j=0; j<width; ++j){int r_32 = p_w_picpathbits_32[ lineNum_32 + j * 4 + 2]; int g_32 = p_w_picpathbits_32[ lineNum_32 + j * 4 + 1];int b_32 = p_w_picpathbits_32[ lineNum _32 + j * 4];// int r_24 = p_w_picpathbits_24[ lineNum_24 + j * 3];        //注意区别32位的图// int g_24 = p_w_picpathbits_24[ lineNum_24 + j *3 + 1];// int b_24 = p_w_picpathbits_24[ lineNum_24 + j * 3 + 2];// int gray_8 = p_w_picpathbits_8[ lineNum_8 + j];……//自己的操作}}

//??出问题了,因为实际的图像数据并不是以width为真实宽度的,解决,有两种方法:

第一种方法:自己计算实际的宽度

修改为:

// 获取每行的字节数

int W_32 = ( width * 32 + 31 )/32 * 4; //注意这里没有四舍五入,所以不要随意换算

int W_24 = ( width * 24 + 31 )/32 * 4;

int W_8 = ( width * 8 + 31)/32 * 4;

   //也可以使用QT函数来获取,功能和上面一样

{

    int  W_32 = p_w_picpath32.bytesPerLine();int  W_24 = p_w_picpath24.bytesPerLine();int  W_8 = p_w_picpath8.bytesPerLine();

}

for(int i=0; i<height; ++i)

{

       //现在可以按照通常的理解,取每行lineNum_32 = i * W_32;               //注意,这里不再需要乘倍数了(4, 3等)// lineNum_24 = i * W_24;            // lineNum_8 = i * W_8;                   for(int j=0; j<width; ++j){//这里的操作同上面的一样}

}

第二种方法:采用scanLine(int)来获取每行的首地址,

for(int i=0; i<height; ++i)

{

   p_w_picpathbits_32 = p_w_picpath32.scanLine(i);p_w_picpathbits_24 = p_w_picpath24.scanLine(i);p_w_picpathbits_8 = p_w_picpath8.scanLine(i);for(int j=0; j<width; ++j){int r_32 = p_w_picpathbits_32[ j * 4 + 2]; int g_32 = p_w_picpathbits_32[ j * 4 + 1];int b_32 = p_w_picpathbits_32[ j * 4];// int r_24 = p_w_picpathbits_24[ j * 3];       // int g_24 = p_w_picpathbits_24[ j *3 + 1];// int b_24 = p_w_picpathbits_24[ j * 3 + 2];// int gray_8 = p_w_picpathbits_8[ j ];……//自己的操作}

}

OK,上述两种方法的索引就不会出现图像数据偏移的问题

4、大家注意到QImage的这个构造函数了吧,QImage::QImage ( uchar * data, int width, int height, Format format )

 嗯,这个函数就是从uchar* 的数据来构造图像,一般我们都可能先将图像数据存在uchar*中,uchar* data32 = new uchar[ width * height * 4];      uchar* data24 = new uchar[ width * height * 3];uchar* data8 = new uchar[ width * height];从data32构造图像,不会有任何问题,但是当width不是4的整数倍时,你就不可能从data24和data8构造出自己想要的数据,程序会挂掉的,因为这两个数组的数据量根本不够一幅图(还记得数据补齐不)。

解决办法:

你需要首先计算出,你的图像的真实数据量(字节数), 可以根据QImage.byteCount()函数来获取图像的字节数,当然,你也可以自己计算,计算公式 byteCount = height * W; 这里的W就是每行的字节数,上面已经讲过了它的计算方法。

然后,你可以由QByteArray来获取转换的指针数据:

如:你的图像数据放在数组 uchar* srcData; 中

QByteArray p_w_picpathByteArray = QByteArray( (const char*)srcData, byteCount );

uchar* transData = (unsigned char*)p_w_picpathByteArray.data();

QImage desImage = QImage(transData, width, height, QImage::Format_…);

嗯,经过上述转换后,transData中将是补齐数据的数组,由此构造的图像不会有任何问题。

好了,终于总结完了,有很多小的问题,我不想写了,应该够用了,如果有具体其他问题,大家再仔细想想,肯定能解决的,哈哈

https://www.zydui.com/afafdV28BDQU.html
>

相关文章:

  • image图片格式怎么打开
  • 如何将jpg转换为image
  • rgba转换rgb
  • imagej打开图片
  • image是什么格式
  • qimage读取图片数据
  • imagej图像处理
  • imagejpeg
  • vscode搭建nodejs環境,關于VS code ESP-IDF 提示“loading ‘build.ninja‘: 系統找不到指定的文件” 的解決方案
  • 什么是應用軟件并舉例,16.應用舉例
  • 【面經】美團春招三輪面經分享~涵蓋眾多知識點
  • 2021年面試題目,面試題--新增
  • magic king怎么讀,magick++ 簡介
  • 微信怎么設置定時發送,朋友圈可以定時發送嗎?
  • can not connect to rpc service,RPC service
  • ftpserver安卓版,FTPServer
  • server u使用教程,Server-U
  • rpc服務器,RPC 和 Web Service 有什么區別?
  • rpc服務器,web service和rpc的區別
  • psexec
  • dhclient命令,hpe?3par命令行查看狀況腳本
  • hp存儲默認管理口地址,HP3par 多路徑存儲磁盤使用方法
  • hp3par命令行手冊,3par命令集
  • 存儲器芯片的地址范圍,存儲器芯片類別有哪些?
  • 在pc機中各類存儲器,1.14各類存儲器芯片
  • 存儲芯片漲價最新消息,存儲器芯片
  • Windows/Linux性能監控軟件>csv文件,方便生成圖表
  • sqlserver nvarchar,【SQL開發實戰技巧】系列(四十五):Oracle12C常用新特性?VARCHAR2/NVARCHAR2類型最大長度由40
  • arcgis怎么導入地圖,Arcgis路網導入3dmax批量改成道路面
  • 定義animal父類,定義一個父類Animal eat方法 , 定義兩個子類 Dog 特有方法keepHome , Cat 特有方法 catchMouse ;并
  • 手機連接兩個藍牙方法,打開藍牙的設置
  • iconfont圖標免費嗎,關于阿里矢量圖標彩色icon使用
  • ps制作賽博朋克風格,如何用ps做出賽博朋克的風格?
  • ue4綠幕實時導入場景,如何在UE4中制作賽博朋克LED效果
  • 產品經理有哪些培訓課程,2023年全國NPDP產品經理國際認證火熱招生啦
  • B端產品需要什么能力,NPDP認證|B端產品經理是如何做競品調研的?
  • 超級工具,Supershell 一款牛叉閃閃的工具
  • buffer在c語言中是什么意思,QBuffer 用法理解