第四章介绍关于图像直方图方面的知识,首先介绍了直方图的计算,cv::calcHist,并写出了自定义的直方图计算方法,然后介绍了LUT的应用,然后介绍了直方图拉伸与均衡cv::equalizeHist(image,result),累积直方图,接着介绍反向投影直方图检测特殊图像内容,接着讲利用均值漂移算法(mean shift algorithm)来发现目标,最后是利用直方图比较进行图像相似检索.
(以后的头文件就不贴上来了,需要的可以贴以前文章的.)
先给出LUT,strech,equalizeHist应用程序:
#include "stdafx.h"
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<cv.h>
using namespace std;
using namespace cv;
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;
}
Mat getHistogram(const Mat &image)
{
Mat hist;
//计算直方图函数
//参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围
calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);
return hist;
}
Mat getHistogramImage(const Mat &image)
{
//首先计算直方图
Mat hist = getHistogram(image);
//获取最大值和最小值
double maxVal = 0;
double minVal = 0;
//minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取
minMaxLoc(hist,&minVal,&maxVal,0,0);
//展示直方图的画板:底色为白色
Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));
//将最高点设为bin总数的90%
int hpt = static_cast<int>(0.9*histSize[0]);
//为每一个bin画一条线
for(int h = 0; h < histSize[0];h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
//int intensity = static_cast<int>(binVal);
line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));
}
return histImg;
}
Mat equalize( Mat& image)
{
Mat equimage;
equalizeHist(image,equimage);
return equimage;
}
Mat applyLookUp(const Mat& image,const Mat& lookup)
{
Mat result;
LUT(image,lookup,result);
return result;
}
Mat strech(const Mat &image,int minValue = 0)
{
//首先计算直方图
Mat hist = getHistogram(image);
//左边入口
int imin = 0;
for(;imin< histSize[0];imin++)
{
cout<<hist.at<float>(imin)<<endl;
if(hist.at<float>(imin) > minValue)
break;
}
//右边入口
int imax = histSize[0]-1;
for(;imax >= 0; imax--)
{
if(hist.at<float>(imax) > minValue)
break;
}
//创建查找表
int dim(256);
Mat lookup(1,&dim,CV_8U);
for(int i = 0; i < 256; i++)
{
if(i < imin)
{
lookup.at<uchar>(i) = 0;
}
else if(i > imax)
{
lookup.at<uchar>(i) = 255;
}
else
{
lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);
}
}
Mat result;
result = applyLookUp(image,lookup);
return result;
}
};
int main()
{
///以灰度方式读取图像
Mat image = imread("lena.bmp");
imshow("lena",image);
if (!image.data)
return -1;
Mat result;
float hranges[2];
const float* ranges[3];
int channels[3];
hranges[0]= 0.0; // range [0,255]
hranges[1]= 255.0;
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
Mat imageROI;
imageROI=image(Rect(361,171,100,100));
imshow("lenaROI",imageROI);
Histogram1D h;
MatND hist=h.getHistogram(imageROI);
//imshow("hist",hist);
//归一化直方图
Mat nhist;
cv::normalize(hist,nhist,1.0);//,0.0,NORM_MINMAX);
imshow("nhist",nhist);
//
calcBackProject(&image,1,channels,nhist,result,ranges,255);
imshow("reslut",result);
//二值化
//float thresh=-1.0f;
//threshold(result,result,thresh,255,THRESH_BINARY);
//应用OPENCV的直方图均衡化
Mat src;
cvtColor(image,src,CV_BGR2GRAY);
Mat equalizeImage;
//直方图均衡化要求图像为单通道灰度图像
equalizeHist(src,equalizeImage);
imshow("equalizeImage",equalizeImage);
//单通道的反向投影
int channelst[1];
channelst[0]=0;
const float* rangest[1];
rangest[0]=hranges;
Mat resultOneChannel;
calcBackProject(&src,1,channelst,nhist,resultOneChannel,rangest,255);
imshow("reslutt",resultOneChannel);
waitKey();
return 0;
}
反向投影用于检测图像中特殊的图像内容.先定义需要检测的ROI,然后直方图归一化,反向投影,再阈值,就能判断图像中是否有目标物体.反向投影直方图就是用ROI归一化直方图中对应的概率值取代输入图像中的每一个像素值.
int _tmain(int argc, _TCHAR* argv[])
{
//以灰度方式读取图像
Mat image = imread("lena.bmp");
imshow("lena",image);
if (!image.data)
return -1;
Mat result;
float hranges[2];
const float* ranges[3];
int channels[3];
hranges[0]= 0.0; // range [0,255]
hranges[1]= 255.0;
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
Mat imageROI;
imageROI=image(Rect(361,171,100,100));
imshow("lenaROI",imageROI);
Histogram1D h;
MatND hist=h.getHistogram(imageROI);
//imshow("hist",hist);
//归一化直方图
Mat nhist;
cv::normalize(hist,nhist,1.0);//,0.0,NORM_MINMAX);
imshow("nhist",nhist);
//
calcBackProject(&image,1,channels,nhist,result,ranges,255);
imshow("reslut",result);
//二值化
//float thresh=-1.0f;
//threshold(result,result,thresh,255,THRESH_BINARY);
//应用OPENCV的直方图均衡化
Mat src;
cvtColor(image,src,CV_BGR2GRAY);
Mat equalizeImage;
//直方图均衡化要求图像为单通道灰度图像
equalizeHist(src,equalizeImage);
imshow("equalizeImage",equalizeImage);
//单通道的反向投影
int channelst[1];
channelst[0]=0;
const float* rangest[1];
rangest[0]=hranges;
Mat resultOneChannel;
calcBackProject(&src,1,channelst,nhist,resultOneChannel,rangest,255);
imshow("reslutt",resultOneChannel);
waitKey();
return 0;
}
为了提高检测结果,可用彩色信息或者HSV彩色空间进行反向投影.
(以后的头文件就不贴上来了,需要的可以贴以前文章的.)
先给出LUT,strech,equalizeHist应用程序:
#include "stdafx.h"
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<cv.h>
using namespace std;
using namespace cv;
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;
}
Mat getHistogram(const Mat &image)
{
Mat hist;
//计算直方图函数
//参数为:源图像(序列)地址,输入图像的个数,通道数,掩码,输出结果,直方图维数,每一维的大小,每一维的取值范围
calcHist(&image,1,channels,Mat(),hist,1,histSize,ranges);
return hist;
}
Mat getHistogramImage(const Mat &image)
{
//首先计算直方图
Mat hist = getHistogram(image);
//获取最大值和最小值
double maxVal = 0;
double minVal = 0;
//minMaxLoc用来获得最大值和最小值,后面两个参数为最小值和最大值的位置,0代表不需要获取
minMaxLoc(hist,&minVal,&maxVal,0,0);
//展示直方图的画板:底色为白色
Mat histImg(histSize[0],histSize[0],CV_8U,Scalar(255));
//将最高点设为bin总数的90%
int hpt = static_cast<int>(0.9*histSize[0]);
//为每一个bin画一条线
for(int h = 0; h < histSize[0];h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
//int intensity = static_cast<int>(binVal);
line(histImg,Point(h,histSize[0]),Point(h,histSize[0]-intensity),Scalar::all(0));
}
return histImg;
}
Mat equalize( Mat& image)
{
Mat equimage;
equalizeHist(image,equimage);
return equimage;
}
Mat applyLookUp(const Mat& image,const Mat& lookup)
{
Mat result;
LUT(image,lookup,result);
return result;
}
Mat strech(const Mat &image,int minValue = 0)
{
//首先计算直方图
Mat hist = getHistogram(image);
//左边入口
int imin = 0;
for(;imin< histSize[0];imin++)
{
cout<<hist.at<float>(imin)<<endl;
if(hist.at<float>(imin) > minValue)
break;
}
//右边入口
int imax = histSize[0]-1;
for(;imax >= 0; imax--)
{
if(hist.at<float>(imax) > minValue)
break;
}
//创建查找表
int dim(256);
Mat lookup(1,&dim,CV_8U);
for(int i = 0; i < 256; i++)
{
if(i < imin)
{
lookup.at<uchar>(i) = 0;
}
else if(i > imax)
{
lookup.at<uchar>(i) = 255;
}
else
{
lookup.at<uchar>(i) = static_cast<uchar>(255.0*(i-imin)/(imax-imin)+0.5);
}
}
Mat result;
result = applyLookUp(image,lookup);
return result;
}
};
int main()
{
///以灰度方式读取图像
Mat image = imread("lena.bmp");
imshow("lena",image);
if (!image.data)
return -1;
Mat result;
float hranges[2];
const float* ranges[3];
int channels[3];
hranges[0]= 0.0; // range [0,255]
hranges[1]= 255.0;
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
Mat imageROI;
imageROI=image(Rect(361,171,100,100));
imshow("lenaROI",imageROI);
Histogram1D h;
MatND hist=h.getHistogram(imageROI);
//imshow("hist",hist);
//归一化直方图
Mat nhist;
cv::normalize(hist,nhist,1.0);//,0.0,NORM_MINMAX);
imshow("nhist",nhist);
//
calcBackProject(&image,1,channels,nhist,result,ranges,255);
imshow("reslut",result);
//二值化
//float thresh=-1.0f;
//threshold(result,result,thresh,255,THRESH_BINARY);
//应用OPENCV的直方图均衡化
Mat src;
cvtColor(image,src,CV_BGR2GRAY);
Mat equalizeImage;
//直方图均衡化要求图像为单通道灰度图像
equalizeHist(src,equalizeImage);
imshow("equalizeImage",equalizeImage);
//单通道的反向投影
int channelst[1];
channelst[0]=0;
const float* rangest[1];
rangest[0]=hranges;
Mat resultOneChannel;
calcBackProject(&src,1,channelst,nhist,resultOneChannel,rangest,255);
imshow("reslutt",resultOneChannel);
waitKey();
return 0;
}
反向投影用于检测图像中特殊的图像内容.先定义需要检测的ROI,然后直方图归一化,反向投影,再阈值,就能判断图像中是否有目标物体.反向投影直方图就是用ROI归一化直方图中对应的概率值取代输入图像中的每一个像素值.
int _tmain(int argc, _TCHAR* argv[])
{
//以灰度方式读取图像
Mat image = imread("lena.bmp");
imshow("lena",image);
if (!image.data)
return -1;
Mat result;
float hranges[2];
const float* ranges[3];
int channels[3];
hranges[0]= 0.0; // range [0,255]
hranges[1]= 255.0;
ranges[0]= hranges; // all channels have the same range
ranges[1]= hranges;
ranges[2]= hranges;
channels[0]= 0; // the three channels
channels[1]= 1;
channels[2]= 2;
Mat imageROI;
imageROI=image(Rect(361,171,100,100));
imshow("lenaROI",imageROI);
Histogram1D h;
MatND hist=h.getHistogram(imageROI);
//imshow("hist",hist);
//归一化直方图
Mat nhist;
cv::normalize(hist,nhist,1.0);//,0.0,NORM_MINMAX);
imshow("nhist",nhist);
//
calcBackProject(&image,1,channels,nhist,result,ranges,255);
imshow("reslut",result);
//二值化
//float thresh=-1.0f;
//threshold(result,result,thresh,255,THRESH_BINARY);
//应用OPENCV的直方图均衡化
Mat src;
cvtColor(image,src,CV_BGR2GRAY);
Mat equalizeImage;
//直方图均衡化要求图像为单通道灰度图像
equalizeHist(src,equalizeImage);
imshow("equalizeImage",equalizeImage);
//单通道的反向投影
int channelst[1];
channelst[0]=0;
const float* rangest[1];
rangest[0]=hranges;
Mat resultOneChannel;
calcBackProject(&src,1,channelst,nhist,resultOneChannel,rangest,255);
imshow("reslutt",resultOneChannel);
waitKey();
return 0;
}
为了提高检测结果,可用彩色信息或者HSV彩色空间进行反向投影.
利用直方图完成基于图像内容的检索
呵呵,最后两个程序没有实现