openCV学习笔记(十一)-- 模板匹配,轮廓操作

  1. 模板匹配
  2. 轮廓发现及绘制轮廓
  3. 凸包
  4. 轮廓周围绘制矩形或圆形

1.模板匹配
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

归一化后的模板匹配算法:
在这里插入图片描述

在API中对应模板匹配算法的定义:
在这里插入图片描述
在这里插入图片描述

模板匹配算法API:
在这里插入图片描述

具体实现:

	//模板匹配
	#include<opencv2/opencv.hpp>
#include<math.h>
#include<iostream>

using namespace cv;
using namespace std;


Mat src,dst,gray_src,temp;
int max_track = 5;//最多六种方法,0-5
const char* INPUT_T = "input_image";
const char* OUTPUT_T = "result_image";
const char* match_t = "template_match_demo";
int match_method = TM_SQDIFF;//方法参数
void Match_demo(int, void*);
int main(int argc, char** argv) {
	src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
	if (src.empty()) {
		printf("could not load image");
		return -1;
	}
	temp = imread("C:/Users/18929/Desktop/博客项目/项目图片/09.jpg");

	namedWindow(INPUT_T, WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_T, WINDOW_AUTOSIZE);
	namedWindow(match_t, WINDOW_AUTOSIZE);
	imshow(INPUT_T, src);

	//定义一个滚动条控制使用哪个算法匹配
	createTrackbar("tracker_title", OUTPUT_T, &match_method, max_track, Match_demo);
	Match_demo(0, 0);


	waitKey(0);
	return 0;

}

void Match_demo(int, void*) {
	int width = src.cols - temp.cols + 1;
	int height = src.rows - temp.rows + 1;
	Mat result(width, height, CV_32FC1);//定义一个图像接受匹配结果

	matchTemplate(src,temp,result,match_method,Mat());//调用模板匹配方法
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

	Point minLoc;//找到最小匹配坐标
	Point maxLoc;//找到最大匹配坐标
	double min, max;
	src.copyTo(dst);
	Point temLoc;//定义来记录对应结果坐标

	minMaxLoc(result, &min, &max, &minLoc, &maxLoc, Mat());
	//minMAXLoc -- 在数组中找到全局最小值和最大值
	//即在result结果中,找出最小坐标和最大坐标
	//&min, &max--返回的最小值指针, &minLoc, &maxLoc--返回最小最大值坐标的指针
	if (match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED) {
		temLoc = minLoc;//对应性算法--结果越小代表越相似
	}
	else {
		temLoc = maxLoc;
	}

	//绘制矩形圈出结果
	rectangle(dst, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255));
	rectangle(result, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255));

	imshow(OUTPUT_T, result);
	imshow(match_t, dst);
}

效果图:
在这里插入图片描述

2.轮廓发现
在这里插入图片描述
在这里插入图片描述
轮廓发现及绘制轮廓API:
在这里插入图片描述
在这里插入图片描述

具体实现步骤:
在这里插入图片描述
代码实现:

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

using namespace cv;
using namespace std;


Mat src,dst,gray_src,temp;
const char* output_win = "findcontours-demo";
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Contours(int, void*);
int main(int argc, char** argv) {
	src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
	if (src.empty()) {
		printf("could not load image");
		return -1;
	}
	namedWindow("input_image", WINDOW_AUTOSIZE);
	namedWindow(output_win, WINDOW_AUTOSIZE);

	imshow("input_image", src);
	cvtColor(src, src, CV_BGR2GRAY);

	//创建滚动条调节canny函数的最大最小阈值
	const char* trackbar_title = "Threshold Value:";
	createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
	Demo_Contours(0, 0);
	
	waitKey(0);
	return 0;

}

void Demo_Contours(int, void*) {
	Mat canny_output;
	//定义一个容器装发现轮廓的位置
	vector<vector<Point>> contours; 
	//定义图形的拓扑结构
	vector<Vec4i> hierachy;
	//边缘提取
	Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
	imshow("canny_img", canny_output);
	
	//轮廓发现
	findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	//定义一个零图像,用来画轮廓
	dst = Mat::zeros(src.size(), CV_8UC3);
	RNG rng(12345);
	for (size_t i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
	}
	imshow(output_win, dst);


}

效果图:
在这里插入图片描述

3.凸包
在这里插入图片描述

凸包特征
在这里插入图片描述
凸包扫描算法:
在这里插入图片描述

凸包检测时,可以预定顺时针或逆时针旋转,但是都不可逆
在这里插入图片描述

对应API:
在这里插入图片描述
openCV凸包检测步骤:
在这里插入图片描述

效果:
在这里插入图片描述
可以看见,凸包会将所有轮廓包围在内,大小轮廓都有对应的凸包

代码实现:

//凸包
#include<opencv2/opencv.hpp>
#include<math.h>
#include<iostream>

using namespace cv;
using namespace std;


Mat src,dst,gray_src,temp,dst1;
const char* output_win = "output_img";
int threshold_value = 100;
int threshold_max = 255;
void Threshold_Callback(int, void*);
RNG rng(12345);
int main(int argc, char** argv) {
	src = imread("C:/Users/18929/Desktop/博客项目/项目图片/01.jpg");
	if (src.empty()) {
		printf("could not load image");
		return -1;
	}
	namedWindow("input_image", WINDOW_AUTOSIZE);
	namedWindow(output_win, WINDOW_AUTOSIZE);
	const char* trackbar_label = "Threshold:";

	cvtColor(src, gray_src, CV_BGR2GRAY);
	//模糊一下,可以在图像二值化时降低噪声
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
	imshow("input_image", gray_src);

	createTrackbar(trackbar_label, output_win, &threshold_value, threshold_max, Threshold_Callback);
	Threshold_Callback(0, 0);

	waitKey(0);
	return 0;

}
void Threshold_Callback(int, void*) {
	Mat bin_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;

	threshold(gray_src, bin_output, threshold_value, threshold_max, THRESH_BINARY);
	findContours(bin_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	//设定一个和contours大小的容器装可行的凸包点
	vector<vector<Point>> convexs(contours.size());
	//找出凸包可行点
	for (size_t i = 0; i < contours.size(); ++i) {
		convexHull(contours[i], convexs[i], false, true);//falsr--逆时针方向,true--返回点的个数
	}

	//绘制
	dst = Mat::zeros(src.size(), CV_8UC3);
	dst1 = Mat::zeros(src.size(), CV_8UC3);
	vector<Vec4i> empty(0);//因为凸包没有拓扑结构,所以定义一个空的给它绘制
	for (size_t j = 0; j < contours.size(); j++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		//先画轮廓图
		drawContours(dst, contours, j, color, 2, LINE_8, hierachy, 0, Point(0, 0));
		drawContours(dst1, contours, j, color, 2, LINE_8, hierachy, 0, Point(0, 0));
		//画凸包图
		drawContours(dst, convexs, j, color, 2, LINE_8, empty, 0, Point(0, 0));
	}
	imshow(output_win, dst);
	imshow("nature", dst1);

}

4. 轮廓周围绘制矩形或圆形

绘制矩形在这里插入图片描述
在这里插入图片描述
什么是RDP算法?
在这里插入图片描述
对应就是设定最短距离,两点间最短距离小于最短距离的就要舍去中间点

绘制圆形
在这里插入图片描述

绘制步骤
在这里插入图片描述
效果图:
在这里插入图片描述

openCV代码:

	//绘制边缘矩形和圆形
	#include<opencv2/opencv.hpp>
#include<math.h>
#include<iostream>

using namespace cv;
using namespace std;


Mat src,dst,gray_src,temp,dst1;
const char* output_win = "output_img";
RNG rng(12345);
int threshold_v = 100;
int threshold_max = 255;
void Contours_Callback(int, void*);
int main(int argc, char** argv) {
	src = imread("C:/Users/18929/Desktop/博客项目/项目图片/10.jpg");
	if (src.empty()) {
		printf("could not load image");
		return -1;
	}
	namedWindow("input_image", WINDOW_AUTOSIZE);
	namedWindow(output_win, WINDOW_AUTOSIZE);

	cvtColor(src, gray_src, CV_BGR2GRAY);
	//模糊一下,二值化时减少噪点
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));

	imshow("input_image", gray_src);

	createTrackbar("Threshold Value", output_win, &threshold_v, threshold_max, Contours_Callback);
	Contours_Callback(0, 0);

	waitKey(0);
	return 0;

}
void Contours_Callback(int, void*) {
	Mat binary_ouput;
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	threshold(gray_src, binary_ouput, threshold_v, threshold_max, THRESH_BINARY);
	findContours(binary_ouput, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	//设置存放矩形和圆形的容器
	vector<vector<Point>> contours_poly(contours.size());
	vector<Rect> ploy_rect(contours.size());
	vector<Point2f> ccs(contours.size());
	vector<float> radius(contours.size());

	vector<RotatedRect> minRects(contours.size());
	vector<RotatedRect> myellipse(contours.size());

	for (size_t i = 0; i < contours.size(); i++)
	{
		//基于RDP算法,减少多边形轮廓点数,提高效率,把轮廓直线化,拟合为矩形
		approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//3-最短距离,低于该距离,舍弃,true--输出的是闭合的矩形
		//绘制矩形
		ploy_rect[i] = boundingRect(contours_poly[i]);
		//获取可绘制矩形数据
		minEnclosingCircle(contours[i], ccs[i], radius[i]);

		//绘制旋转矩形,且旋转矩形需要大于5个连接点才可以进行
		if (contours_poly[i].size() > 5) {
			//用椭圆将像素点包围起来,椭圆拟合,获取绘制旋转椭圆的点
			myellipse[i] = fitEllipse(contours_poly[i]);
			//绘制旋转矩形
			minRects[i] = minAreaRect(contours_poly[i]);

		}

	}
	Mat drawImg,drawImg1;
	drawImg = Mat::zeros(src.size(), src.type());
	drawImg1 = Mat::zeros(src.size(), src.type());
	Point2f pts[4];//存储矩形的四个点
	for (size_t t = 0; t < contours.size(); t++) {
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		rectangle(drawImg, ploy_rect[t], color, 2, 8);
		circle(drawImg, ccs[t], radius[t], color, 2, 8);
		if (contours_poly[t].size()>5)
		{
			//绘制椭圆
			ellipse(drawImg1, myellipse[t], color, 1, 8);
			minRects[t].points(pts);//把minRect数据集分为多个点
			//绘制旋转矩形
			for (int r = 0; r < 4; r++)
			{
				line(drawImg1, pts[r], pts[(r + 1) % 4], color, 1, 8);
			}
		}
	}
	imshow(output_win, drawImg);
	imshow("ROLATE", drawImg1);
	return;
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值