用C++写个函数实现灰度图均衡化以及用C++显示灰度直方图

  https://www.cnblogs.com/skyfsm/p/7767043.html

用C++写个函数实现灰度图均衡化以及用C++显示灰度直方图。

1、灰度图均衡化

直方图均衡化在图像增强方面有着很重要的应用。一些拍摄得到的图片,我们从其直方图可以看出,它的分布是集中于某些灰度区间,这导致人在视觉上感觉这张图的对比度不高。所以,对于这类图像,我们可以通过直方图均衡技术,将图像的灰度分布变得较为均匀,从而使得图像对比度增大,视觉效果更佳。

直方图均衡化的代码实现有以下几个步骤:

  1. 遍历全图,先统计每个灰度级下的像素点个数(为此我们开辟了256大小的数组);
  2. 计算每个灰度级的像素点占总像素的点的比例;
  3. 按照第二步求出的比例重新计算每个灰度级下的新的灰度值,即均衡化;
  4. 依照新的灰度值表遍历更新图像的灰度值。

实现代码:

int gray[256] = { 0 };  //记录每个灰度级别下的像素个数
double gray_prob[256] = { 0 };  //记录灰度分布密度
double gray_distribution[256] = { 0 };  //记录累计密度
int gray_equal[256] = { 0 };  //均衡化后的灰度值

int gray_sum = 0;  //像素总数

Mat equalize_hist(Mat& input)
{
    Mat output = input.clone();
    gray_sum = input.cols * input.rows;

    //统计每个灰度下的像素个数
    for (int i = 0; i < input.rows; i++)
    {
        uchar* p = input.ptr<uchar>(i);
        for (int j = 0; j < input.cols; j++)
        {
            int vaule = p[j];
            gray[vaule]++;
        }
    }

  
    //统计灰度频率
    for (int i = 0; i < 256; i++)
    {
        gray_prob[i] = ((double)gray[i] / gray_sum);
    }

    //计算累计密度
    gray_distribution[0] = gray_prob[0];
    for (int i = 1; i < 256; i++)
    {
        gray_distribution[i] = gray_distribution[i-1] +gray_prob[i];
    }

    //重新计算均衡化后的灰度值,四舍五入。参考公式:(N-1)*T+0.5
    for (int i = 0; i < 256; i++)
    {
        gray_equal[i] = (uchar)(255 * gray_distribution[i] + 0.5);
    }


    //直方图均衡化,更新原图每个点的像素值
    for (int i = 0; i < output.rows; i++)
    {
        uchar* p = output.ptr<uchar>(i);
        for (int j = 0; j < output.cols; j++)
        {
            p[j] = gray_equal[p[j]];
        }
    }

    return output;
}

 

2、显示灰度直方图

void show_histogram(Mat& img)
{
    //为计算直方图配置变量  
    //首先是需要计算的图像的通道,就是需要计算图像的哪个通道(bgr空间需要确定计算 b或g货r空间)  
    int channels = 0;
    //然后是配置输出的结果存储的 空间 ,用MatND类型来存储结果  
    MatND dstHist;
    //接下来是直方图的每一个维度的 柱条的数目(就是将数值分组,共有多少组)  
    int histSize[] = { 256 };       //如果这里写成int histSize = 256;   那么下面调用计算直方图的函数的时候,该变量需要写 &histSize  
    //最后是确定每个维度的取值范围,就是横坐标的总数  
    //首先得定义一个变量用来存储 单个维度的 数值的取值范围  
    float midRanges[] = { 0, 256 };
    const float *ranges[] = { midRanges };

    calcHist(&img, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);

    //calcHist  函数调用结束后,dstHist变量中将储存了 直方图的信息  用dstHist的模版函数 at<Type>(i)得到第i个柱条的值  
    //at<Type>(i, j)得到第i个并且第j个柱条的值  

    //开始直观的显示直方图——绘制直方图  
    //首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像  
    Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);
    //因为任何一个图像的某个像素的总个数,都有可能会有很多,会超出所定义的图像的尺寸,针对这种情况,先对个数进行范围的限制  
    //先用 minMaxLoc函数来得到计算直方图后的像素的最大个数  
    double g_dHistMaxValue;
    minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
    //将像素的个数整合到 图像的最大范围内  
    //遍历直方图得到的数据  
    for (int i = 0; i < 256; i++)
    {
        int value = cvRound(dstHist.at<float>(i) * 256 * 0.9 / g_dHistMaxValue);

        line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(255, 255, 255));
    }

    imshow("【原图直方图】", drawImage);
}

几个关键函数的解释:

void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims,
 const int* histSize, const float** ranges, booluniform=true, bool accumulate=false )

计算直方图,统计各灰度的像素个数,其输出为多维矩阵
const Mat* images:
为输入图像的指针。
int nimages:
要计算直方图的图像的个数。此函数可以为多图像求直方图,我们通常情况下都只作用于单一图像,所以通常nimages=1。
const int* channels:
图像的通道,它是一个数组,如果是灰度图像则channels[1]={0};如果是彩色图像则channels[3]={0,1,2};如果是只是求彩色图像第2个通道的直方图,则channels[1]={1};
IuputArray mask:
是一个遮罩图像用于确定哪些点参与计算,实际应用中是个很好的参数,默认情况我们都设置为一个空图像,即:Mat()。
OutArray hist:
计算得到的直方图
int dims:
得到的直方图的维数,灰度图像为1维,彩色图像为3维。
const int* histSize:
直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。
const float** ranges:
这是一个二维数组,用来指出每个区间的范围。后面两个参数都有默认值,uniform参数表明直方图是否等距,最后一个参数与多图像下直方图的显示与存储有关。

void minMaxLoc(InputArray src, double* minVal, double* maxVal=0, Point* minLoc=0,
 Point* maxLoc=0, InputArray mask=noArray())

找出矩阵中最大和最小的值以及他们的坐标
src – Source single-channel array.
单通道数组
minVal – Pointer to the returned minimum value. NULL is used if not required.
指向最小值的指针
maxVal – Pointer to the returned maximum value. NULL is used if not required.
指向最大值的指针
minLoc – Pointer to the returned minimum location (in 2D case). NULL is used if not required.
最小值的二维坐标
maxLoc – Pointer to the returned maximum location (in 2D case). NULL is used if not required.
最大值得二维坐标
mask – Optional mask used to select a sub-array.
掩码

void cvLine( CvArr* img,CvPoint pt1, CvPoint pt2, CvScalar color,int thickness=1,
int line_type=8, int shift=0 );

第一个参数img:要划的线所在的图像;
第二个参数pt1:直线起点
第二个参数pt2:直线终点
第三个参数color:直线的颜色 e.g:Scalor(0,0,255)
第四个参数thickness=1:线条粗细
第五个参数line_type=8, 
   8 (or 0) - 8-connected line(8邻接)连接 线。
   4 - 4-connected line(4邻接)连接线。
   CV_AA - antialiased 线条。
第六个参数:坐标点的小数点位数。

static_cast

用法:static_cast < type-id > ( expression_r_r )
该运算符把expression_r_r转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
把空指针转换成目标类型的空指针。
把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
更详细的:http://blog.sina.com.cn/s/blog_4a84e45b0100f57m.html

参考链接:https://blog.csdn.net/qq_24282081/article/details/73135799

                 https://www.cnblogs.com/skyfsm/p/7767043.html

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值