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

大致和灰度图均衡是一样的,主要是不能像平滑什么的直接对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. 【Path Sum】cpp

    题目: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up ...

  2. selenium--下拉列表选择

    html 代码: <select name="ColumnId" id="columnOrd"> <option value="2& ...

  3. 深入理解jQuery中live与bind方法的区别

    本篇文章主要是对jQuery中live与bind方法的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助 注意如果是通过jq添加的层和对象一定要用live(),用其他的都不起作用 ...

  4. Nodejs Express 4.X 中文API 1--- Application篇

    相关阅读: Express 4.X API 翻译[一] --  Application篇 Express4.XApi 翻译[二] --  Request篇 Express4.XApi 翻译[三] -- ...

  5. Ajax HTML, JS

    Ajax Request HTML <script></script>及外部的js文件,都需要 var scriptStrs = response.match(/\<[\ ...

  6. Ckeditor 中一些核心的对象的作用

    1.CKEditor CKEditor对象用于掌管全局,他是一个单例对象,管理着所有实例化了的编辑框. 通过replace方法创建编辑框实例. 2.CKEditor.editor 表示一个编辑框实例, ...

  7. mysql 数据库优化

    提到优化,先要确定出现的问题,是存储引擎选择问题,还是sql语句使用问题(如:索引)亦或者是单一存储服务器对于千万级别的数据力不从心. 解决方法:1.根据不同业务选用不同存储引擎,虽然一般情况下都优先 ...

  8. 自定义TexturePacker插件导出自己的plist文件

    原地址:http://www.cppblog.com/sunicdavy/archive/2014/02/06/205645.html cocos2dx引擎使用plist文件, 一种特殊的xml格式作 ...

  9. Sqli-labs less 17

    Less-17 本关我们可以看到是一个修改密码的过程,利用的是update语句,与在用select时是一样的,我们仅需要将原先的闭合,构造自己的payload. 尝试报错 Username:admin ...

  10. [初级教程]用SecureCRT+Xming轻松远程实现Linux的X DISPLAY

    [初级教程]用SecureCRT+Xming轻松远程实现Linux的X DISPLAY 发布者:sqqdugdu 时间:10-06 阅读数:2117 测试环境:RHEL 6.1,SecureCRT 5 ...