# Opencv2系列学习笔记6(直方图的应用)

<1>图像反转

Code：

Main.cpp

        MatND hist = getHistogram(image);
int i;
for(i = 0; i < 256; i++)
{
cout << "Value" << i << ": " << hist.at<float>(i) << endl;
}
/*int dim(256);
Mat lut(1, &dim, CV_8U);
for(i = 0; i < 256; i++)
{
lut.at<uchar>(i) = 255 - i;
}
Mat result = applyLookUp(image, lut);

Result：

<2>提高图像对比度

Code：

MatND getHistogram(Mat &image)  //  得到图像的直方图
{
MatND hist;
int channels[] = {0};
int dims = 1;
int histSize[] = {256};
float granges[] = {0, 255};
const float *ranges[] = {granges};
calcHist(&image, 1, channels, Mat(), hist, dims, histSize, ranges);
return hist;
}

Mat getHistogramImage(Mat &image, int scaleX = 1, int scaleY = 1)   //  将图像的直方图展示出来
{
MatND hist = getHistogram(image);
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));
}
return showImage;
}

Mat stretch(Mat &image, int minValue = 0)
{
// 首先计算直方图
MatND hist = getHistogram(image);
int imin = 0,i = 0;
// 寻找直方图的左端
for(; i < 256; i ++)
{
float iminValue = hist.at<float>(i);
if(iminValue > minValue)
{
imin = i;
break;
}
}
//  寻找直方图的右端
int imax = 255;
for(i = 255; i >= 0 ; i--)
{
float imaxValue = hist.at<float>(i);
if(imaxValue > minValue){
imax = i;
break;
}
}
// 创建查找表
Mat lookUp(1, 256, CV_8U);
// 填充查找表
for(i = 0; i < 256; i++)
{
// 确保数值位于imin和imax之间
if(i < imin)
lookUp.at<uchar>(i) = 0;
else if(i > imax)
lookUp.at<uchar>(i) = 255;
else     // 线性映射
lookUp.at<uchar>(i) = saturate_cast<uchar>(255.0*(i - imin)/(imax - imin));
}
// 应用查找表
Mat result;
LUT(image, lookUp, result);
return result;
}
Mat applyLookUp(Mat &image, Mat& lut)
{
Mat result;
LUT(image, lut, result);
return result;
}
Main.cpp

int main()
{
if(!image.data)
{
cout << "fail to load image" << endl;
return 0;
}
Mat showImage = getHistogramImage(image);
Mat result = stretch(image, 100);
Mat showImage2 = getHistogramImage(result);
namedWindow("image");
imshow("image", image);
namedWindow("showImage");
imshow("showImage", showImage);
namedWindow("showImage2");
imshow("showImage2", showImage2);
namedWindow("result");
imshow("result", result);
waitKey(0);
return 0;
}

Result：

Code：

Main.cpp

int main()
{
if(!image.data)
{
cout << "fail to load image" << endl;
return 0;
}
Mat result;
equalizeHist(image, result);   // 直方图的均衡化====增加图像的对比度
namedWindow("image");
imshow("image", image);
namedWindow("result");
imshow("result", result);
Mat imageHist = getHistogramImage(image);
Mat resultHist = getHistogramImage(result);

namedWindow("imageHist");
imshow("imageHist", imageHist);
namedWindow("resultHist");
imshow("resultHist", resultHist);

waitKey(0);
return 0;
}

Explaination：

opencv2中提供的函数为equalizeHist();它的原理是这样的，在一副完全均衡的直方图中，所有的容器拥有同等数量的像素。公式为：

lookup.at<uchar>(i)= static_cast<uchar>(255*p[i])；；其中p[i]代表强度值小于i的像素所占的比例。

Result：

Code：

Main.cpp：

int main()
{
if(!image.data)
{
cout << "Fail to load image" << endl;
return 0;
}
Mat imageROI = image(Rect(80, 120, 40, 50));
MatND histImage = getHistogram(imageROI);
normalize(histImage, histImage, 1.0);   //归一化该直方图
int channels[] = {0};
Mat result;
float granges[] = {0, 255};
const float *ranges[] = {granges};
calcBackProject(&image, 1, channels, histImage, result, ranges, 255.0);
/*第二个参数：图像数量   第三个参数: 通道数， histImage: 归一化的直方图,  result: 概率映射图
ranges: 维度的范围
*/
namedWindow("image", 0);
imshow("image", image);
namedWindow("result", 0);
imshow("result", result);
waitKey(0);
return 0;
}

Result：

Meanshift算法的具体介绍可以看我转载的一篇blog：http://blog.csdn.net/lu597203933/article/details/17042331  它就是以迭代的方式锁定概率函数的局部最大值

Code：

/*计算一幅图像特定区域的hist*/
MatND getHueHistogram(Mat &image, int minSaturation = 0)
{
MatND hist;
Mat hsvColor;
cvtColor(image, hsvColor, CV_BGR2HSV);
vector<Mat> hsv;
split(hsvColor, hsv);
if(minSaturation > 0)
{
int channels[] = {0};
int histSize[] = {181};
float hRanges[] = {0, 180};
const float *ranges[] = {hRanges};
int dims = 1;
calcHist(&hsv[0], 1, channels, mask, hist, dims, histSize, ranges);
}
normalize(hist, hist, 1.0);
return hist;
}

/*通过上面特定区域的直方图得到图像的反投影直方图*/
Mat getBackProject(Mat &image, MatND colorHist)
{
int channels[] = {0};
Mat result;
float hRanges[] = {0, 180};
const float *ranges[] = {hRanges};
calcBackProject(&image, 1, channels, colorHist, result, ranges, 255);
int thre = 60;
threshold(result, result, 60, 255,THRESH_BINARY);
return result;
}
int main()
{
// 载入第一幅图像
// 定义需要跟踪的目标---感兴趣的区域
Mat imageROI = image(Rect(230, 320, 60, 35));
// 得到目标的直方图  ********
int minSat = 65;
MatND colorHist = getHueHistogram(imageROI, minSat);

//  载入需要跟踪的图片
// 转换颜色到hsv空间
Mat hsvColor;
cvtColor(image2, hsvColor, CV_BGR2HSV);
vector<Mat> hsv;
split(image2, hsv);
// 得到目标图像的反投影直方图  *********
Mat result = getBackProject(hsv[0], colorHist);
// 去除 低饱和区域
threshold(hsv[1], hsv[1], minSat, 255, THRESH_BINARY);
bitwise_and(result, hsv[1], result);

Rect rect(230, 320, 60, 35);
rectangle(image, rect, Scalar(0,0,255));
rectangle(image2, rect, Scalar(0,0,255));
// 定义迭代的次数以及迭代的精度
TermCriteria criteria(TermCriteria::MAX_ITER, 10, 0.01);
// meanshift 算法 跟踪目标 并且得到新目标的位置rect
meanShift(result, rect, criteria);
rectangle(image2, rect, cv::Scalar(0,255,0));
namedWindow("image");
imshow("image", image);
namedWindow("result");
imshow("result", result);
namedWindow("image2", 0);
imshow("image2", image2);
waitKey(0);
return 0;

}

Explaination：

<1>代码中我们使用HSV颜色空间中的色调分量以描述所要搜索的物体。

<2>还需要注意的是如果一个颜色的饱和度偏低，会导致色调信息变得不稳定以及不可靠。这是因为低饱和度的颜色中，红绿蓝三个分量几乎是相等的。

<3>meanshift：intcvMeanShift( const CvArr* prob_image, CvRect window, CvTermCriteria criteria,CvConnectedComp* comp );

prob_image

window

criteria

Code：

int main()
{
colorReduce(imageSource, 32);
MatND sourceHist = getHistogram(imageSource);
stringstream ss;
string str;
string strBest = "";
double minDistance = 256*100*100*100;
for(int i = 1; i < 10; i++)
{
str = "F:\\test\\";
ss.clear();
ss << str;
ss << i;
ss << ".jpg";
ss >> str;
colorReduce(imageDst, 1);
MatND dstHist = getHistogram(imageDst);
double distance = compareHist(sourceHist, dstHist, CV_COMP_INTERSECT);
if(distance < minDistance)
{
strBest = str;
minDistance = distance;
}
}
namedWindow(strBest);
imshow(strBest,best);
waitKey(0);
return 0;

}

Explaination：

<1>代码中使用了降低颜色数。这是因为直方图的比较大多数都是基于逐个容器的，即比较直方图容器时并不考虑相邻容器的影像。因此，测量相似度之前减少颜色空间是很重要的。

<2>compareHist函数直接明了，只需提供两个直方图，函数边返回测量距离。通过一个标志参数可以指定测量方法。代码中的参数CV_COMP_INTERSECT表示交叉测量法。即简单比较每个直方图容器的值，并保留最小的一个。相似性测量值只是这些最小值的和。



作者：小村长  出处：http://blog.csdn.net/lu597203933 欢迎转载或分享，但请务必声明文章出处。 （新浪微博：小村长zack, 欢迎交流！）

• 本文已收录于以下专栏：

## 彩色图像直方图均衡化 --- 基于OpenCV中EqualizeHist_Demo实现

• xdsheng0818
• 2014年09月12日 16:48
• 8355

## opencv3.0 函数学习 3——equalizeHist 直方图均衡化

equalizeHist 直方图均衡化 函数功能：直方图均衡化，该函数能归一化图像亮度和增强对比度 为了更好地观察直方图均衡化的效果, 我们使用一张对比度不强的图片作为源图...
• banjiding8023
• 2016年08月09日 17:06
• 4275

## OpenCV学习笔记__入门篇（三）

11、霍夫线变换：使用OpenCV的以下函数 HoughLines 和 HoughLinesP 来检测图像中的直线. 霍夫线变换是一种用来寻找直线的方法。 是用霍夫线变换之前, 首先要对图像进行边...
• Rueing839
• 2015年09月29日 10:49
• 1068

## EqualizeHist函数

1、EqualizeHist函数 函数作用： 直方图均衡化，，用于提高图像的质量 2、EqualizeHist函数调用形式 C++: void equalizeHist(InputArray ...
• qq_18343569
• 2015年08月27日 16:08
• 2866

## opencv源码阅读之直方图均衡化（1）

opencv实现直方图均衡化的函数为equalizeHist（）；在看了直方图均衡化原理后想要实现他，于是看了一下opencv的equalizeHist（），同时提高一下自己的编程水平。最后找到了这个...
• wxplol
• 2017年03月30日 17:09
• 458

## OpenCV学习笔记（八）——图像处理之直方图ImgProc

• yang_xian521
• 2011年11月02日 18:18
• 26711

## OpenCV学习笔记（五）：计算图像直方图

• u011452747
• 2016年08月12日 15:52
• 846

## 【OpenCV】calcHist在直方图中的使用

• u014395105
• 2014年05月08日 17:55
• 1551

## opencv之直方图caluHist函数

void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray his...
• xiaozz_m608c
• 2013年08月17日 16:16
• 830

## SVD和PCA

• u010725283
• 2018年01月24日 20:28
• 1092

举报原因： 您举报文章：Opencv2系列学习笔记6(直方图的应用) 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)