【OpenCV】- 直方图反向投影

本文介绍了如何在OpenCV中使用直方图反向投影技术,包括工作原理、作用、calcBackProject()函数的应用以及实际示例。通过计算Hue通道的直方图,并根据模型查找图像中的匹配区域,理解了反向投影在计算机视觉中的定位功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

🤖🤖🤖🤖 欢迎浏览本博客 🤖🤖🤖🤖
😆😆😆😆😆😆😆大家好,我是:我菜就爱学😆😆😆😆😆😆😆一名刚刚入行OpenCV的小白👻👻
👻👻 从事方向:计算机视觉
🔔🔔我菜就爱学,分享有误,欢迎大佬指出🔔🔔
🌏🌏🌏本篇介绍:直方图反向投影

1 引言

反向投影就是一种记录给定图像中的像素点适应直方图模型像素分布方式的一种方法。也就是计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法

2 反向投影的工作原理
  • 建立直方图模型
  • 计算待测图像直方图并映射到模型中
  • 从模型中反向计算生成图像
3 反向投影的作用

反向投影用于输入图像中查找与特定图像最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。

4 反向投影的结果

反向投影的结果包含了以输入图像像素点为起点的直方图对比结果。可以看作一个二维的浮点型数组、二维矩阵,或者单通道的浮点型图像。

5 计算反向投影:calcBackProject()函数
void calcBackProject(const Mat * images,int nimages,const int* channels,InputArray hist,OutputArray backProject,const float** ranges,double scale=1,bool uniform=true)
  • 第一个参数:输入的数组
  • 第二个参数:输入数组的个数,也就是有多少张图片,通常为1
  • 第三个参数:通道数目
  • 第四个参数:输入的直方图
  • 第五个参数:目标反向投影阵列,单通道,与image[0]有相同的大小和深度
  • 第六个参数:表示每一个维度数组的每一维的边界矩阵,每一个维度的取值范围
  • 第七个参数:默认值1,输出的方向投影可选的缩放因子
  • 第八个参数:直方图是否均匀的标识符,默认值True
6 通道复制:mixChannels()函数

说明:此函数由输入参数复制某通道到输出参数特定的通道中。该函数是为重排图像通道提供比较先进的机制。之前接触的split()和merge()以及cvtColor()都是mixChannels()函数一部分

void mixChannels(const Mat * src,size_t nsrcs,Mat * dst,size_t ndsts,const int * fromTo,size_t npairs)
  • 第一个参数:输入的数组(hsv),所有的矩阵必须有相同的尺寸和深度

  • 第二个参数:第一个参数src输入的矩阵数

  • 第三个参数:输出数组(hue),所有矩阵必须初始化,大小和深度必须与src[0]相同

    hue.create(hsv.szie(),hsv.depth())

  • 第四个参数:第三个参数dst的输出矩阵数

  • 第五个参数:对指定的通道进行复制的数组索引

  • 第六个参数:第五个参数fromTo的索引数

示例说明:将一个4通道的RGBA图像转化为3通道BGR和一个单独的Alpha通道图像

Mat rgba(100,100,CV_8UC4,Scalar(1,2,3,4));
Mat bgr(rgba.rows,rgba.cols,CV_8UC3);
Mat alpha(rgba.rows,rgba.cols,CV_8UC1);
//组成矩阵数组来进行操作
Mat out[]={bgr,alpha};
//将rgba[0]->bgr[2]
//将rgba[1]->bgr[1]
//将rgba[2]->bgr[1]
//将rgba[3]->alpha[0]
int fromTo[]={0,2,1,1,2,0,3,3};
mixChannels(&rgba,1,out,2,fromTo,4);
7 综合示例:反向投影
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
#define WINDOW_NAME1 "【原始图】"
#define WINDOW_NAME2 "【反射投影图】"
Mat g_srcImage; Mat g_hsvImage; Mat g_hueImage;
int g_bins = 30;//直方图组距
void on_BinChange(int, void *);
int main()
{
	g_srcImage = imread("E:\\Pec\\手.jpg", 1);
	cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV);
	//分离Hue色调通道
	g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth());
	int ch[] = { 0,0 };
	mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1);
	//创建Trackbar来输入bin数目
	namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
	namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE);
	createTrackbar("色调组距:", WINDOW_NAME2, &g_bins, 180, on_BinChange);
	on_BinChange(0, 0);
	imshow(WINDOW_NAME1, g_srcImage);
	waitKey(0);
	return 0;
}
void on_BinChange(int, void *)
{
	//参数准备
	MatND hist;//Mat表示二维数组,MatND表示三维或者以上
	int histSize = MAX(g_bins, 2);
	float hue_range[] = { 0,180 };
	const float * ranges = { hue_range };
	//计算直方图并归一化
	calcHist(&g_hueImage, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
	//计算反射投影
	Mat backproj;
	calcBackProject(&g_hueImage, 1, 0, hist, backproj, &ranges, 1, true);
	imshow(WINDOW_NAME2, backproj);
	//绘制直方图
	int hist_w = 400, hist_h = 400;
	//cvRound:对double类型的数四舍五入并返回一个整型
	int bin_w = cvRound((double)hist_w / histSize);
	Mat histImage = Mat::zeros(hist_w, hist_h, CV_8UC3);
	for (int i = 0; i < g_bins; i++)
	{
		//pt1 -- 矩形的一个顶点。pt2 -- 矩形对角线上的另一个顶点
		rectangle(histImage, Point(i*bin_w, hist_h),
			Point((i + 1)*bin_w, hist_h - cvRound(hist.at<float>(i)*hist_h / 255.0)), 
			Scalar(100, 123, 255),-1);
	}
	imshow("直方图", histImage);
}

(1)原图展示

在这里插入图片描述

(2)组距bin为 6 的反向投影

在这里插入图片描述

(3)组距bin为 30 的反向投影
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我菜就爱学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值