目录
1.概念
1.1直方图概念
??1.2直方图均衡化概念
?2.直方图计算
2.1直方图概念扩展
?2.2 画三通道直方图
?3.直方图的比较
3.1Correlation 相关性比较
?3.2Chi-Square 卡方比较
?3.3intersection十字交叉性
3.4Bhattacharyya distance 巴氏距离?
3.5相关API
3.6案例分析
4.直方图的反向投影(back projection)
4.1反向投影概述
?
4.2反向投影步骤
4.3实现步骤及相关API
4.4 代码演示
1.概念
1.1直方图概念
?1.2直方图均衡化概念
?图像直方图均衡化的实现:
直方图均衡化API:
?直方图均衡化案例
void MyApi::histogramEqualize(Mat& image)
{
Mat gray_image,dst;
cvtColor(image, gray_image, COLOR_BGR2GRAY);
imshow("灰度图", gray_image);
equalizeHist(gray_image, dst);
imshow("直方图均衡化后图像", dst);
}
?上图分别是原图、灰度图、直方图均衡化后的图
?2.直方图计算
2.1直方图概念扩展
?
?2.2 画三通道直方图
void MyApi::histogram_cal(Mat& image)
{
//1.把多通道的图像分离单通道
vector<Mat> bgr_planes;
split(image, bgr_planes);
//imshow("单个通道",bgr_planes[0]);//我们可以输出bgr中的b通道的图像
//2.计算直方图
int histSize = 256;
float range[] = { 0,256 };
const float* histRanges = {range};
Mat b_hist, g_hist, r_hist;
calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
//归一化:为了避免有些像素值的统计值很大,因此为了方便观察归一化到一定的范围内
int hist_h = 400;
int hist_w = 512;
int bin_w = hist_w / histSize;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//绘制直方图
for (int i = 1; i < histSize; i++)
{
line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA);
line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);
line(histImage, Point((i - 1) * bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);
}
imshow("彩色图像直方图", histImage);
}
?3.直方图的比较
对于输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间(图像大小要一致)然后可以通过计算H1与H2之间的距离得到两个直方图的相似程度,进而比较图像本身的相似程度。openCV提供了比较方法有四种:
- Correlation 相关性比较
- Chi-Square 卡方比较
- intersection十字交叉性
- Bhattacharyya distance 巴氏距离
3.1Correlation 相关性比较
?3.2Chi-Square 卡方比较
?3.3intersection十字交叉性
3.4Bhattacharyya distance 巴氏距离
3.5相关API
opencv4中compareHist中的method是改为如下:
相关性比较(HISTCMP_CORREL)值越接近1,相关性越高;越接近0,相关性越低; 卡方比较(HISTCMP_CHISQR)值越小越接近,为0时相似度最高; 巴氏距离(HISTCMP_BHATTACHARYYA),完全匹配为 0,完全不匹配为1
3.6案例分析
源文件函数如下:
string convertToString(double d)//double类型转为string类型
{
ostringstream os;
if (os << d)
return os.str();
return "invalid convertsion";
}
void MyApi::histogram_comp(Mat& image, Mat& test1, Mat& test2)
{
//图像颜色空间转到HSV空间
cvtColor(image, image, COLOR_BGR2HSV);
cvtColor(test1, test1, COLOR_BGR2HSV);
cvtColor(test2, test2, COLOR_BGR2HSV);
//设置两个灰度等级
int h_bins = 50;
int s_bins = 60;
int histSize[] = {h_bins,s_bins};
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = {h_ranges,s_ranges};
int channels[] = { 0,1 };
MatND hist_image;
MatND hist_test1;
MatND hist_test2;
//计算直方图
calcHist(&image, 1, channels, Mat(), hist_image, 2, histSize, ranges, true, false);
normalize(hist_image, hist_image, 0, 1, NORM_MINMAX, -1, Mat());
calcHist(&test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false);
normalize(hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat());
calcHist(&test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false);
normalize(hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat());
//相互比较
double imageimgae = compareHist(hist_image, hist_image, HISTCMP_CORREL);
double imagetest1 = compareHist(hist_image, hist_test1, HISTCMP_CORREL);
double imagetest2 = compareHist(hist_image, hist_test2, HISTCMP_CORREL);
double test1test2 = compareHist(hist_test1, hist_test2, HISTCMP_CORREL);
printf("test1与test2比较的相关性指标为:%f", test1test2);
putText(image, convertToString(imageimgae), Point(50, 50), FONT_HERSHEY_COMPLEX,
1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test1, convertToString(imagetest1), Point(50, 50), FONT_HERSHEY_COMPLEX,
1, Scalar(0, 0, 255), 2, LINE_AA);
putText(test2, convertToString(imagetest2), Point(50, 50), FONT_HERSHEY_COMPLEX,
1, Scalar(0, 0, 255), 2, LINE_AA);
namedWindow("image", WINDOW_AUTOSIZE);
namedWindow("test1", WINDOW_AUTOSIZE);
namedWindow("test2", WINDOW_AUTOSIZE);
imshow("image", image);
imshow("test1", test1);
imshow("test2", test2);
}
?测试函数如下:
#include<opencv2/opencv.hpp>
#include<iostream>
#include"myApi.h"
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
Mat src = imread("F:\\testImage\\test.png");
if (src.empty()) {
printf("could not load image...");
return -1;
}
//如果图像过于大,不能完全显示整张图像可以使用namedWindow()可以实现对图像的自由缩放
//namedWindow("input_window", WINDOW_FREERATIO);
//imshow("input_window", src);
Mat test1 = imread("F:\\testImage\\test1.png");
Mat test2 = imread("F:\\testImage\\test2.png");
MyApi ma;
ma.histogram_comp(src,test1,test2);
waitKey(0);
return 0;
}
?从左到右分别是image与test1比较的相似性、与test2比较的相似性、与image比较的相似性
4.直方图的反向投影(back projection)
4.1反向投影概述
4.2反向投影步骤
- 建立直方图模型
- 计算待测图像直方图并映射到模型中
- 从模型反向计算生成图像
4.3实现步骤及相关API
- 加载图片imread
- 将图像从RGB色彩空间转换到HSV色彩空间cvtcolor
- 计算直方图和归一化calcHist与normalize
- Mat与MatND其中Mat表示二维数据,MatND表示三维或者多维数据,此处均可以用Mat表示
- 计算反向投影图像calcBackProject
4.4 代码演示
mixChannels()参数说明:
void mixChannels( const Mat* src, //输入数组或向量矩阵,所有矩阵的大小和深度必须相同。 size_t nsrcs, //矩阵的数量 Mat* dst, //输出数组或矩阵向量,大小和 深度必须与src[0]相同 size_t ndsts,//矩阵的数量 const int* fromTo,//指定被复制通道与要复制到的位置组成的索引对 size_t npairs //fromTo中索引对的数目 );
#define INPUT_TITLE "Input Image"
#define OUTPUT_TITLE "Back Projection"
#define HIST_TITLE "Histogram"
#include<iostream>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
/*———————————本代码所需变量定义及初始化——————————— */
Mat src, hsv_src, hue, backProjectionImg;
int bins = 12;
int nchannels[] = { 0,0 };
/*—————————————本代码所需函数声明————————————— */
void Hist_And_BackProjection(int, void*);
int main() {
/*—————————————全局变量的赋值————————————— */
//1.图像载入
src = imread("D:/hand.jpg");
if (!src.data)
{
cout << "ERROR : could not load image.\n";
return -1;
}
//2.将图像转化为HSV图像
cvtColor(src, hsv_src, CV_BGR2HSV);
//3.创建一个图像
hue.create(hsv_src.size(), hsv_src.depth());
//窗口命名
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(HIST_TITLE, CV_WINDOW_AUTOSIZE);
//从输入图像中拷贝某通道到输出图像中特定的通道
mixChannels(&hsv_src, 1, &hue, 1, nchannels, 1);
//动态调整直方图的 bins ,并做反向投影
createTrackbar("Histogram Bins", INPUT_TITLE, &bins, 180, Hist_And_BackProjection);
Hist_And_BackProjection(0, 0);
imshow(INPUT_TITLE, src);
waitKey(0);
return 0;
}
/*—————————————本代码所需函数实现————————————— */
void Hist_And_BackProjection(int, void*) {
//局部变量
float range[] = { 0,180 };
const float *histRanges = { range };
int hist_h = 400;
int hist_w = 400;
int bin_w = hist_w / bins;
Mat h_hist;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
//直方图计算及归一化处理
calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());
//直方图反向投影
calcBackProject(&hue, 1, 0, h_hist, backProjectionImg, &histRanges, 1, true);
//画直方图分部图
for (int i = 0; i < bins; i++)
{
/*rectangle(histImage,
Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1)*(400 / 255)))),
Point(i*bin_w, (hist_h - cvRound(h_hist.at<float>(i)*(400 / 255)))),
Scalar(0, 0, 255),
-1);*/
rectangle(histImage,
Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1)*(400 / 255)))),
Point(i*bin_w, hist_h),
Scalar(0, 0, 255),
-1);
}
imshow(OUTPUT_TITLE, backProjectionImg);
imshow(HIST_TITLE, histImage);
}
|