从昨天折腾到今天。再折腾下去我都要上主楼了 

大致和灰度图均衡是一样的,主要是不能像平滑什么的直接对R,G,B三个分量进行。这样出来的图像时没法看的。因此我们要对亮度进行均衡。而HSI彩色空间中的分量I代表图像的亮度,和图像的彩色信息无关,所以它是我们perfect的折腾对象。

一、首先,就是把图像从RGB空间转换到HSI空间。原理我就很懒的截图了:

(引自《数字图像处理第三版》(中文版)P280)
实现代码如下:
 void RGBtoHSI(float r,float g,float b,float *h,float *s,float *i)
{
float pi = 3.1415926;
float temp = sqrt((r-g)*(r-g)+(r-b)*(g-b));
temp = temp > ?temp:0.01;
if(b<=g)
*h = acos(((r-g+r-b)/2.0)/temp);
else
*h = *pi - acos(((r-g+r-b)/2.0)/temp);
temp = r+g+b>?r+g+b:0.01;
*s = 1.0-(3.0/temp)*min(r,g,b);
*i = (r+g+b)/3.0;
}

二、当然在进行直方图均衡以后我们还要把HSI转换回RGB,要不然我不知道怎么把它画出来。原理还是截图如下:

代码如下:

 void HSItoRGB(float h,float s,float i,float *r,float *g,float *b)
{
float pi = 3.1415926;
float otz =*pi / ;
if(h >= && h < otz)
{
*b = i*(1.0-s);
*r = i*(1.0+(s*cos(h))/(cos(pi/3.0-h)));
*g = 3.0*i-(*b+*r);
}
else if(h >= otz && h < * otz)
{
*r = i*(-s);
*g = i*(+(s*cos(h-otz))/(cos(pi -h)));
*b = *i-(*g+*r);
}
else
{
*g = i*(-s);
*b = i*(+(s*cos(h-otz*))/(cos(*pi/-h)));
*r = *i-(*g+*b);
}
}

第四行定义的otz这个变量就代表2pi/3,即120度,其实有了变量pi完全可以把它省略掉的。

最主要的注意就是除法中除数不能为零,所以第5行和第10行对于即将作为除数的temp都有个判断,其他的照着公式打就可了。头文件里要包含#include "cmath"。

三、最后对分量I进行直方图均衡,基本和对灰度图像进行直方图均衡时一样的步骤,然后再调用上面的HSItoRGB()函数把图像转回到RGB空间画出来就好了。最最最最最最最重要的一天(这个bug我调了很久)就是从HSI转回到RGB空间的时候分量R,G,B的值有可能超过255,一定要修改成255,见下面代码的73~75行!要不出来的图像会吓死你。

代码如下:

 void MainWindow::on_action_color_zhifang_triggered()
{
width = image_png.width();
height = image_png.height();
grayImg = QImage(width,height,QImage::Format_ARGB32); //存放HSI空间分量的结构体
typedef struct HSI{
float h;
float s;
float i;
}hsi; //申请一个二维结构体数组,存放每个像素转换到HSI空间后三分量的值
hsi **p = new hsi*[height];
for(int i = ;i < height;i++)
p[i] = new hsi[height]; //遍历图像,调用函数RGBtoHSI()转换到HSI空间
float max = ;
for(int i = ;i < width;i++)
{
for(int j = ;j < height;j ++)
{
QRgb rgb = image_png.pixel(i,j);
RGBtoHSI(qRed(rgb),qGreen(rgb),qBlue(rgb),&p[i][j].h,&p[i][j].s,&p[i][j].i);
max = max > p[i][j].i?max:p[i][j].i;
}
}
//qDebug()<<max; int n = (int)(max+0.5);
//对分量I进行直方图均衡
int *II = new int[n+];
float *IIPro = new float[n+];
float *IITemp = new float[n+];
float *IIJun = new float[n+]; for(int i = ;i <= n;i++)
II[i] = ; //计算频率,即nk
for(int i = ;i < width;i++)
{
for(int j = ;j < height;j ++)
{
II[(int)(p[i][j].i+0.5)]++;
}
} //计算每个数量级出现的概率
for(int i = ;i <= n;i++)
{
IIPro[i] = (II[i]*1.0)/(width*height);
} //概率累加并计算均值
IITemp[] = IIPro[];
for(int i = ;i <= n;i++)
{
IITemp[i] = IITemp[i-]+IIPro[i]; IIJun[i]= n*IITemp[i];
}
for(int i=;i<width;i++)
{ for(int j=;j<height;j++)
{
p[i][j].i = IIJun[(int)(p[i][j].i+0.5)];
float r,g,b;
HSItoRGB(p[i][j].h,p[i][j].s,p[i][j].i,&r,&g,&b);
r = r > ?:(int)(r+0.5);
g = g > ?:(int)(g+0.5);
b = b > ?:(int)(b+0.5);
grayImg.setPixel(i,j,qRgb(r,g,b));
}
} update();
}

实现的效果如下图所示,左边是原图,右边是亮度均衡后的图像:

转载请注明出处:BY DEMONEDGE

QT 实现彩色图亮度均衡,RGB和HSI空间互相转换的更多相关文章

  1. 为什么使彩色图变灰RGB的权重会固定(R:0.299 G:0.587 B:0.114)?

    人眼对绿色的敏感度最高,对红色的敏感度次之,对蓝色的敏感度最低,因此使用不同的权重将得到比较合理的灰度图像.根据实验和理论推导得出以下数值 R: 0.299. G:  0.587. B: 0.114.

  2. Qt生成灰度图(转载)

    Qt生成灰度图(转载)   项目中用到大量基础图像处理知识,其中灰度图的生成是很重要的一环. 先补充一些基础知识: ------------------------------------------ ...

  3. OpenNI1.5获取华硕XtionProLive深度图和彩色图并用OpenCV显示

    华硕XtionPro类似Kinect,都是体感摄像机,可捕捉深度图和彩色图. 具体參数见:http://www.asus.com.cn/Multimedia/Xtion_PRO_LIVE/specif ...

  4. OpenNI2获取华硕XtionProLive深度图和彩色图并用OpenCV显示

    使用OpenNI2打开XtionProLive时有个问题,彩色图分辨率不管怎样设置始终是320*240,深度图倒是能够设成640*480,而OpenNI1.x是能够获取640*480的彩色图的. 彩色 ...

  5. Android-将RGB彩色图转换为灰度图

    package com.example.yanlei.wifi; import android.graphics.Bitmap; import android.graphics.BitmapFacto ...

  6. Inkscape svg彩色图转灰度图

    操作: Ctrl+A 全选所有对象, 然后使用滤镜渲染成灰度图, 至于这个RGB比值, 看个人需求, 标准情况下rgb2gray是0.299 * R + 0.587 * G + 0.114 * B 原 ...

  7. Color Models (RGB, CMY, HSI)

    目录 概 定义 RGB CMY CMYK HSI 相互的转换 RGB <=> CMY CMY <=> CMYK CMY > CMYK CMYK > CMY RGB ...

  8. 基于RGB与HSI颜色模型的图像提取法

    现实中我们要处理的往往是RGB彩色图像.对其主要通过HSI转换.分量色差等技术来提出目标. RGB分量灰度化: RGB可以分为R.G.B三分量.当R=G=B即为灰度图像,很多时候为了方便,会直接利用某 ...

  9. Qt 串口通信之使用16进制发送数据的转换方式

    Qt 串口通信之使用16进制发送数据的转换方式 一 概述 有时候在做上位机串口通讯时,经常需要将字符串转成16进制的形式作为发送,借此分析记录一下. 二 需求分析 //假设需要转换的字符:如下 QSt ...

随机推荐

  1. Netsharp FAQ

    1.启动服务器时候不能监听端口,出现如下错误: 回答: 这种问题应该是在win7环境下才有,是没有权限,要以管理员身份运行Netsharp.Elephant.Q.exe. 2.启动服务器的时候,服务端 ...

  2. printf的一个常用技巧

    acm 的题目经常要求输出最后面一位不能有空格: 用if语句显得代码难看: 实现如下: int a[5]={1,2,3,4,5}; for(int i=0;i<=4;i++) printf(&q ...

  3. UIFontFamily

    Family: Hiragino Kaku Gothic ProN W3     Font: HiraKakuProN-W3 Family: Courier     Font: Courier     ...

  4. 使用NPOI和线程池快速加载EXCEL数据

    private void FilterData() { List<Task> tasks = new List<Task>(); IWorkbook workbook = Cs ...

  5. 虚拟目录里面的webconfig不继承网站的设置

    必須在上一层虚拟目录(如根目录,上级网站)所在的Web.config加上 如:<location path="." allowOverride="false&quo ...

  6. JavaScript之数据类型讲解

    JavaScript中有5种简单数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number和String.还有1种复杂数据类型——Object,Object本质上是由一 ...

  7. 【补解体报告】topcoder 634 DIV 2

    A:应该是道语文题,注意边界就好: B:开始考虑的太复杂,没能够完全提取题目的思维. 但还是A了!我愚蠢的做法:二分答案加暴力枚举, 枚举的时候是完全模拟的,比如每次取得时候都是从大到小的去取,最后统 ...

  8. 浅谈MySQL索引背后的数据结构及算法【转】

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  9. hdu 2389(最大匹配bfs版)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2389 思路:纯裸的一个最大匹配题,不过悲摧的是以前一直用的dfs版一直过不了,TLE无数次啊,然后改成 ...

  10. MongoDB (八) MongoDB 文档操作

    一. MongoDB 插入文档 insert() 方法 要插入数据到 MongoDB 集合,需要使用 MongoDB 的  insert() 或 save() 方法. 语法 insert() 命令的基 ...