在了解反向投影前需要先了解下直方图的概念,可以看我上一章内容:opencv直方图计算calcHist函数解析
直方图反向投影是一种图像处理技术,通常用于目标检测和跟踪。通过计算反向投影,可以将图像中与给定模式(目标对象)具有相似颜色分布的区域显著地突出显示。
反向投影原理:
首先有一张4x4原图像,像素值大小如下
像素值范围是0-15,在直方图中如果把bin(像素值范围)划分为4份,那第一份到第四份对应的像素值范围为[0, 3],[4, 7],[8, 11],[12, 15]。
这四份对应的像素数量分别为: Histogram = 4,4,6,2
反向投影图就是图像对应像素区间的数量统计,也可以看做是密度统计。 反向投影图在某一位置(点)的值是原图对应位置(点)的像素值所在原图区间(bins)的总数目,那么可以得到反向投影图如下:
一个区间点越多,在反向投影矩阵中就越亮。
反向投影中的“反向”指的是从直方图值到反向投影矩阵映射的过程。通过反向投影,原始的图像被简化了,而这个简化的过程实际上就是提取出图像的某个特征。所以我们就可以用这个特征来对比两幅图,如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的。
反向投影使用的基本流程:
(1)首先对图像选择一个感兴趣区域,也是我们需要追踪的目标对象
(2)计算目标对象的直方图,直方图表示了目标对象在不同像素值上的分布情况
(3)比较输入图像的直方图和目标对象的直方图,生成一个反向投影图像。这个反向投影图像的每个像素值表示输入图像该位置的像素值与目标对象直方图的相似程度。
(4)反向投影图像可以通过阈值或其他技术进行进一步处理,以便强调与目标对象具有相似统计特征的区域。这有助于定位目标对象在输入图像中的位置。
opencv接口:
void cv::calcBackProject(
const Mat* images // 输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
int nimages // 输入图像的数量
const int* channels // 用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,
InputArray hist // 输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
OutputArray backProject // 目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
const float ranges** // 直方图中每个维度bin的取值范围
double scale=1: // 可选输出反向投影的比例因子
bool uniform=true: // 直方图是否均匀分布(uniform)的标识符,有默认值true
)
接口调用示例:
#include <opencv2/opencv.hpp>
int main() {
// 读取图像
cv::Mat image = cv::imread("image.jpg", cv::IMREAD_COLOR);
// 定义直方图参数
int histSize = 256; // 直方图的大小
float range[] = {0, 256}; // 像素值范围
const float* histRange = {range};
int channels[] = {0}; // 使用的通道
// 计算直方图
cv::Mat hist;
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, &histSize, &histRange);
// 归一化直方图
cv::normalize(hist, hist, 0, 255, cv::NORM_MINMAX);
// 计算反向投影
cv::Mat backProject;
cv::calcBackProject(&image, 1, channels, hist, backProject, &histRange, 1, true);
// 显示结果
cv::imshow("Original Image", image);
cv::imshow("Back Project", backProject);
cv::waitKey(0);
return 0;
}
这个例子中,首先计算了输入图像的直方图,然后归一化直方图。最后,使用 calcBackProject 函数计算了反向投影图像,并显示了原始图像和反向投影图像。