图像处理反向投影原理

反向投影的作用是什么?
    反向投影用于在输入图像(通常较大)中查找特定图像(通常较小或者仅1个像素,称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。

直接看原文 https://blog.csdn.net/yee_yj/article/details/6035913

具体过程就是:

假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)生成临时图像的直方图;
(3)用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
(6)重复(1)~(5)步直到输入图像的右下角。

反向投影的结果是什么?
    反向投影的结果包含了:以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵,或者单通道的浮点型图像。通过图像的反向投影矩阵,我们实际上把原图像简单化了,简单化的过程实际上就是提取出图像的某个特征。以后我们可以用这个特征来对比两幅图,如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的

看完后,重点是直方图对比的方法

1、直方图对比概述

        对输入的两张图像进行直方图均衡化及直方图计算步骤后,可以对两个图像的直方图进行对比,计算相似度,并通过对比的结果得到一些我们想要的结论。

2、直方图对比的应用

(1)图像相似度比较

        如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。

(2)分析图像之间关系

        两张图像的直方图反映了该图像像素的分布情况,可以利用图像的直方图,来分析两张图像的关系。

3、直方图比较原理

        要比较两个直方图(H1 和 H2),首先必须要选择一个衡量直方图相似度的对比标准,我们设为d(H1,H2),

4、直方图比较方法
(1)相关性比较(Correlation)

(2)Chi-Square(卡方比较)

(3)Intersection(十字交叉性)

 (4)Bhattacharyya distance(巴氏距离)

在直方图相似度计算时,巴氏距离获得的效果最好,但计算是最为复杂的。巴氏距离的计算结果,其值完全匹配为1,完全不匹配则为0。

API介绍——compareHist

(1)步骤

        a.先用cvtColor()把图像从RGB色彩空间转换到HSV色彩空间;

        b.计算图像的直方图,然后归一化到[0~1]之间,用到函数 calcHist() 和 normalize() ;

        c.使用上述的四种方法之一进行比较,用到函数compareHist()。

(2)API介绍

        函数一共有三个参数,一个输入图像,一个输出图像,一个比较方法。比较方法的取值的情况为上面的四种方法,在OpenCV中,每个都有自己的名字:Correlation ( CV_COMP_CORREL );Chi-Square ( CV_COMP_CHISQR );Intersection ( CV_COMP_INTERSECT );Bhattacharyya 距离( CV_COMP_BHATTACHARYYA )。

里要说明下为什么要用H-S直方图来作对比,因为BGR直方图我们只能三个通道分别计算,计算后也没法合在一起,也就是不能把图片作为一个整体来比较,而H-S就可以将图片作一个整体对比,所以这里用H-S直方图来作对比

Opencv代码



#define INPUT_TITLE0 "input image src"
#define INPUT_TITLE1 "input image srctest1"
#define INPUT_TITLE2 "input image srctest2"
#define OUTPUT_TITLE "name"

#include<iostream>
#include<math.h>
#include<opencv2\opencv.hpp>

using namespace std;
using namespace cv;

string convertToString(double d);

int main() {
	// 加载图像 
	Mat src, srctest1, srctest2;
	src = imread("2.jpg");
	srctest1 = imread("5.jpg");
	srctest2 = imread("3.jpg");

	if (!src.data || !srctest1.data || !srctest2.data)
	{
		cout << "ERROR : could not load image.";
		return -1;
	}

	imshow("【src 原图】", src);
	imshow("【srctest1 原图】", srctest1);
	imshow("【srctest2 原图】", srctest2);

	//从RGB色彩空间转化为HSV色彩空间
	cvtColor(src, src, CV_BGR2HSV);
	cvtColor(srctest1, srctest1, CV_BGR2HSV);
	cvtColor(srctest2, srctest2, CV_BGR2HSV);

	//定义直方图计算所需要的各种参数
	int h_bins = 50;
	int s_bins = 60;
	int histSize[] = { h_bins,s_bins };

	float h_ranges[] = { 0,180 };
	float s_ranges[] = { 0,256 };
	const float* ranges[] = { h_ranges, s_ranges };

	int channels[] = { 0,1 };//使用第0和第1通道

	//MatND 是 Mat的别名,方便区分经过直方图计算处理后和输入图像
	MatND hist_src;
	MatND hist_srctest1;
	MatND hist_srctest2;

	//计算直方图并归一化处理
	calcHist(&src, 1, channels, Mat(), hist_src, 2, histSize, ranges, true, false);
	normalize(hist_src, hist_src, 0, 1, NORM_MINMAX, -1, Mat());

	calcHist(&srctest1, 1, channels, Mat(), hist_srctest1, 2, histSize, ranges, true, false);
	normalize(hist_srctest1, hist_srctest1, 0, 1, NORM_MINMAX, -1, Mat());

	calcHist(&srctest2, 1, channels, Mat(), hist_srctest2, 2, histSize, ranges, true, false);
	normalize(hist_srctest2, hist_srctest2, 0, 1, NORM_MINMAX, -1, Mat());

	//直方图比较
	double src_src = compareHist(hist_src, hist_src, CV_COMP_CORREL);
	double src_srctest1 = compareHist(hist_src, hist_srctest1, CV_COMP_CORREL);
	double src_srctest2 = compareHist(hist_src, hist_srctest2, CV_COMP_CORREL);
	double srctest1_srctest2 = compareHist(hist_srctest1, hist_srctest2, CV_COMP_CORREL);

	cout << "src compare with src correlation value : " << src_src << endl;
	cout << "src compare with srctest1 correlation value : " << src_srctest1 << endl;
	cout << "src compare with srctest2 correlation value : " << src_srctest2 << endl;
	cout << "srctest1 compare with srctest2 correlation value : " << srctest1_srctest2 << endl;

	//给每个图像上添加文字,内容为该图片和原始图片的比较结果
	putText(src, convertToString(src_src), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 255, 255), 2, LINE_AA);
	putText(srctest1, convertToString(src_srctest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
	putText(srctest2, convertToString(src_srctest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 255), 2, LINE_AA);

	//图像的显示
	namedWindow(INPUT_TITLE0, CV_WINDOW_AUTOSIZE);
	namedWindow(INPUT_TITLE1, CV_WINDOW_AUTOSIZE);
	namedWindow(INPUT_TITLE2, CV_WINDOW_AUTOSIZE);
	//namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);

	imshow(INPUT_TITLE0, src);
	imshow(INPUT_TITLE1, srctest1);
	imshow(INPUT_TITLE2, srctest2);


	waitKey(0);
	return 0;
}

string convertToString(double d) {
	ostringstream os;
	if (os << d)
	{
		return os.str();
	}
	return "invalid conversion";
}

反向投影 – 步骤

    建立直方图模型
    计算待测图像直方图并映射到模型中
    从模型反向计算生成图像

实现步骤与相关API

    加载图片imread
    将图像从RGB色彩空间转换到HSV色彩空间cvtColor
    计算直方图和归一化calcHist与normalize
    Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数据,此处均可以用Mat表示。
    计算反向投影图像 - calcBackProject
 

// recognition.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;

// 申明图像矩阵,初始化bin数目:
Mat src, hsv, hue;
int bins = 25;

void Hist_and_Backproj(int, void*);

int main(int argc, char** argv)
{
	// 1. 读取输入图像并转换到HSV 空间
	src = imread("3.jpg");
	cvtColor(src, hsv, CV_BGR2HSV);
	// 2. 使用Hue通道来创建1维直方图:
	// 分离 Hue 通道。 色调在HSV颜色空间定义取值为0°到360°,实际在OpenCV中取值为0-180
	hue.create(hsv.size(), hsv.depth());// 这里要传深度,传type会报错
	int nchannels[] = { 0, 0 };

	/*  // 将输入数组的指定通道复制到输出数组的指定通道
		mixChannels(
			const Mat* src, //输入数组或向量矩阵,所有矩阵的大小和深度必须相同。
			size_t nsrcs, //矩阵的数量
			Mat* dst, //输出数组或矩阵向量,大小和深度必须与src相同
			size_t ndsts,//矩阵的数量
			const int* fromTo,//指定被复制通道与要复制到的位置组成的索引对
			size_t npairs //fromTo中索引对的数目
		);
	*/

	mixChannels(&hsv, 1, &hue, 1, nchannels, 1);
	imshow("hue", hue);


	// 3. 创建 Trackbar 来输入bin的数目
	char text[] = "Source image";
	char* window_image = text;
	namedWindow(window_image, CV_WINDOW_AUTOSIZE);
	createTrackbar("* Hue  bins: ", window_image, &bins, 180, Hist_and_Backproj);
	Hist_and_Backproj(0, 0);

	// 现实图像
	imshow(window_image, src);

	// 等待用户反应
	waitKey(0);
	return 0;
}

void Hist_and_Backproj(int, void*)
{
	MatND hist;
	int histSize = MAX(bins, 2);
	float hue_range[] = { 0, 180 };
	const float* ranges = { hue_range };

	// 计算直方图并归一化到范围[0,255]
	calcHist(&hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());

	// 调用函数 calcBackProject 计算同一张图像的反向投影:
	MatND backproj;
	/*
		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
		)
	*/
	calcBackProject(&hue, 1, 0, hist, backproj, &ranges, 1, true);

	// 显示反向投影
	imshow("BackProj", backproj);

	// 绘制直方图
	int w = 400; int h = 400;
	int bin_w = cvRound((double)w / histSize);
	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(hist.at<float>(i)*h / 255.0)),
			Scalar(0, 0, 255), -1); //-1表示填充矩形
	}

	imshow("Histogram", histImg);
}




 

参考:

https://blog.csdn.net/shuiyixin/article/details/80257822

https://blog.csdn.net/michaelhan3/article/details/73550643

https://blog.csdn.net/qq_42887760/article/details/86562370

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值