反向投影概念
反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式,简单来讲,反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的特征。反向投影在某一位置的值就是原图对应位置像素值在原图像中的总数目
反向投影原理
#include<opencv2/opencv.hpp>
#include<iostream>
int main(int argc, char** argv) {
cv::Mat M(4, 4, CV_8UC1, cv::Scalar(0));
M.at<uchar>(0, 1) = 1;
M.at<uchar>(0, 2) = 2;
M.at<uchar>(0, 3) = 3;
M.at<uchar>(1, 0) = 4;
M.at<uchar>(1, 1) = 5;
M.at<uchar>(1, 2) = 6;
M.at<uchar>(1, 3) = 7;
M.at<uchar>(2, 0) = 8;
M.at<uchar>(2, 1) = 9;
M.at<uchar>(2, 2) = 10;
M.at<uchar>(2, 3) = 11;
M.at<uchar>(3, 0) = 8;
M.at<uchar>(3, 1) = 9;
M.at<uchar>(3, 2) = 14;
M.at<uchar>(3, 3) = 15;
std::cerr << "M="<< std::endl << M << std::endl << std::endl;
cv::Mat hist; //保存直方图
int bins = 4; //设定bins数目
float range[] = { 0, 16 };//设定取值范围
//注意:取值范围[0,16)
const float* histRange = { range };
calcHist(&M, 1, 0, cv::Mat(), hist, 1, &bins, &histRange, true, false);
std::cerr << "hist=" << std::endl << hist << std::endl << std::endl;
cv::waitKey(0);
return 0;
}
(1)上面灰度图像如下 :
(2)该灰度图的直方图为(bin指定的区间为[0,3],[4,7],[8,11],[12,16))
(3)反向投影图
4 4 4 4
4 4 4 4
6 6 6 6
6 6 2 2
说明:位置(0,0)上的像素值为0,对应的bin为[0,3],所以反向直方图在该位置上的值这个bin的值4
实例
7.png
#include<opencv2/opencv.hpp>
#include<iostream>
cv::Mat backProjectionImg;
void Hist_And_BackProjection(int bins, void* hue1) { //自定义函数
float range[] = { 0,180 };
const float* histRanges = { range };
int hist_h = 400;
int hist_w = 400;
int bin_w = hist_w / bins;
cv::Mat h_hist;
cv::Mat histImage(hist_w, hist_h, CV_8UC3, cv::Scalar(0, 0, 0));
//直方图计算及归一化处理
cv::Mat hue = *(cv::Mat*)(hue1); //void*转换成cv::Mat
calcHist(&hue, 1, 0, cv::Mat(), h_hist, 1, &bins, &histRanges, true, false);//直方图计算
normalize(h_hist, h_hist, 0, 255, cv::NORM_MINMAX, -1, cv::Mat());
calcBackProject(&hue, 1, 0, h_hist, backProjectionImg, &histRanges, 1, true); //直方图反向投影
/*
参数1:Mat* images:输入图像,图像深度必须是CV_8U, CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
参数2:int 输入图像的数量
参数3:int* channels : 用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels() - 1,
第二个数组通道从图像image[0].channels()到image[0].channels() + image[1].channels() - 1计数
参数4:输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
参数5:反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
参数6:直方图中bin的取值范围
参数7:double scale = 1 : 可选输出反向投影的比例因子
输出8:bool uniform = true : 直方图是否均匀分布(uniform)的标识符,有默认值true
*/
//画直方图分部图
for (int i = 0; i < bins; i++) {
rectangle(histImage,
cv::Point((i) * bin_w, (hist_h - cvRound(h_hist.at<float>(i) * (400 / 255)))),
cv::Point(i * bin_w, hist_h),
cv::Scalar(0, 0, 255),
-1);
}
imshow("输出图像", backProjectionImg);
imshow("直方图图像", histImage);
}
int main(int argc, char** argv) {
cv::Mat src, hsv_src, hue, backProjectionImg;
int bins = 12;
int nchannels[] = { 0,0 };//通道复制对应信息
src = cv::imread("D:/bb/tu/7.png");
if (!src.data)
{
std::cout << "图像载入错误.\n";
return -1;
}
cvtColor(src, hsv_src, cv::COLOR_BGR2HSV); //将图像转化为HSV图像
hue.create(hsv_src.size(), hsv_src.depth());//创建一个图像
mixChannels(&hsv_src, 1, &hue, 1, nchannels, 1);//通道复制
//把hsv_src的0通道复制到hue的0通道
//窗口命名
namedWindow("原图像", cv::WINDOW_AUTOSIZE);
namedWindow("输出图像", cv::WINDOW_AUTOSIZE);
namedWindow("直方图图像", cv::WINDOW_AUTOSIZE);
imshow("原图像", src);
cv::createTrackbar("直方图区段数bins", "原图像", &bins, 180, Hist_And_BackProjection,&hue);//创建滑动条
Hist_And_BackProjection(bins, &hue);
cv::waitKey(0);
return 0;
}