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

大致和灰度图均衡是一样的,主要是不能像平滑什么的直接对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. C/C++求职宝典21个重点笔记

    转:http://blog.csdn.net/lanxuezaipiao/article/details/41557307 char c = '\72'; 中的\72代表一个字符,72是八进制数,代表 ...

  2. 【转载】Web应用工作原理

    问题描述:           Web应用工作原理   问题解决:          参考资料:http://blog.csdn.net/lcore/article/details/8964642   ...

  3. 编写单例的 dojo class

    define([ "dojo/_base/declare" ],function( declare ){ var TimeChartService = declare(" ...

  4. Sqli-labs less 45

    Less-45 同样的,45关与43关的payload是一样的,只不过45关依旧没有报错信息. 登录 username:admin Password:c');create table less45 l ...

  5. 对于Linux平台下C语言开发中__sync_函数的认识

      reference:http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html#Atomic-Builtins A built ...

  6. Java 8怎么了:局部套用vs闭包

    [编者按]本文作者为专注于自然语言处理多年的 Pierre-Yves Saumont,Pierre-Yves 著有30多本主讲 Java 软件开发的书籍,自2008开始供职于 Alcatel-Luce ...

  7. CF444C DZY Loves Colors

    考试完之后打的第一场CF,异常惨烈呀,又只做出了一题了.A题呆滞的看了很久,领悟到了出题者的暗示,应该就是两个点的时候最大吧,不然的话这题肯定特别难敲,YY一发交上去然后就过了.然后就在不停地YY B ...

  8. POJ 3982 序列(JAVA,简单,大数)

    题目 //在主类中 main 方法必须是 public static void 的,在 main 中调用非static类时会有警告信息, //可以先建立对象,然后通过对象调用方法: import ja ...

  9. GCD初步认识

    //(1)用异步函数往并发队列中添加任务, //总结:同时开启三个子线程 - (void)test1 { //1.获得全局的并发队列 dispatch_queue_t queue = dispatch ...

  10. C# 语音识别(文字to语音、语音to文字)

    最近打算研究一下语音识别,但是发现网上很少有C#的完整代码,就把自己的学习心得放上来,和大家分享一下. 下载API: 1)SpeechSDK51.exe                   (67.0 ...