【opencv】之直方图的应用

来源:互联网 发布:dnf制裁秒淘宝能解么 编辑:程序博客网 时间:2024/05/22 09:50

    这一篇我们来学习下直方图的应用,主要有直方图的拉伸、直方图均衡化以及利用直方图寻找相似图像。

1. 直方图拉伸

    图像对比度增强分为两类:直接对比度增强和间接对比度增强。直方图拉伸和直方图均衡化是两种最常用的间接对比度增强方法。直方图拉伸是通过对比度拉伸对直方图进行调整,从而扩大“前景”和背景灰度的差别,以达到增强对比度的目的。

    公式如下:

    设f(x,y)为输入图像,则

        最小灰度级A=min[f(x,y)]

        最大灰度级B=max[f(x,y)]

    将A和B分别线性映射到0和255,最终得到的图像为:

         g(x,y)=(255/(B-A))[f(x,y)-A]
   

    以下为代码实现:

/*------------------------------------【程序说明】-------------------------------------描述:直方图拉伸2015/10/16 by czp 2015/10/18 【修改】由于现有的图片像素区间在【0,255】,无法进行拉伸,故进行反向运算,得到sky-lancer1.jpg---------------------------------------------------------------------------------------*//*--------------------------------【程序头文件部分】----------------------------------描述:包含程序所依赖的文件--------------------------------------------------------------------------------------*/#include <iostream>#include "highgui.h"#include <opencv2/opencv.hpp>/*--------------------------------【命名空间部分】-------------------------------------描述:包含程序所使用的命名空间--------------------------------------------------------------------------------------*/using namespace cv;using namespace std;/*--------------------------------【类Histogram1D】-------------------------------------描述:计算一维直方图--------------------------------------------------------------------------------------*/class Histogram1D{private:int histSize[1];//项的数量float hranges[2];const float*ranges[1];int channels[1];public:Histogram1D(){histSize[0] = 256;hranges[0] = 0.0;hranges[1] = 255.0;ranges[0] = hranges;channels[0] = 0;}MatND getHistogram(const Mat &image){MatND hist;calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);return hist;}Mat getHistogramImage(const Mat &image){MatND hist = getHistogram(image);double maxVal = 0;double minVal = 0;minMaxLoc(hist, &minVal, &maxVal, 0, 0);Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));int hpt = static_cast<int>(0.9*histSize[0]);for (int h = 0; h < histSize[0]; h++){float binVal = hist.at<float>(h);int intensity = static_cast<int>(binVal*hpt / maxVal);line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));}return histImg;}};/*--------------------------------【main()函数】---------------------------------------描述:控制台应用程序入口--------------------------------------------------------------------------------------*/int main(){int PixMax_array[3] = { 0, 0, 0 }, PixMin_array[3] = { 255, 255, 255 };    //存储像素的最大值和最小值float DifferenceOfMaxMin[3];int i, j, nl, nc;Mat srcImg = imread("sky-lancer1.jpg", 1); //读入原图像,这里只研究彩色图像if (!srcImg.data){ printf("读取图片错误!!\n"); return false; }Mat dstImg = srcImg.clone();//遍历图像,寻找最大和最小值nl = dstImg.rows; //行数nc = dstImg.cols; //列数for (i = 0; i < nl; i++){for (j = 0; j < nc; j++){if (dstImg.at<Vec3b>(i, j)[0] < PixMin_array[0]){ PixMin_array[0] = dstImg.at<Vec3b>(i, j)[0]; }if (dstImg.at<Vec3b>(i, j)[1] < PixMin_array[1]){ PixMin_array[1] = dstImg.at<Vec3b>(i, j)[1]; }if (dstImg.at<Vec3b>(i, j)[2] < PixMin_array[2]){ PixMin_array[2] = dstImg.at<Vec3b>(i, j)[2]; }if (dstImg.at<Vec3b>(i, j)[0] > PixMax_array[0]){ PixMax_array[0] = dstImg.at<Vec3b>(i, j)[0]; }if (dstImg.at<Vec3b>(i, j)[1] > PixMax_array[1]){ PixMax_array[1] = dstImg.at<Vec3b>(i, j)[1]; }if (dstImg.at<Vec3b>(i, j)[2] > PixMax_array[2]){ PixMax_array[2] = dstImg.at<Vec3b>(i, j)[2]; }}}//遍历图像,进行直方图拉伸for (i = 0; i < 3; i++){DifferenceOfMaxMin[i] = 255.0/(float)(PixMax_array[i] - PixMin_array[i]);}for (i = 0; i < nl; i++){for (j = 0; j < nc; j++){dstImg.at<Vec3b>(i, j)[0] = (int)(DifferenceOfMaxMin[0] * (dstImg.at<Vec3b>(i, j)[0] - PixMin_array[0]));dstImg.at<Vec3b>(i, j)[1] = (int)(DifferenceOfMaxMin[1] * (dstImg.at<Vec3b>(i, j)[1] - PixMin_array[1]));dstImg.at<Vec3b>(i, j)[2] = (int)(DifferenceOfMaxMin[2] * (dstImg.at<Vec3b>(i, j)[2] - PixMin_array[2]));}}    namedWindow("srcImg");namedWindow("dstImg");imshow("srcImg", srcImg);waitKey(5000);imshow("dstImg", dstImg);waitKey(5000);//查看各个通道的直方图是否有变化(以通道0为例子)vector<Mat> mv,nv;split(srcImg,mv);split(dstImg, nv);Histogram1D hm, hn;namedWindow("Histogram_m");imshow("Histogram_m", hm.getHistogramImage(mv.at(0)));waitKey(5000);namedWindow("Histogram_n");imshow("Histogram_n", hn.getHistogramImage(nv.at(0)));waitKey(5000);}
效果图:

  

        

参考文章:http://blog.csdn.net/guoyk1990/article/details/8104130

2.直方图均衡化

    如果一幅图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度和多变的灰度色调。直方图均衡化就是为了达到这种效果。它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。【百度百科】

    简单的说,均衡化就是“把一个分布(给定的直方图)映射到另一个分布(一个更宽更统一的强度值分布),所以强度值分布会在整个范围内展开”。直方图均衡化是通过累计分布函数来实现的。

  详细的原理参见:直方图原理

    OpenCV提供了一个简单易用的函数来执行直方图均衡化。

          cv::equalizeHist(Mat &srcImage,Mat &dstImage);

         其中输入输出均为单通道图像。

        代码及其实现:

//------------------------------------【程序功能】-----------------------------------------------//  描述:直方图均衡化//-----------------------------------------------------------------------------------------------//----------------------------------【头文件包含部分】-------------------------------------------//  描述:包含程序所依赖的文件//-----------------------------------------------------------------------------------------------#include <iostream>#include "highgui.h"#include <opencv2/opencv.hpp>//-----------------------------------【命名空间声明】--------------------------------------------//  描述:包含程序所使用的命名空间//-----------------------------------------------------------------------------------------------using namespace cv;using namespace std;// 定义直方图的类class Histogram1D{private:int histSize[1];//项的数量float hranges[2];const float*ranges[1];int channels[1];public:Histogram1D(){histSize[0] = 256;hranges[0] = 0.0;hranges[1] = 255.0;ranges[0] = hranges;channels[0] = 0;}MatND getHistogram(const Mat &image){MatND hist;calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);return hist;}Mat getHistogramImage(const Mat &image){MatND hist = getHistogram(image);double maxVal = 0;double minVal = 0;minMaxLoc(hist, &minVal, &maxVal, 0, 0);Mat histImg(histSize[0], histSize[0], CV_8U, Scalar(255));int hpt = static_cast<int>(0.9*histSize[0]);for (int h = 0; h < histSize[0]; h++){float binVal = hist.at<float>(h);int intensity = static_cast<int>(binVal*hpt / maxVal);line(histImg, Point(h, histSize[0]), Point(h, histSize[0] - intensity), Scalar::all(0));}return histImg;}};//-------------------------------------【main()函数】-----------------------------------------------//描述:控制台应用程序的入口//--------------------------------------------------------------------------------------------------int main(){Mat srcImage = imread("sky-lancer.jpg", 0), dstImage;  //读入灰度图像if (!srcImage.data)  {printf("读取图像错误!"); return false;}equalizeHist(srcImage, dstImage);//处理前和处理后的图像对比namedWindow("srcImage");imshow("srcImage", srcImage);waitKey(5000);namedWindow("dstImage");imshow("dstImage", dstImage);waitKey(5000);//处理前和处理后的直方图对比Histogram1D h;namedWindow("srcHistogram");/*split(srcImage, nv);*/imshow("srcHistogram", h.getHistogramImage(srcImage));waitKey(5000);namedWindow("EqualizationOfHistogram");imshow("EqualizationOfHistogram", h.getHistogramImage(dstImage));waitKey(5000);}

  

  




0 0
原创粉丝点击