OpenCV2学习笔记(二):图像的直方图

直方图(Histogram)又称质量分布图。是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。众所周知,一幅图像是由不同颜色值的像素组成,因此像素值在图像中的分布情况是这幅图像的一个重要特征,因此直方图广泛应用在数字图像处理中。拍照是现实生活中必不可少的一部分,由于环境亮度、图像拍摄过程中透视光圈设置错误等影响,经常会拍出一些“过暗”的照片,此时美图、PS等美化工具可以派上用场。但是这些工具的算法通常都是不公开的,鉴于研究所需,这里利用图像直方图的一些性质来探索一些图像增强方法。开发平台为OpenCV2.4.9+Qt5.3.2。

一、灰度图像的直方图 在一幅单通道的灰度图像中,每个像素的取值区间为[0,255],因此灰度图像的直方图包含256个容器,各个容器给出当前值的像素个数。简单来说,直方图统计出每种像素取值的个数,它可以被归一化,即算出图像的像素总数,然后将各容器的像素个数除去总数,归一化后所有项的和为1。 在OpenCV中,使用cv::calcHist函数以计算直方图,这里创建一个Qt控制台应用并定义一个类(注意直方图中的数据类型为float):

histgram1d.h:

{public:Histogram1D(){// 准备直方图的相关参数histSize[0] = 256;hranges[0] = 0.0; // 灰度值范围为0到255,float类型hranges[1] = 255.0;ranges[0] = hranges;channels[0] = 0;}cv::MatND getHistogram(const cv::Mat &image); // 计算灰度图像的直方图cv::Mat getHistogramImage(const cv::Mat &image); // 计算灰度直方图并返回图像private:*ranges[1];int channels[1]; // 仅使用一个通道};

histgram1d.cpp:

cv::MatND Histogram1D::getHistogram(const cv::Mat &image){cv::MatND hist;cv::calcHist(&image, // 输入图像1,// 计算1张图片的直方图channels, // 图像的通道数cv::Mat(), // 不实用图像作为掩码hist,// 返回的直方图1,// 1D的直方图histSize, // 容器的数量ranges); // 像素值的范围return hist;}cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image){// 先计算直方图cv::MatND hist = getHistogram(image);// 获取直方图中的最大值和最小值double minVal = 0;double maxVal = 0;cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);// 以下步骤实现显示直方图的图像cv::Mat hist_img(histSize[0], histSize[0], CV_8U, cv::Scalar(255));// 设置图像的最高点int highpoint = 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*highpoint/maxVal);// 两点之间绘制一条线cv::line(hist_img, cv::Point(h, histSize[0]),cv::Point(h, histSize[0]-intensity),cv::Scalar::all(0));}return hist_img;}

注意直方图数据为浮点类型!接着修改main函数:

main(int argc, char *argv[]){QCoreApplication a(argc, argv);// 读取图片cv::Mat image = cvLoadImage(“c:/Fig6.35(5).jpg”, -1); // 允许单通道和三通道的图像读取// 创建histogram对象Histogram1D h;cv::MatND histo = h.getHistogram(imt);for(int i=0;i<256;i++){ // 输出各像素值的个数std::cout << “Value” << i << “=” << histo.at<float>(i) << std::endl;}cv::imshow(“Image”,imt);cv::imshow(“Histgram”, h.getHistogramImage(imt));return a.exec();

这是一幅亮度不足的图片,这里提供三种提高对比度的方法增强图像的方法:

一、使用查找表增强图像

首先在histgram1d.h中添加:

public:cv::Mat stretch(const cv::Mat &image, int); // 基于查找表的图像拉伸,提高图像对比度

然后在histgram1d.cpp中编写该函数如下:

cv::Mat Histogram1D::stretch(const cv::Mat &image, int minValue = 0){// 先计算直方图cv::MatND hist = getHistogram(image);// 寻找直方图的左方int imin = 0;for(;imin < 256; imin++){if(hist.at<float>(imin) > minValue)break;}// 寻找直方图的右方int imax = 255;for(;imax >= 0 ;imax–){if(hist.at<float>(imax) > minValue)break;}std::cout<< imin << “;” << imax << std::endl;// 创建查找表cv::Mat lookup(1, 256, CV_8U);// 以下循环生成查找表for(int i=0; i<256; i++){// 确保数值位于imin与imax之间if(i<imin) lookup.at<uchar>(i)=0;else if(i>imax) lookup.at<uchar>(i)=255;// 以下是个像素点的线性映射关系elselookup.at<uchar>(i)=static_cast<uchar>(255.0*(i-imin)/(imax-imin));}// 应用查找表,输出图像resultcv::Mat result;cv::LUT(image, lookup, result);return result;}每个人心中,都会有一个古镇情怀,流水江南,烟笼人家。

OpenCV2学习笔记(二):图像的直方图

相关文章:

你感兴趣的文章:

标签云: