1 、反向投影
反向投影是反映直方图模型在目标图像中的分布情况
简单点说就是用直方图模型去目标图像中寻找是否有相似的对象。通常用HSV色彩空间的HS两个通道直方图模型
2 、步骤
1.建立直方图模型
2.计算待测图像直方图并映射到模型中
3.从模型反向计算生成图像
3 、代码流程
加载图片imread
将图像从RGB色彩空间转换到HSV色彩空间cvtColor
计算直方图和归一化calcHist与normalize
Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处均可以用Mat表示。
计算反向投影图像 - calcBackProject
4、理解
直方图运算是统计每个灰度值对应的像素个数,而反向投影则是将像素个数回送到该像素个数对应灰度区间的像素位置
image.png
将灰度值划分为如下四个区间:[0,2] [3,5] [6,7] [8,10]很容易得到这个图像矩阵的直方图hist= 4 4 6 2
最后计算反向投影,原图像中坐标为(0,0)的灰度值为1,1位于区间[0,2] 中,区间[0,2] 对应的直方图值为4,所以反向投影矩阵中中坐标为(0,0)的值记为4。以此类推,得到反向投影后的矩阵:
image.png
反向投影是基于直方图的逆运算,而直方图则反应了图像的色彩(亮度)特征,当两幅相似的图像仅发生位置的变化而色彩(光线)几乎不变时,对应的两幅直方图相似度非常高。
直方图只是得到了特征,反向投影则是将特征“反映”到图像上,对于物体特征识别和分割有着很大的作用
4 、整体代码测试
mixChannels()函数用于将输入数组的指定通道复制到输出数组的指定通道。
void mixChannels(
const Mat* src, //输入数组或向量矩阵,所有矩阵的大小和深度必须相同。
size_t nsrcs, //矩阵的数量
Mat* dst, //输出数组或矩阵向量,大小和
深度必须与src[0]相同
size_t ndsts,//矩阵的数量
const int* fromTo,//指定被复制通道与要复制到的位置组成的索引对
size_t npairs //fromTo中索引对的数目
);
calcBackProject
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
C++: void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )
参数详解:
onst Mat* images:输入图像
int nimages:输入图像的个数
const int* channels:需要统计直方图的第几通道
InputArray mask:掩膜,,计算掩膜内的直方图 ...Mat()
OutputArray hist:输出的直方图数组
int dims:需要统计直方图通道的个数
const int* histSize:指的是直方图分成多少个区间,就是 bin的个数
const float** ranges: 统计像素值得区间
bool uniform=true::是否对得到的直方图数组进行归一化处理
bool accumulate=false:在多个图像时,是否累计计算像素值得个数
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
//定义全局变量
Mat srcImage, hsvImage, hueImage;
const int hueBinMaxValue = 180;
int hueBinValue = 25;
//声明回调函数
void Hist_and_Backprojection(int, void*);
int main()
{
srcImage = imread("D:\\pic/z2.jpg");
//判断图像是否加载成功
if (srcImage.empty())
{
cout << "图像加载失败" << endl;
return -1;
}
else
cout << "图像加载成功..." << endl << endl;
//将图像转化为HSV图像
cvtColor(srcImage, hsvImage, CV_BGR2HSV);
//只使用图像的H参数
hueImage.create(hsvImage.size(), hsvImage.depth());
int ch[] = { 0,0 };
mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1);
//轨迹条参数设置
//char trackBarName[20];
//sprintf(trackBarName, "Hue bin:%d", hueBinMaxValue);
namedWindow("SourceImage", WINDOW_AUTOSIZE);
//创建轨迹条并调用回调函数
createTrackbar("bar", "SourceImage", &hueBinValue, hueBinMaxValue, Hist_and_Backprojection);
Hist_and_Backprojection(hueBinValue, 0);
imshow("SourceImage", srcImage);
waitKey(0);
return 0;
}
void Hist_and_Backprojection(int, void*)
{
MatND hist;
int histsize = MAX(hueBinValue, 2);
float hue_range[] = { 0,180 };
const float* ranges = { hue_range };
//计算图像直方图并归一化处理
calcHist(&hueImage, 1, 0, Mat(), hist, 1, &histsize, &ranges, true, false);
normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
//获取反向投影
MatND backProjection;
calcBackProject(&hueImage, 1, 0, hist, backProjection, &ranges, 1, true);
//输出反向投影
imshow("BackProjection", backProjection);
//绘制图像直方图
int w = 400;
int h = 400;
int bin_w = cvRound((double)w / histsize);
Mat histImage = Mat::zeros(w, h, CV_8UC3);
for (int i = 0; i < hueBinValue; i++)
{
rectangle(histImage, Point(i * bin_w, h), Point((i + 1) * bin_w, h - cvRound(hist.at(i) * h / 255.0)), Scalar(0, 0, 255), -1);
}
imshow("HistImage", histImage);
}
image.png