QImage 图像格式小结
原地址: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 图像格式小结的更多相关文章
- Qt编程之QImage类小结
最近用Qt做图像处理,以下references是需要用到的 references: http://blog.csdn.net/lyc_daniel/article/details/9193881 ht ...
- cv::Mat转换QImage
cvtColor(img, img, CV_BGR2RGB); QImage image((uchar*)img.data,img.cols,img.rows,QImage::Format_RGB88 ...
- cvReleaseImage 释放内存出错
cvReleaseImage是OpenCV中C语言库中的释放图片内存的函数,比如我们加载或者克隆了一幅图片,当不需要这幅图片了时,我们为了避免内存泄露,需要释放这些空间,可以参见我之前的博客OpenC ...
- OpenCV-Python图像转换为PyQt图像的变形及花屏无法正常显示问题研究
☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<PyQt转换显示Python-OpenCV图像实现图形化界面的视频播放>介绍了实现在OpenCV和PyQt之间转换并传递图像实现在P ...
- 【转】OpenCV与CxImage转换(IplImage)、IplImage QImage Mat 格式互转
最近由于在项目中用到了Opencv库,但是为了更好的显示图像还是使用了Cximage库,它可以快捷地存取.显示.转换各种图像.Opencv库用于高级图像处理与识别.为了使Cximage图像与Openc ...
- (转) QImage总结
嗯,这个QImage的问题研究好久了,有段时间没用,忘了,已经被两次问到了,突然有点解释不清楚,我汗颜,觉得有必要重新总结下了,不然无颜对自己了. 图像的数据是以字节为单位保存的,每一行的字节数必须是 ...
- PS与AI快捷键小结
[文档整理系列] PS与AI快捷键小结PS快捷键 填充前景色 alt+del填充背景色 crel+del前景色与背景色互换: x[英文状态] 切换打开的文件:ctrl + tab关闭当前文件: ctr ...
- GDI+编程小结
GDI+(Graphics Device Interface Plus图形设备接口加)是Windows XP和Windows Server 2003操作系统的子系统,也是.NET框架的重要组成部分,负 ...
- QImage的浅拷贝与深拷贝
首先简单说说什么是浅拷贝和深拷贝:浅拷贝就比如像引用类型,而深拷贝就比如值类型,即浅拷贝是共用一块内存的,而深拷贝是复制一份内容. 我们再来看看QImage类的几个构造函数: // 浅拷贝 QI ...
随机推荐
- 写给自己看的Linux运维基础(一) - 系统基础
查看内核版本信息 uname -a 查看发行版本 cat /etc/issue 查看硬件配置 CPU: cat /proc/cpuinfo more /proc/cpuinfo | grep ...
- [ucgui] 彩色条函数
/* 颜色条 */ void ShowColorBar(void) { , y0 = , yStep = , i; int NumColors = LCD_GetDevCap(LCD_DEVCAP_N ...
- 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...
- 2-MSP430按键输入检测
为了写一篇文章做铺垫--提醒着自己,,,,,, P1.0的电平,随着P1.1引脚输入的电平变化而变化 #include "io430.h" void delay(void) { u ...
- crossplatform---Nodejs in Visual Studio Code 07.学习Oracle
1.开始 Node.js:https://nodejs.org OracleDB: https://github.com/oracle/node-oracledb/blob/master/INSTAL ...
- paip.自定义java 泛型类与泛型方法的实现总结
paip.自定义java 泛型类与泛型方法的实现总结 ============泛型方法 public static <atiType,retType> retType reduce ...
- Essential C++中文版——满汉全席之外
满汉全席之外 Stanley B. Lippman 所著的C++ Primer 雄踞书坛历久不衰,堪称C++最佳教科书.但是走过十个年头之后,继1237 页的C++ Primer 第3 版,Lippm ...
- React Ajax
React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取, 当从服务端获取数据库可以将数据存储在 state 中,再用 this.setState 方法重新渲染 ...
- hdu 2844 多重背包coins
http://acm.hdu.edu.cn/showproblem.php?pid=2844 题意: 有n个硬币,知道其价值A1.....An.数量C1...Cn.问在1到m价值之间,最多能组成多少种 ...
- javascript效果:手风琴、轮播图、图片滑动
最近都没有更,就来几个效果充实一下. 都没有进行美化这步. 手风琴: 纯css: <!DOCTYPE html> <html lang="en"> < ...