图像直方图常见操作(一):https://blog.csdn.net/qq_37120369/article/details/104792427
图像直方图常见操作(二):https://blog.csdn.net/qq_37120369/article/details/104802821
直方图反向投影(Back Projection)的原理:
参考https://blog.csdn.net/michaelhan3/article/details/73550643
直方图反向投影作用:
如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的,区别于判断相似度,相似度参考https://blog.csdn.net/qq_37120369/article/details/104802821
直方图反向投影步骤及API:
1.加载图片imread
2.将图像从RGB色彩空间转换到HSV色彩空间cvtColor
3.计算直方图和归一化calcHist与normalize
4.计算反向投影图像 - calcBackProject
API:
void cv::calcBackProject (
const Mat * images, //输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,每一幅图像都可以有任意的通道数
int nimages, //输入图像个数
const int * channels, //用于计算反向投影的通道列表,通道数必须与直方图维度相匹配
InputArray hist, //输入的直方图
OutputArray backProject, //目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
const float ** ranges, //直方图中每个维度bin的取值范围
double scale = 1, //可选输出反向投影的比例因子
bool uniform = true //直方图是否均匀分布(uniform)的标识符,有默认值true
);
void mixChannels( //主要就是把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)的某些通道中
const Mat* src, //输入矩阵
size_t nsrcs, //输入矩阵个数
Mat* dst, //输出矩阵
size_t ndsts,//输出矩阵个数,
const int* fromTo, //通道数组
size_t npairs //有几组输入输出通道关系,其实就是前一个参数的数组元素个数除以2
);
例程:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
Mat src,hsv,hue;
int bins = 12;
void Hist_And_Backprojection(int, void*);
int main(int argc, char** argv) {
src = imread("C:\\Users\\Administrator\\Pictures\\timsa.jpg");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
cvtColor(src, hsv, CV_BGR2HSV);
hue.create(hsv.size(), hsv.depth());
int nchannels[] = { 0, 0 };
//mixChannels主要就是把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)的某些通道中
/* 参数:
输入矩阵,
输入矩阵个数,
输出矩阵,
输出矩阵个数,
通道数组,
有几组输入输出通道关系,其实就是前一个参数的数组元素个数除以2
*/
mixChannels(&hsv, 1, &hue, 1, nchannels, 1);
namedWindow("input image", CV_WINDOW_NORMAL);
namedWindow("BackProj", CV_WINDOW_NORMAL);
namedWindow("Histogram", CV_WINDOW_NORMAL);
createTrackbar("Histogram Bins:", "input image", &bins, 45, Hist_And_Backprojection);
Hist_And_Backprojection(0, 0);
imshow("input image", src);
waitKey(0);
return 0;
}
void Hist_And_Backprojection(int, void*) {
float range[] = { 0, 180 };//每个维度中像素范围,一般是[0,256]
const float *histRanges = { range };
Mat h_hist;//直方图图像
calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());
Mat backPrjImage;//反向投影输出的图像
calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true);
imshow("BackProj", backPrjImage);
int hist_h = 400;
int hist_w = 400;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
int bin_w = (hist_w / bins);
for (int i = 1; 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)))),
Point(i*bin_w, hist_h),
Scalar(0, 0, 255), -1);
}
imshow("Histogram", histImage);
return;
}