项目中用到大量基础图像处理知识,其中灰度图的生成是很重要的一环。

先补充一些基础知识:

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

一:灰度图

灰度图就是黑白图,整幅图片只有不同程度的黑白两色。灰度也可认为是亮度,简单的说就是色彩的深浅程度 !

1:如果我们用八位来存储灰度图。则共有256种组合。那相当于:我们把从:纯黑 到 纯白 之间区分成了256种灰度。从而对应256种灰度值! 而如果用一个数字来表示的话:则0-255每个数字对应一种灰度!

2:灰度就是没有色彩,它的RGB色彩分量全部相等。 比如 rgb(20,20,20)。  既然这样:我们完全可以用rgb中的某一个分量的值 来代替这个实际的灰度值! 比如上边这个例子:我们完全可以用20来代替这个灰度! 这是一个一一映射关系!

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

二:色彩表

色彩表就是表示当前所有颜色的一张表。 而我们知道任何一种颜色都可以用rgb值来表示。如此我们完全可以设计一张表,里边每个元素都是一个rgb值,从而将所有的颜色都用rgb值表示出来!

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

三:颜色索引模式

在一张图片的每个像素中可以直接存放其rgb值!当然:我们也可以存放一个索引值,通过这个索引值去其对应的颜色表中去查找对应的颜色的rgb值来进行绘制。这种像素中存放索引值而不是实际rgb值的模式在Qt中有:QImage::Format_Indexed8,亦即:用8位来存放一个索引值。

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

四:灰度索引图:

对于8阶灰度图而言:由于其一共有256种灰度,所以我们可以设计一个颜色表:里边存放256个rgb值!每个rgb值的三个分量都是相等的。这样:这张表就可以用来表示所有的灰度!

灰度索引图中存放的是各个整数索引值,这些图片数据本身是无法显示的,因为其没有实际的rgb值。当实际构图时:是用该索引值在上边创建的颜色表中进行查找,找到对应的灰度rgb值,而后才能进行实际的绘图等操作。

有了上两步基础,问题的关键就在于:这个灰度索引值是如何获得的?

==================================================================================================================

有了上述基础知识,下一步可以来看一下如何从彩色图转为灰度图了。

一:整体流程:

1:依据某一个算法:将rgb32彩色图像的每个像素中的rgb值转为一个整数灰度值。

2:用这个计算获得的值来替代原图中的每个rgb。

这样就可以将一张彩色图转为灰度图了。

但是这个过程中存在以下问题:

1:如何从彩色图原本的rgb值计算出灰度值?

2:因为每个像素的rgb都被灰度值取代,其都是一样的,这完全可以用一个灰度值取代,而不是用三个。用三个有点浪费空间。

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

对于问题1:灰度值的计算方法有以下几种:

1.浮点算法:Gray=R*0.3+G*0.59+B*0.11

2.整数方法:Gray=(R*30+G*59++B*11)/100

3.移位方法:Gray =(R*28+G*151+B*77)>>8;

4.平均值法:Gray=(R+G+B)/3;

5.仅取绿色:Gray=G;

而各种方法之间的区别在于:精确度! 亦即:得到的灰度图的效果不同!浮点数运算得到的效果最好,而仅仅取绿色得到的效果最差。至于取哪一种,则取决于实际需要!

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

对于问题2:我们可以每个像素中只存唯一一个灰度值,而后设计一个色彩表,通过这个灰度值去对应查找其真实的颜色。那这样就可以                 用到上边所的灰度索引图了。亦即:此时图中存放的不是真实的rgb值,而是一个灰度所以值;而后设计一张其对应的颜色      表。这样二者便可以完全代表整张灰度图了。而且二者加起来的空间也比非索引模式要小的多,而且查找速度会更快。

所以:最好是将灰度图用索引模式进行存储,这在Qt中是指定QImage格式为Index8实现。亦即:有8位索引,可以指定256种灰度值。

那么:我们从彩色图转为灰度索引图的整体流程为:

(以rgb32转为index8为例)

1:首先我们要创建一张空的index8图像。

2:依据某一个算法:将rgb32彩色图像的每个像素中的rgb值转为一个整数值,存储在index8灰度图的每个像素中。

3:构建颜色表。

4:依据存储在index图像中的整数值,去灰度表中查找对应的灰度来进行实际的构图!

==================================================================================================================

OK,现在方法有了,下边我们可以来实现了。

1:最简单的方法:

  1. for(int i =0;i<width;i++)
  2. {
  3. for(int j=0;j<height;j++)
  4. {
  5. QRgb pixel=iImage->pixel(i,j);
  6. int r=qRed(pixel);
  7. int g=qGreen(pixel);
  8. int b=qBlue(pixel);
  9. iGray->setPixel(i,j,qGray(r,g,b));
  10. }
  11. }

亦即:先用 pixel()获取每个像素点的QRgb值。而后分别用qRed(),qGreen(),qBlue()来获取rgb分量的值。而后进行上述灰度值的计算。之后再重新赋予给该像素点。

但是实际运行一下你会发现:对于600*800大小的图像:这个函数要运行30s+,这显然是不能容忍的。

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

上边这个方法很简单直接,但是效率上太失败,所以我们需要来优化效率,主要从以下两个方面实现:

1:要用pixel() ,qRed(),qGreen(),qBlue()来遍历获取每个像素的rgb分量。其函数实现时:肯定是一个查找过程,尤其是依据像素位置来获得rgb值的函数pixel()。每次都一个完整的查找,这显然效率较为低下,尤其是不断的大量查找! 由于数据都是连续存放在内存中的,我们完全可以通过移动指针的方式来获取rgb分量。每次只移动一个指针位置就可以了。这种移动指针的方式显然比全查找要快!

这块代码实现上:其是直接来取用green绿色分量值 来作为gray索引值!

其比上一个方法的优化之处在于:它没有使用系统函数,而是使用移动指针的方式来取得rgb分量。它把所有灰度索引值存放到index8灰度图中。最后创建了8阶灰度图的颜色表并赋予给该灰度图。这样:系统会自动(不需要我们手动去查找)依据存储在图像中的灰度索引值去 颜色表中查找对应灰度的rgb值来进行绘制!

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

2:计算灰度索引值的函数qGray(),按照Qt文档上所说:其计算过程为:(r*11+g*16+5*5)/32 .乘除法是一个很大的计算量,最好用移位操作来进行取代!

(这就牵扯一个问题:原本我以为:乘除法在寄存器中就算转为移位操作的,所以乘除法和移位操作在效率上应该没什么区别。但是实际不是这样的,因为:如果你使用乘除法,则其在运行时:转化成的乘法指令本身会消耗很多cpu周期,所以这无形中已经降低了效率!所以来说:在做高性能计算时:最好用移位操作来取代乘除法)

============================================================================================

知道如何优化后,我们看下在Qt中如何实现,这个在网上我找到了一个方法,摘录如下

  1. QImage colourImg("colourImage.bmp");
  2. QSize colourImgSize = colourImg.size();
  3. int width = colourImgSize.rwidth();
  4. int height = colourImgSize.rheight();
  5. unsigned char *colourImgDataPtr = colourImg.bits();
  6. QImage grayImg(colourImgSize, QImage::Format_Indexed8);
  7. unsigned char *grayImgDataPtr = grayImg.bits();
  8. //下边这个for循环是直接取用green绿色分量值 来作为gray索引值
  9. for(int i = 0; i < height; i++)
  10. {
  11. for(int j = 0; j < width; j++)
  12. {
  13. *grayImgDataPtr = *(colourImgDataPtr + 1);      colourImgDataPtr += 4;          grayImgDataPtr++;
  14. }
  15. }
  16. QVector<QRgb> grayColourTable;
  17. unsigned int rgb = 0;
  18. for(int i = 0; i < 256; i++)
  19. {
  20. grayColourTable.append(rgb);
  21. rgb += 0x00010101;
  22. }
  23. grayImg.setColourTable(rayColourTable);
  24. graImg.save("grayImage.bmp", "bmp");

这块代码实现上:其是直接来取用green绿色分量值 来作为gray索引值!

其比上一个方法的优化之处在于:它没有使用系统函数,而是使用移动指针的方式来取得rgb分量。它把所有灰度索引值存放到index8灰度图中。最后创建了8阶灰度图的颜色表并赋予给该灰度图。这样:系统会自动(不需要我们手动去查找)依据存储在图像中的灰度索引值去 颜色表中查找对应灰度的rgb值来进行绘制!

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

在上述方法的基础上,我们在使用时:需要注意的是效果能不能达到需求,从而可能要用精确度更高的灰度索引值计算方法。那这就牵扯大量运算,此时记得要用移位操作 来取代 乘除法运算

  1. QBYTE RGBtoGRAY(QBYTE r, QBYTE g, QBYTE b)
  2. {
  3. return (QBYTE)((((QUINT32)((r << 5) + (r << 2) + (r << 1)))+ (QUINT32)((g << 6) + (g << 3) + (g << 1) + g)
  4. + (QUINT32)((b << 4) - b)) >> 7);
  5. }

这个是网上找到的最优化的实时计算灰度索引值算法。没有用到乘除法运算,转而使用大量移位操作。

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

暂且总结到这里,上述代码都实际测试过,没有问题。

【Qt开发】QImage设置为8-bit灰度图的更多相关文章

  1. 【Qt开发】设置Qt应用程序图标

    [Qt开发]设置Qt应用程序图标 标签:[Qt开发] 首先,准备一个图标,例如:zx.ico,并新建一个文本文档,在里面添加一行: IDI_ICON1 ICON DISCARDABLE"zx ...

  2. Eclipse+Qt开发环境设置(Linux和Win)

    文章摘要: Windows,Linux平台下安装使用Eclipse + QT4.4.3开发环境 Windows,Linux新建project时的配置(不使用QT预置项目类型,而是手工配置) 使用Ecl ...

  3. 【Qt开发】如何将内存图像数据封装成QImage V1

    如何将内存图像数据封装成QImage 当采用Qt开发相机数据采集软件时,势必会遇到采集内存图像并进行处理(如缩放.旋转)操作.如果能够将内存图像数据封装成QImage,则可以利用QImage强大的图像 ...

  4. 【Qt开发】将内存图像数据封装成QImage V2

    如何将内存图像数据封装成QImage 当采用Qt开发相机数据采集软件时,势必会遇到采集内存图像并进行处理(如缩放.旋转)操作.如果能够将内存图像数据封装成QImage,则可以利用QImage强大的图像 ...

  5. Qt 如何使用 QImage 设置指定的颜色为透明色?

    Qt 如何使用 QImage 设置指定的颜色为透明色? 需求背景:使用华大身份证读卡器模块读取身份证信息,通过模块读取的图片为 *.BMP 格式,无透明色,故绘制到身份证上无法美观的显示. 通过查询身 ...

  6. 【Linux开发】【Qt开发】配置tslibs触摸屏库环境设置调试对应的设备挂载点

    [Linux开发][Qt开发]配置tslibs触摸屏库环境设置调试对应的设备挂载点 标签(空格分隔): [Linux开发] [Qt开发] 比如: cat /dev/input/mice cat /de ...

  7. Qt开发的应用记录读取用户习惯设置的方法

    Qt开发的应用记录读取用户习惯设置的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/w ...

  8. 【Qt开发】QSplitter的使用和设置

     Qt库版本:5.2.1     Qt Creator版本:3.0.1 1 QSplitter的用途 QSplitter使得用户可以通过拖动子窗口之间的边界来控制它们的大小,例如 图1 窗口拆分示意图 ...

  9. QImage Color Convert to Gray 转为灰度图

    在Qt中,我们有时需要把QImage类的彩色图片转为灰度图,一开始我想的是用QImage的成员函数convertToFormat(),但是试了好多参数,返现转化的图片都有问题,不是我们想要的灰度图,如 ...

随机推荐

  1. 【C#-算法】根据生日自动计算年龄_DataTime 的 DateDiff 方法

    dateTimePicker1.Value出生日期控件的值 long BirthDay = DateAndTime.DateDiff(DateInterval.Year, dateTimePicker ...

  2. Python 模块Ⅲ

    globals() 和 locals() 函数 根据调用地方的不同,globals() 和 locals() 函数可被用来返回全局和局部命名空间里的名字. 如果在函数内部调用 locals(),返回的 ...

  3. linux7buffer和cache

    现象:作为hdfs集群的主节点,越来越卡 排查:CPU,mem CPU正常,检查内存情况,发现如下 如上截图:发现程序可用内存为91G,但是部分swap分区被占用.于是引出如下思考,free -h这条 ...

  4. Nowcoder Playing Games ( FWT 优化 DP && 博弈论 && 线性基)

    题目链接 题意 : 给出 N 个数.然后问你最多取出多少石子使得在 NIM 博弈中.后手必胜 分析 :  Nim 博弈模型,后手必胜当且仅当各个堆的石子的数目的异或和为 0 转化一下.变成最少取多少石 ...

  5. windows下安装geopandas

    在linux下没任何问题,直接 pipenv install geopandas, 各种依赖库该编译的编译,该依赖的依赖. win下pyproj4编译不过,而且gdal库什么的也都是问题,建议全部从h ...

  6. POJ 1466 大学谈恋爱 二分匹配变形 最大独立集

    Girls and Boys Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 11694   Accepted: 5230 D ...

  7. Selenium 对元素的判断(expected_conditions)(转载)

    我们在用webdriver去操作元素时,先要判断这个元素是否存在,存在才去操作,否则就会报错. selenium的expected_conditions模块提供了一些判断方法 场景 Expected ...

  8. C#程序模拟登录批量获取各种邮件内容信息

    一般来说,如果现实中你有这样一种需求“假如你是褥羊毛的羊毛党,你某日发现了一个app有一个活动,通过邮箱注册账号激活可以领5元红包,而恰恰你手上又有一批邮箱可用,那么批量获取邮箱中的激活链接去激活则是 ...

  9. 使用 vuetron 调试 mpvue 项目

    简介 由于小程序开发工具的封闭,我们无法通过安装 chrome 插件来方便地使用 vue-devtools 调试我们的 mpvue 项目.vuetron 是一个 vue.js 的项目调试工具, 同时支 ...

  10. 定时刷新指定div层

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...