原地址: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. python 列表生成器

    python 列表生成器 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 一个循环 在C语言等其他语言中,for循环一般是这样的 ...

  2. 辐射4 中文武器命名方法, 不用winhex, 直接游戏内操作

    参考资料:https://www.reddit.com/r/fo4/comments/3t354b/tip_you_can_add_text_formatting_italic_underline/h ...

  3. atitit.提升开发效率---动态语言总结

    atitit.提升开发效率---动态语言总结 ruby,python 都不错,就是语法不好, 应用不广泛,文档,工具都非常少,不推荐... php狠不错,就是高级特性不行.. 看来子有.net/jav ...

  4. 两两组合覆盖测试用例设计工具:PICT

    两两组合覆盖测试用例设计工具:PICT 2016-08-31 目录 1 成对测试简介2 PICT使用  2.1 安装 PICT  2.2 使用PICT3 PICT算法  3.1 准备阶段  3.2 产 ...

  5. Leetcode 52 N-Queens II 回溯搜索

    对于N-Queens的每种情况,回答出每种情况的N-Queens的排列数. l,r和c是每种类型的格子是否有棋子. l判断的是这样的对角线的格子                   r判断的是这样的对 ...

  6. javascript坐标:event.x、event.clientX、event.offsetX、event.screenX 用法

    clientX 设置或获取鼠标指针位置相对于窗口客户区域的 x 坐标,其中客户区域不包括窗口自身的控件和滚动条. clientY 设置或获取鼠标指针位置相对于窗口客户区域的 y 坐标,其中客户区域不包 ...

  7. 深入理解.NET程序的原理 谈一谈破解.NET软件的工具和方法

    最近一段时间不忙,闲下来的空闲时间,重读了一下CLR的原理,回味一下有关程序集的的知识,顺便练了一下手,学习致用,破解了若干个.NET平台的软件.以此来反观.NET程序开发中,需要注意的一些问题. 基 ...

  8. RMAN duplciate 准备时,需要检查的target数据库参数内容

    SQL> show parameter audit_file_dest; NAME                                 TYPE        VALUE------ ...

  9. GTD时间管理---非行动性

    一:行动性和非行动有什么区别? 1:非行动性:指的是收集箱中的信息,是先存储后使用,这些信息平时都处于冬眠状态,只是要用到的时候能够找到它就好了.(偏向于处理生活) 2:行动性: 指的是收集箱中的信息 ...

  10. [AYUI]QQ管家源码已经开源

    (0-50元 黑色字体     享受AY 1周的 ayui 技术问答) (50-100元 绿色字体 享受AY 15天的 ayui 技术问答) (100-150元 蓝色字体 享受AY 20天的 ayui ...