zoukankan      html  css  js  c++  java
  • QT 实现彩色图亮度均衡,RGB和HSI空间互相转换

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

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

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

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

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

    代码如下:

     1 void HSItoRGB(float h,float s,float i,float *r,float *g,float *b)
     2 {
     3     float pi = 3.1415926;
     4     float otz =2*pi / 3;
     5     if(h >=0 && h < otz)
     6     {
     7         *b = i*(1.0-s);
     8         *r = i*(1.0+(s*cos(h))/(cos(pi/3.0-h)));
     9         *g = 3.0*i-(*b+*r);
    10     }
    11     else if(h >= otz && h < 2 * otz)
    12     {
    13         *r = i*(1-s);
    14         *g = i*(1+(s*cos(h-otz))/(cos(pi -h)));
    15         *b = 3*i-(*g+*r);
    16     }
    17     else
    18     {
    19         *g = i*(1-s);
    20         *b = i*(1+(s*cos(h-otz*2))/(cos(5*pi/6-h)));
    21         *r = 3*i-(*g+*b);
    22     }
    23 }

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

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

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

    代码如下:

     1 void MainWindow::on_action_color_zhifang_triggered()
     2 {
     3     width = image_png.width();
     4     height = image_png.height();
     5     grayImg = QImage(width,height,QImage::Format_ARGB32);
     6 
     7     //存放HSI空间分量的结构体
     8     typedef struct HSI{
     9         float h;
    10         float s;
    11         float i;
    12     }hsi;
    13 
    14     //申请一个二维结构体数组,存放每个像素转换到HSI空间后三分量的值
    15     hsi **p = new hsi*[height];
    16     for(int i = 0;i < height;i++)
    17         p[i] = new hsi[height];
    18 
    19     //遍历图像,调用函数RGBtoHSI()转换到HSI空间
    20     float max = 0;
    21     for(int i = 0;i < width;i++)
    22     {
    23         for(int j = 0;j < height;j ++)
    24         {
    25             QRgb rgb = image_png.pixel(i,j);
    26             RGBtoHSI(qRed(rgb),qGreen(rgb),qBlue(rgb),&p[i][j].h,&p[i][j].s,&p[i][j].i);
    27             max = max > p[i][j].i?max:p[i][j].i;
    28         }
    29     }
    30     //qDebug()<<max;
    31 
    32     int n = (int)(max+0.5);
    33     //对分量I进行直方图均衡
    34     int *II = new int[n+1];
    35     float *IIPro = new float[n+1];
    36     float *IITemp = new float[n+1];
    37     float *IIJun = new float[n+1];
    38 
    39     for(int i = 0;i <= n;i++)
    40         II[i] = 0;
    41 
    42     //计算频率,即nk
    43     for(int i = 0;i < width;i++)
    44     {
    45         for(int j = 0;j < height;j ++)
    46         {
    47             II[(int)(p[i][j].i+0.5)]++;
    48         }
    49     }
    50 
    51     //计算每个数量级出现的概率
    52     for(int i = 0;i <= n;i++)
    53     {
    54         IIPro[i] = (II[i]*1.0)/(width*height);
    55     }
    56 
    57     //概率累加并计算均值
    58     IITemp[0] = IIPro[0];
    59     for(int i = 1;i <= n;i++)
    60     {
    61         IITemp[i] = IITemp[i-1]+IIPro[i];
    62 
    63         IIJun[i]= n*IITemp[i];
    64     }
    65     for(int i=0;i<width;i++)
    66     {
    67 
    68         for(int j=0;j<height;j++)
    69         {
    70             p[i][j].i = IIJun[(int)(p[i][j].i+0.5)];
    71             float r,g,b;
    72             HSItoRGB(p[i][j].h,p[i][j].s,p[i][j].i,&r,&g,&b);
    73             r = r > 255?255:(int)(r+0.5);
    74             g = g > 255?255:(int)(g+0.5);
    75             b = b > 255?255:(int)(b+0.5);
    76             grayImg.setPixel(i,j,qRgb(r,g,b));
    77          }
    78      }
    79 
    80     update();
    81 }

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

    转载请注明出处:BY DEMONEDGE

  • 相关阅读:
    14_最长公共前缀_字符串_简单
    5. 最长回文子串_字符串_中等
    187. 重复的DNA序列_字符串_中等
    lr_bn_batchsize_deformable convolution_Hard negative mining
    彻底搞懂HTTPs的加密原理
    20. 有效的括号_字符串_简单
    13_罗马数字转整数_字符串_简单
    202_快乐数_数组_简答
    组件
    World
  • 原文地址:https://www.cnblogs.com/sunshineatnoon/p/3700427.html
Copyright © 2011-2022 走看看