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

大致和灰度图均衡是一样的,主要是不能像平滑什么的直接对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. ASP.NET MVC 如何在一个同步方法(非async)方法中等待async方法

    问题 首先,在ASP.NET MVC 环境下对async返回的Task执行Wait()会导致线程死锁.例: public ActionResult Asv2() { //dead lock var t ...

  2. 【BZOJ】【1059】【ZJOI2007】矩阵游戏

    二分图完美匹配/匈牙利算法 如果a[i][j]为黑点,我们就连边 i->j ,然后跑二分图最大匹配,看是否有完美匹配. <_<我们先考虑行变换:对于第 i 行,如果它第 j 位是黑点 ...

  3. java 解决JFrame不能设置背景色的问题 分类: Java Game 2014-08-15 09:48 119人阅读 评论(0) 收藏

    这段时间比较多,于是写一写JAVA的一些IT技术文章.如有JAVA高手请加QQ:314783246,互相讨论. 在Java的GUI设计中,Frame和JFrame两者之间有很大差别,上次刚学时编一个窗 ...

  4. 使用TCP协议的NAT穿透技术

    一直以来,说起NAT穿透,很多人都会被告知使用UDP打孔这个技术,基本上没有人会告诉你如何使用TCP协议去穿透(甚至有的人会直接告诉你TCP协议是无法实现穿透的).但是,众所周知的是,UDP是一个无连 ...

  5. setrendertraget 上下颠倒

    这个问题遇到两次了 之前一次是粒子rendertotexture 没设viewprot的时候是上下颠倒的 设置viewport之后就好了 现在在一个setrendertarget的地方又遇到了 上下颠 ...

  6. string为什么可以写入共享内存

    我今天在想这个vector,map为什么不能写入共享内存,原来是因为new的时候只是new了这个对象在共享内存上,而真正的堆上的内存并没有在共享内存里面的,如果要想vector 可以共享就要重写分配器 ...

  7. sencha Touch 2.4 学习之 XTemplate模板

    XTemplate模板 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  8. UML用例图(转载)

    概述: 为了模拟系统最重要的方面是捕捉到的动态行为.为了阐明位详细信息,动态的行为意味着它运行时/操作系统的行为. 因此,只有静态的行为是不够的模拟系统,而动态的行为,更重要的是比静态行为.在UML模 ...

  9. php随机数怎么获取?一个简单的函数就能生成

    小美女建了一个站,有些页面相似度比较高,想添加一些字段来实现差异化,比如用php随机数生成从10到100之间随机一个数字.其实会php的朋友几十个字符就能实现了,如下代码所示,简单吧?10代表最小值, ...

  10. 测试c语言函数调用性能因素之测试三

    函数调用:即调用函数调用被调用函数,调用函数压栈,被调用函数执行,调用函数出栈,调用函数继续执行的一个看似简单的过程,系统底层却做了大量操作. 操作: 1,               调用函数帧指针 ...