1.反向投影概念
(1)反向投影:反映直方图模型在目标图像中的分布情况,用直方图模型去目标图像中寻找是否有相似的对象。通常用HSV色彩空间的HS两个通道直方图模型。
(2)API生成步骤:
建立直方图模型
计算待测图像直方图并映射到模型中
从模型反向计算生成图像
2.实现步骤和相关API介绍
(1)实现步骤:
加载图片imread
将图像从RGB色彩空间转换到HSV色彩空间cvtColor
计算直方图和归一化calcHist与normalize
Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处均可以用Mat表示
计算反向投影图像 - calcBackProject
(2)void mixChannels(const Mat* src,size_t nsrcs,Mat* dst,size_t ndsts,const int* fromTo,size_t npairs );
详细参考:https://blog.csdn.net/akadiao/article/details/79006929
src:输入数组或向量矩阵,所有矩阵的大小和深度必须相同
nsrcs:输入矩阵数量
dst:输出数组或矩阵向量,大小和 深度必须与src[0]相同
ndsts:输出矩阵数量
fromTo:指定被复制通道与要复制到的位置组成的索引对
npairs:fromTo中索引对的数目
(3)void cv::calcBackProject (const Mat * images, int nimages,const int * channels, InputArray hist,OutputArray backProject,const float **ranges,double scale = 1, bool uniform = true)
详细参考:https://blog.csdn.net/keith_bb/article/details/70154219#commentBox
const Mat* images:输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
int nimages:输入图像的数量
const int* channels:用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,第二个数组通道从图像image[0].channels()到image[0].channels()+image[1].channels()-1计数
InputArray hist:输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
OutputArray backProject:目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
const float ranges**:直方图中每个维度bin的取值范围
double scale=1:可选输出反向投影的比例因子
bool uniform=true:直方图是否均匀分布(uniform)的标识符,有默认值true
3.代码实现
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
Mat src, hsv,hc;
vector<Mat> bgrChannels;//存放待测试单通道图像
int bins = 12;//初始bins级数
char inputName[] = "input name";
char outputName[] = "output name";
void HistBin(int, void *);
int main()
{
src = imread("D:/demo.jpg");
if (src.empty())
{
cout << "找不到图像!" << endl;
return -1;
}
namedWindow(inputName, CV_WINDOW_AUTOSIZE);
namedWindow(outputName, CV_WINDOW_AUTOSIZE);
namedWindow("BackProj", CV_WINDOW_AUTOSIZE);
namedWindow("Histgram", CV_WINDOW_AUTOSIZE);
imshow(inputName, src);
split(src, bgrChannels);
//先转为hsv图像
cvtColor(src, hsv, CV_BGR2HSV);
hc.create(src.size(), src.depth());
int channels[] = { 0,0 };
cout << channels << endl;
mixChannels(&hsv, 1, &hc, 1, channels, 1);//mixChannels()函数用于将输入数组的指定通道复制到输出数组的指定通道
createTrackbar("Histtogram bins", outputName, &bins, 180, HistBin);
HistBin(0, 0);
waitKey(0);
return 0;
}
void HistBin(int, void *)
{
float range[] = { 0,180 };
const float *histRange = { range };
Mat h_hist;
calcHist(&hc, 1, 0, Mat(), h_hist, 1, &bins, &histRange, true, false);
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX);
Mat backProj;
calcBackProject(&bgrChannels[0], 1, 0, h_hist, backProj, &histRange, 1, true);
imshow("BackProj", backProj);
//绘制直方图
int w = 400;
int h = 400;
int bin_w = cvRound((double)w / bins);
Mat histImg = Mat::zeros(w, h, CV_8UC3);
for (int i = 0; i < bins; i++)
{
rectangle(histImg, Point(i*bin_w, h), Point((i + 1)*bin_w, h - cvRound(h_hist.at<float>(i)*h / 255.0)), Scalar(255, 0, 0), 2, LINE_AA);
}
imshow("Histgram", histImg);
}
4.运行结果
左边为h通道生成的直方图模型,右上为原图B通道的图像(检测图像),右下为反投影结果。