文章转载自:

https://blog.51cto.com/tracey2076/539690

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

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

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

如果不是整数倍,则根据公式: 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(); 图像每行字节数,Qt会自动根据图像格式对齐图像数据,返回值一定是4的整数倍。

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

QImage::Format_RGB888,存入格式为R, G, B 对应 0,1,2

QImage::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中将是补齐数据的数组,由此构造的图像不会有任何问题。

好了,终于总结完了,有很多小的问题,我不想写了,应该够用了,如果有具体其他问题,大家再仔细想想,肯定能解决的,哈哈
-----------------------------------
©著作权归作者所有:来自51CTO博客作者tracey2076的原创作品,请联系作者获取转载授权,否则将追究法律责任
QImage 图像格式小结
https://blog.51cto.com/tracey2076/539690

-----------------------------------

附录

QImage image;
image.load(path);
if (image.isNull())
{return false;
}qDebug() << image.format();int bytePerLine0 = image.bytesPerLine();//Qt会自动根据图像格式对齐图像数据,返回值一定是4的整数倍
int bytePerLine1 = (w * bitcount + 31) / 32 * 4; //四字节对齐计算之后的单行字节数
int bytePerLine2 = int((w * bitcount / 8 + 3) / 4) * 4;QImage img(pBuf, width, height, QImage::Format_Indexed8); //浅拷贝
QVector<QRgb> vtColorTable;
//Set the color table (used to translate colour indexes to qRgb values)
if (vtColorTable.empty())
{for (int k = 0; k < 256; ++k){vtColorTable.push_back(qRgb(k, k, k));}
}img.setColorTable(vtColorTable);

enum QImage::Format
QImage::Format_Invalid 图像无效
QImage::Format_Mono 存储使用1位每像素的图像,字节填充最重要位第一
QImage::Format_MonoLSB 存储使用1位每像素的图像,字节填充不显著位第一
QImage::Format_Indexed8 图像存储使用8位指标转化成Colormap及需要设定一张颜色表QVector<QRgb>

QImage::Format_Grayscale8 图像是使用一个8位灰度格式存储,不需要颜色表
QImage::Format_RGB32 存储使用32位RGB格式的图像(0xffrrggbb)
QImage::Format_ARGB32 存储使用32为ARGB格式的图像(0xaarrggbb)
QImage::Format_ARGB32_Premultiplied 图像存储使用一个自左乘32位ARGB格式
QImage::Format_RGB16 图像存储使用5-6-5 16位RGB格式
QImage::Format_ARGB8565_Premultiplied 图像存储使用一个自左乘24位ARGB格式8-5-6-5
QImage::Format_RGB666 图像存储使用6-6-6 24位RGB格式,未使用的最重要的位总是为零
QImage::Format_ARGB6666_Premultiplied 图像存储使用一个自左乘24位ARGB格式6-6-6-6
QImage::Format_RGB555 图像存储使用16位RGB格式(5-5-5),位置用的最重要的始终为零
QImage::Format_ARGB8555_Premultiplied 图像存储使用一个自左乘24位ARGB格式8-5-5-5
QImage::Format_RGB888 图像存储使用8-8-8 24位RGB格式(0xrrggbb)

QImage::Format_RGB444 图像存储使用16位RGB格式(4-4-4)未使用的位始终为零
QImage::Format_ARGB4444_Premultiplied 图像存储使用一个自左乘16位ARGB格式4-4-4-4
QImage::Format_RGBX8888 图像存储使用32位字节命令RGB(x)格式8-8-8-8
QImage::Format_RGBA8888 存储使用32位字节命令RGBA格式(8-8-8-8)的的图像
QImage::Format_RGBA8888_Premultiplied 图像存储使用一个自左乘32位字节命令RGBA格式8-8-8-8
QImage::Format_BGR30 存储使用32位BGR格式(x-10-10-10)的的图像
QImage::Format_A2BGR30_Premultiplied 图像存储使用32位自左乘abgr格式2-10-10-10
QImage::Format_RGB30 存储使用32位RGB格式(x-10-10-10)的的图像
QImage::Format_A2RGB30_Premultiplied 图像存储使用2-10-10-10 32位自左乘ARGB格式
QImage::Format_Alpha8 该图像是使用一个8位的阿尔法格式存储

QImage 图像格式小结,QImage::Format相关推荐

  1. QImage 图像格式小结 Format_RGB32

    原文链接 嗯,这个QImage的问题研究好久了,有段时间没用,忘了,已经被两次问到了,突然有点解释不清楚,我汗颜,觉得有必要重新总结下了,不然无颜对自己了. 图像的数据是以字节为单位保存的,每一行的字 ...

  2. Qt QImage类详解(QImage类型转换、QImage类函数及QImage像素操作)

    打开Qt帮助文档,会看到有关于QImage的描述如下:The QImage class provides a hardware-independent image representation tha ...

  3. QImage图像格式解读

    enum QImage::Format QImage::Format_Invalid 图像无效 QImage::Format_Mono 存储使用1位每像素的图像,字节填充最重要位第一 QImage:: ...

  4. [视觉实战案例]Qt下BYTE、QImage、HObject、Mat等图像格式的转换和图像显示方法

    文章目录 一.图像格式间相互转换 1.BYTE转QImage.HObject和Mat 2.QImage.HObject和Mat的相互转换 二.图像显示方法 1.QLabel显示QPixmap图像 2. ...

  5. QImage/cv::Mat/HObject的图像格式互相转换,4字节对齐

    QImage/cv::Mat互相转换 QImage ImgChange::cvMat2QImage(const Mat &mat) // Mat 改成 QImage {if (mat.type ...

  6. 【Qt】QImage、QPixmap、QBitmap和QPicture

    简述 Qt 提供了四个用于处理图像数据的类: QImage. QPixmap. QBitmap和QPicture.QImage是为 I/O 设计和优化的, 用于直接像素访问和操作, 而QPixmap是 ...

  7. 【Qt】QImage使用总结

    图像格式转换 由 RGB 格式转换成 BGR 格式 QImage::rgbSwapped() 返回一个QImage,其中所有像素的红色和蓝色组件的值被交换,有效地将RGB图像转换为BGR图像. QIm ...

  8. QT的QImage类的使用

    详细说明 QImage类提供了独立于硬件的图像表示形式,该图像表示形式可以直接访问像素数据,并且可以用作绘制设备. Qt提供了四个用于处理图像数据的类:QImage,QPixmap,QBitmap和Q ...

  9. QT中使用GDAL多线程读取遥感图像到QImage

    GDAL 是一个很强大的可以读取很多格式 的带有GIS信息的栅格型图像.前阵子项目中需要读取遥感图像,并显示到QT界面,由于遥感图像一般很大,所以采取新开一个读图线程的方式来读取,防止界面假死.下面是 ...

最新文章

  1. WPS漏洞利用工具Bully常见命令集合
  2. ytu 1057: 输入两个整数,求他们相除的余数(带参的宏 + 模板函数 练习)
  3. pythonpackage详解_Python详解之包管理:__init__.py
  4. 性能测试报告模板_性能测试新手误区
  5. oracle10g执行insert,oracle 10g 增强审计。表insert 及bind values
  6. MySQL索引和SQL调优手册
  7. Java中的位运算符、移位运算
  8. Hadoop联姻Excel: 微软巩固Office帝国
  9. 不想加班你敢说出来吗?华为员工公开说我不想加班
  10. urllib2的用法
  11. Java获取接口所有实现类的方式
  12. 页面加载速度缓慢时,如何优化?
  13. 特斯拉线圈怎么用_无线快充居然是特斯拉发明的?不愧是发明家
  14. .so 依赖目录 cmake_Android Studio 生成 so 文件
  15. uniapp 拍照 或者 相册 识别身份证信息
  16. 中心极限定理 central limit theorem
  17. JT/T-1078流媒体服务优化升级
  18. Azkaban安装并设置定时任务Schedule以及邮件发送接收
  19. 误差的基本性质与处理matlab实验,基于matlab的误差数据处理实验报告.doc
  20. UCOSIII总结------消息队列(6)

热门文章

  1. Java——Collections
  2. Jupyterlab安装和配置
  3. 深度学习经典论文汇总
  4. java的数据异常_java的各种异常
  5. 如何安装idea社区版
  6. 锁定计算机后如何不黑屏,怎么设置电脑黑屏时间_怎么设置电脑不黑屏
  7. INFLUXDB-influxDB一些查询语法你必须知道
  8. 解决项目Unable to find GatewayFilterFactory with name CacheRequestFilter错误
  9. 家政保洁月嫂保姆家政公司网站源码 dedecms织梦
  10. 降维专题(一):为什么要降维?