原地址:http://tracey2076.blog.51cto.com/1623739/539690

嗯,这个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,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  image32 = QImage(width, height, QImage::Format_32);

QImage  image24 = QImage(width, height, QImage::Format_24);

QImage  image8 = QImage(width, height, QImage::Format_8);

image8.setColorTable(colorTable);

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

int  lineNum_32 = 0;     //行数

int  pixelsub_32 = 0;    //像素下标

uchar*    imagebits_32 = image32.bits();         //获取图像首地址,32位图

uchar*    imagebits24 = image24.bits();

uchar*    imagebits8 = image8.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 = imagebits_32[ lineNum_32 + j * 4 + 2];

int g_32 = imagebits_32[ lineNum_32 + j * 4 + 1];

int b_32 = imagebits_32[ lineNum _32 + j * 4];

// int r_24 = imagebits_24[ lineNum_24 + j * 3];        //注意区别32位的图

// int g_24 = imagebits_24[ lineNum_24 + j *3 + 1];

// int b_24 = imagebits_24[ lineNum_24 + j * 3 + 2];

// int gray_8 = imagebits_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 = image32.bytesPerLine();

int  W_24 = image24.bytesPerLine();

int  W_8 = image8.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)

{

imagebits_32 = image32.scanLine(i);

imagebits_24 = image24.scanLine(i);

imagebits_8 = image8.scanLine(i);

for(int j=0; j<width; ++j)

{

int r_32 = imagebits_32[ j * 4 + 2];

int g_32 = imagebits_32[ j * 4 + 1];

int b_32 = imagebits_32[ j * 4];

// int r_24 = imagebits_24[ j * 3];

// int g_24 = imagebits_24[ j *3 + 1];

// int b_24 = imagebits_24[ j * 3 + 2];

// int gray_8 = imagebits_8[ j ];

……

//自己的操作

}

}

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

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

嗯,这个函数就是从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 imageByteArray = QByteArray( (const char*)srcData,  byteCount );

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

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

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

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

QImage 图像格式小结的更多相关文章

  1. Qt编程之QImage类小结

    最近用Qt做图像处理,以下references是需要用到的 references: http://blog.csdn.net/lyc_daniel/article/details/9193881 ht ...

  2. cv::Mat转换QImage

    cvtColor(img, img, CV_BGR2RGB); QImage image((uchar*)img.data,img.cols,img.rows,QImage::Format_RGB88 ...

  3. cvReleaseImage 释放内存出错

    cvReleaseImage是OpenCV中C语言库中的释放图片内存的函数,比如我们加载或者克隆了一幅图片,当不需要这幅图片了时,我们为了避免内存泄露,需要释放这些空间,可以参见我之前的博客OpenC ...

  4. OpenCV-Python图像转换为PyQt图像的变形及花屏无法正常显示问题研究

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<PyQt转换显示Python-OpenCV图像实现图形化界面的视频播放>介绍了实现在OpenCV和PyQt之间转换并传递图像实现在P ...

  5. 【转】OpenCV与CxImage转换(IplImage)、IplImage QImage Mat 格式互转

    最近由于在项目中用到了Opencv库,但是为了更好的显示图像还是使用了Cximage库,它可以快捷地存取.显示.转换各种图像.Opencv库用于高级图像处理与识别.为了使Cximage图像与Openc ...

  6. (转) QImage总结

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

  7. PS与AI快捷键小结

    [文档整理系列] PS与AI快捷键小结PS快捷键 填充前景色 alt+del填充背景色 crel+del前景色与背景色互换: x[英文状态] 切换打开的文件:ctrl + tab关闭当前文件: ctr ...

  8. GDI+编程小结

    GDI+(Graphics Device Interface Plus图形设备接口加)是Windows XP和Windows Server 2003操作系统的子系统,也是.NET框架的重要组成部分,负 ...

  9. QImage的浅拷贝与深拷贝

     首先简单说说什么是浅拷贝和深拷贝:浅拷贝就比如像引用类型,而深拷贝就比如值类型,即浅拷贝是共用一块内存的,而深拷贝是复制一份内容.   我们再来看看QImage类的几个构造函数: // 浅拷贝 QI ...

随机推荐

  1. Failed to initialize the Common Language Runtime

    今天在SQL Server 2008中执行存储过程的时候报以下错误: Msg , Level , State , Procedure usp_QueryRealTimeRoomInfo, Line F ...

  2. Arduino I2C + 三轴加速度计LIS3DH

    LIS3DH是ST公司生产的MEMS三轴加速度计芯片,实现运动传感的功能.主要特性有: 宽工作电压范围:1.71 ~ 3.6V 功耗:低功耗模式2μA:正常工作模式.ODR = 50Hz时功耗11μA ...

  3. mybatis框架demo first

    SqlMapConfig.xml: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE con ...

  4. paip.slap工具与于64位win7与JDBC的性能对比

    paip.slap工具与于64位win7与JDBC的性能对比 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog ...

  5. paip.提升效率--调试--日志系统日志参数含义---python

    paip.提升效率--调试--日志系统日志参数含义---python #同时向控制台和文件输出日志 #日志参数含义 import logging log_format = '%(filename)s ...

  6. Python类

    在类的变量前面加 _ _ 是私有变量,外部不可访问. 需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是 ...

  7. struts2 iterator排序

    因为存入数据库的数据可能不是按照我们想要的方式存进去的.这就导致取出来的时候,不是按照我们想要的方式排序.这时候就要利用struts2的iterator排序功能,按照我们想要的顺序排列. 首先.一个付 ...

  8. Revit API 获取某墙上洞口的尺寸和位置

    [Transaction(TransactionMode.Manual)] [Regeneration(RegenerationOption.Manual)] public class cmd2012 ...

  9. 传递给数据库 'master' 中的日志扫描操作的日志扫描号无效

    错误:连接数据库的时候提示:SQL Server 检测到基于一致性的逻辑 I/O 错误 校验和不正确 C:\Documents and Settings\Administrator>" ...

  10. 【Python排序搜索基本算法】之深度优先搜索、广度优先搜索、拓扑排序、强联通&Kosaraju算法

    Graph Search and Connectivity Generic Graph Search Goals 1. find everything findable 2. don't explor ...