关闭

图像处理opencv直方图均值化-学习笔记2

标签: opencv图像处理c++
427人阅读 评论(0) 收藏 举报
分类:

直方图均值化

实验简述

实验要求:
下载一曝光不足和一曝光过度的彩色图片,对彩色图片进行直方图均衡化,并保存和展示。

原理简述

直方图概念

直方图(Histogram)又称质量分布图、柱状图,是一种统计报告图,也是表示资料变化情况的一种主要工具。直方图由一系列高度不等的纵向条纹或线段表示数据分布的情况,一般用横轴表示数据类型,纵轴表示分布情况——–百度百科

图像的直方图是以横坐标为像素值(本实验以[0-255]为范围),纵坐标为像素个数(图像以横坐标值为像素值的个数)。

直方图均值化

直方图均值化直观感受

直方图均值化就是把集中在某个值域的像素按某种方法拉伸到整个值域,获得更美观的视觉。
附上图片更容易说明。

未均值化的直方图
这是一张集中于小像素的直方图。

均值化后
均值化后的直方图。

均值化后,图片就更平和不会出现偏亮或偏暗。
附上图片更容易说明。

均值化前图像
均值化前图像

均值化后图像
这里写图片描述

直方图均值化一种原理说明

通过函数将一个小的范围映射到一个大范围,一种原理就是按如下公式进行映射

h(v)=round((cdf(v)-cdfmin)/(M*N-cdfmin)*(L-1))

cdf(v)为累加函数代表像素值小于等于v的个数。
cdfmin为累加函数。
M*N 分别代表长宽像素,其乘积为整幅图的像素。
round()取整函数。
L为256,L-1像素最大值255。

opencv实现

直方图均值化

1。因为直方图均值化需要单通道图像,所以需用split()函数进行分通道,最后需用 merge(bgr, 3, bgr_res);函数合并通道。
代码如下

Mat img = imread("D:\\\\2.jpg");
    Mat bgr[3];
    split(img, bgr);

2。opencv提供均值化函数,计算的必为单通道的图像。

#include "opencv2/imgproc/imgproc.hpp" //直方图均值化函数头件for (int i = 0;i < 3;i++)
equalizeHist(bgr[i], bgr[i]);

3。注意计算直方图时,计算的必为单通道的图像。

    MatND hist;//直方图
    int channels[] = { 0 };//所传图像通道
    int dims = 1;//直方图维数
    int histSize[] = { 256,256 };//直方图大小256*256的正方形
    float granges[] = { 0, 255 };//直方图搜索像素范围
    const float *ranges[] = { granges };//因为有多维度的直方图所以,要将范围以指针形式传出。比如,如果二维就可以再传个范围
    calcHist(&image, 1, channels, Mat(), hist, dims, histSize, ranges);/*第一个参数计算图像,第二个参数为所传图像个数,
    第四个参数,为掩码统计部分图像时用(统计整幅图像则按上所填即可),其余参数均已说明*/

4。计算完成我们现在需要显示直方图。

int scaleY = 1, scaleX = 1;
    Mat showImage(scaleY * 256, scaleX * 256, CV_8U, Scalar(255));
    int i;
    double maxValue = 0;
    minMaxLoc(hist, 0, &maxValue, 0, 0);
    for (i = 0; i < 256; i++)
    {
        float value = hist.at<float>(i);
        int intensity = saturate_cast<int>(256 * scaleY - 256 * scaleY * (value / maxValue));
        rectangle(showImage, Point(i*scaleX, scaleY * 256 - 1), Point((i + 1)*scaleX - 1, intensity), Scalar(0));
    }

简单解释一下scale为最终显示直方图的的规格。1为 256*256;
hist.at(i);(为访问hist矩阵元素的值,即为像素为(i)的值有多少个);
minMaxLoc计算出hist图的最大值并传入maxValue;
for循环为在直方图上刻画一个个小矩形条;

声明: 画图的代码参考了网上的一些优秀的代码。
这样就完成了直方图均值化。

完整源码如下

#include<iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include "opencv2/imgproc/imgproc.hpp" //直方图均值化函数头文件
using namespace std;
using namespace cv;

MatND getHistogram(Mat &image);
Mat getHistogramImage(Mat &image, int scaleX, int scaleY);
int main()
{
    Mat img = imread("D:\\乱\\2.jpg");
    Mat bgr[3];
    Mat bgr_res;
    /**********************************************/

    split(img, bgr);


    Mat hist1 = getHistogramImage(bgr[0], 1, 1);

    for (int i = 0;i < 3;i++)
    equalizeHist(bgr[i], bgr[i]);

    Mat hist2 = getHistogramImage(bgr[0], 1, 1);


    merge(bgr, 3, bgr_res);
    namedWindow("原直方图");
    imshow("原直方图", hist1);
    namedWindow("输出直方图");
    imshow("输出直方图", hist2);
    namedWindow("输出均值化后图");
    imshow("输出均值化后图", bgr_res);
    waitKey(0);
    return 0;
}




Mat getHistogramImage(Mat &image, int scaleX = 1, int scaleY = 1) 
{
    MatND hist;
    int channels[] = { 0 };
    int dims = 1;
    int histSize[] = { 256,256 };
    float granges[] = { 0, 255 };
    const float *ranges[] = { granges };
    calcHist(&image, 1, channels, Mat(), hist, dims, histSize, ranges);



    Mat showImage(scaleY * 256, scaleX * 256, CV_8U, Scalar(255));
    double maxValue = 0;
    minMaxLoc(hist, 0, &maxValue, 0, 0);
    for (int i = 0; i < 256; i++)
    {
        float value = hist.at<float>(i);
        int intensity = saturate_cast<int>(256 * scaleY - 256 * scaleY * (value / maxValue));
        rectangle(showImage, Point(i*scaleX, scaleY * 256 - 1), Point((i + 1)*scaleX - 1, intensity), Scalar(0));
    }
    return showImage;

}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:15435次
    • 积分:373
    • 等级:
    • 排名:千里之外
    • 原创:20篇
    • 转载:3篇
    • 译文:1篇
    • 评论:1条
    最新评论