C++_2019-04-28_机器视觉——Opencv——基于轮廓匹配

/*
Hu轮廓匹配:
#include "Opencv_MatchShape.h"
#include "Match_Shape_NCC.h"

int main(int argc, char* argv)
{

Opencv_MatchShape demo;
demo.MatchShape_HU();
system("pause");
return 0;
}

*/
#include <iostream>
#include <time.h>

#include <opencv/cxcore.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;




class Opencv_MatchShape
{
public:
	Opencv_MatchShape();
	~Opencv_MatchShape();

	// 
	void MatchShape_test1();// 轮廓寻找

	// 
	struct ptin
	{
		int DerivativeX;
		int DerivativeY;
		double Magnitude;
		double MagnitudeN;
	}ptin;



	void MatchShape_test2();

	void MatchShape_HU();/* 对比两张图的形状是 否相似越小越相近 */

private:

};

Opencv_MatchShape::Opencv_MatchShape()
{
}

Opencv_MatchShape::~Opencv_MatchShape()
{
}

void Opencv_MatchShape::MatchShape_test1()
{
	//***********************计算时间************************************************
	
	double total_time = 0;
	clock_t start_time = clock();
	clock_t stop_time = clock();
	total_time = double(stop_time - start_time) / CLOCKS_PER_SEC;
	
	//***********************************************************************

	char* param="./Resource/Search1.jpg";
	Mat searchImage = imread(param, 1);
	if (searchImage.empty())
	{
		return;
	}
	imshow("searchImage", searchImage);
	waitKey(0);

	//***********************Opencv自带的轮廓匹配__SearchImage灰度化****************************
	
	Mat graySearchImg = cvCreateMat(searchImage.rows, searchImage.cols, CV_8UC1);
	if (searchImage.channels() == 3)
		cvtColor(searchImage, graySearchImg, CV_RGB2GRAY);
	else
	{
		searchImage.copyTo(graySearchImg);
	}
	imshow("graySearchImg", graySearchImg);
	waitKey(0);

	//***********************Opencv自带的轮廓匹配__SearchImage二值化****************************
	/*
	//! type of the threshold operation
	enum { THRESH_BINARY=CV_THRESH_BINARY, THRESH_BINARY_INV=CV_THRESH_BINARY_INV,
		   THRESH_TRUNC=CV_THRESH_TRUNC, THRESH_TOZERO=CV_THRESH_TOZERO,
		   THRESH_TOZERO_INV=CV_THRESH_TOZERO_INV, THRESH_MASK=CV_THRESH_MASK,
		   THRESH_OTSU=CV_THRESH_OTSU };
	*/
	Mat dst_bw;
	threshold(graySearchImg, dst_bw, 20, 255, CV_THRESH_OTSU);	
	imshow("dst_bw", dst_bw);
	waitKey(0);

	//***********************Opencv自带的轮廓匹配__SearchImage边缘检测****************************
	Mat edge;
	Canny(dst_bw, edge, 125, 350);
	imshow("dst_edge", edge);
	waitKey(0);

	//***********************Opencv自带的轮廓匹配_SearchImage'Contours****************************
	/*
	https://docs.opencv.org/2.4/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.html
	*/
	/*
	## mode:(定义轮廓的检索模式)
	CV_RETR_EXTERNAL	只检测最外围轮廓,包含在外围轮廓内的内围轮廓将被忽略
	CV_RETR_LIST		检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立
	CV_RETR_CCOMP		检测所有的轮廓,但所有的轮廓只建立两个等级关系
	CV_RETR_TREE		检测所有轮廓,所有轮廓建立一个等级树结构

	## method:(定义轮廓的近似方法)
	CV_CHAIN_APPROX_NONE	存储所有的轮廓点
	CV_CHAIN_APPROX_SIMPLE	压缩水平垂直对角等
	CV_CHAIN_APPROX_TC89_L1	近似算法
	*/
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(edge, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓
	/// Draw contours
	RNG rng(12345);
	Mat drawing = Mat::zeros(edge.size(), CV_8UC3);
	for (int i = 0; i< contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
	}
	/// Show in a window
	namedWindow("Contours", CV_WINDOW_AUTOSIZE);
	imshow("Contours", drawing);
	waitKey(0);

	//***********************Opencv自带的轮廓匹配_模板TemplatImage轮廓****************************
	char* param_template = "./Resource/Template.jpg";
	Mat TemplateImage = imread(param_template, 1);
	if (TemplateImage.empty())
	{
		return;
	}
	imshow("Template", TemplateImage);
	waitKey(0);

	//
	Mat grayTemplateImg = cvCreateMat(TemplateImage.rows, TemplateImage.cols, CV_8UC1);
	if (TemplateImage.channels() == 3)
		cvtColor(TemplateImage, grayTemplateImg, CV_RGB2GRAY);
	else
	{
		TemplateImage.copyTo(grayTemplateImg);
	}
	imshow("grayTemplateImg", grayTemplateImg);
	waitKey(0);

	//***********************Opencv自带的轮廓匹配_模板TemplatImage轮廓****************************
	Mat dst_template_bw;
	threshold(grayTemplateImg, dst_template_bw, 0, 255, CV_THRESH_OTSU);
	imshow("dst_template_bw", dst_template_bw);
	waitKey(0);

	/*
	## mode:(定义轮廓的检索模式)
		CV_RETR_EXTERNAL	只检测最外围轮廓,包含在外围轮廓内的内围轮廓将被忽略
		CV_RETR_LIST		检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立
		CV_RETR_CCOMP		检测所有的轮廓,但所有的轮廓只建立两个等级关系
		CV_RETR_TREE		检测所有轮廓,所有轮廓建立一个等级树结构
	
	## method:(定义轮廓的近似方法)
		CV_CHAIN_APPROX_NONE	存储所有的轮廓点
		CV_CHAIN_APPROX_SIMPLE	压缩水平垂直对角等
		CV_CHAIN_APPROX_TC89_L1	近似算法
	*/
	//***********************Opencv自带的轮廓匹配_模板TemplatImage边缘检测****************************
	Mat template_edge;
	Canny(dst_template_bw, template_edge, 125, 350);
	imshow("template_edge", template_edge);
	waitKey(0);
	//

	vector<vector<Point>> contours_template;
	vector<Vec4i> hierarchy_template;
	findContours(template_edge, contours_template, hierarchy_template, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓

	/// Draw contours
	RNG rng_template(12345);
	Mat drawing_template = Mat::zeros(template_edge.size(), CV_8UC3);
	for (int i = 0; i< contours_template.size(); i++)
	{
		Scalar color = Scalar(rng_template.uniform(0, 255), rng_template.uniform(0, 255), rng_template.uniform(0, 255));
		drawContours(drawing_template, contours_template, i, color, 2, 8, hierarchy_template, 0, Point());

	}
	/// Show in a window
	namedWindow("Contours_Template", CV_WINDOW_AUTOSIZE);
	imshow("Contours_Template", drawing_template);
	waitKey(0);
	system("pause");

}

void Opencv_MatchShape::MatchShape_test2()
{
	char* param = "./Resource/Template.jpg";
	Mat src = imread(param, 1);

	if (src.empty())
	{
		return;
	}

	Mat gray;
	cvtColor(src, gray, CV_RGB2GRAY);
	if (gray.type() != CV_8UC1)
	{
		return;
	}
	imshow("gray", gray);
	waitKey(0);

	Mat bw;
	threshold(gray, bw, 20, 255, CV_THRESH_OTSU);
	imshow("bw", bw);
	waitKey(0);

	Mat edge;
	Canny(bw, edge, 125, 350);
	imshow("dst_edge", edge);
	waitKey(0);

	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(edge, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); //找轮廓

	Mat gx, gy;
	Sobel(gray, gx, CV_32F, 1, 0);
	Sobel(gray, gy, CV_32F, 0, 1);

	Mat magnitude, direction;
	cartToPolar(gx, gy, magnitude, direction);
	long contoursLength = 0;
	double magnitudeTemp = 0;
	int originx = contours[0][0].x;
	int originy = contours[0][0].y;

	typedef struct my
	{
		int DerivativeX;
		int DerivativeY;
		double Magnitude;
		double MagnitudeN;
	}ptin;
	// 提取dx\dy\mag\log信息	
	vector<vector<ptin>> contoursInfo;
	// 提取相对坐标位置
	vector<vector<Point>> contoursRelative;

	// 开始提取
	for (int i = 0; i < contours.size(); i++) {
		int n = contours[i].size();
		contoursLength += n;
		contoursInfo.push_back(vector<ptin>(n));
		vector<Point> points(n);
		for (int j = 0; j < n; j++) {
			int x = contours[i][j].x;
			int y = contours[i][j].y;
			points[j].x = x - originx;
			points[j].y = y - originy;
			ptin pointInfo;
			pointInfo.DerivativeX = gx.at<float>(y, x);
			pointInfo.DerivativeY = gy.at<float>(y, x);
			magnitudeTemp = magnitude.at<float>(y, x);
			pointInfo.Magnitude = magnitudeTemp;
			if (magnitudeTemp != 0)
				pointInfo.MagnitudeN = 1 / magnitudeTemp;
			contoursInfo[i][j] = pointInfo;
		}
		contoursRelative.push_back(points);
	}


	// 计算目标图像梯度
	char* param1 = "./Resource/Search2.jpg";
	Mat src_search = imread(param1, 1);
	Mat grayImage;
	if (src_search.empty())
	{
		cout << "空" << endl;
		return;
	}	
	if (src_search.channels() == 3)
	{
		cvtColor(src_search, grayImage, CV_RGB2GRAY);
	}
	else
	{
		src_search.copyTo(grayImage);
	}
	if (grayImage.type() != CV_8UC1)
	{
		cout << "!CV_8UC1" << endl;
		return;
	}
	Mat gradx, grady;
	Sobel(grayImage, gradx, CV_32F, 1, 0);
	Sobel(grayImage, grady, CV_32F, 0, 1);
	

	Mat mag, angle;
	cartToPolar(gradx, grady, mag, angle);


	// NCC模板匹配
	double minScore = 0.7;		//deafult value
	double greediness = 0.8;		//deafult value
	double nGreediness = 0.8;		//deafult value
	double nMinScore = 0.7;		//deafult value

	double partialScore = 0;
	double resultScore = 0;
	int resultX = 0;
	int resultY = 0;
	double start = (double)getTickCount();
	for (int row = 0; row < grayImage.rows; row++) 
	{
		for (int col = 0; col < grayImage.cols; col++) {
			double sum = 0;
			long num = 0;
			for (int m = 0; m < contoursRelative.size(); m++) {
				for (int n = 0; n < contoursRelative[m].size(); n++) {
					num += 1;
					int curX = col + contoursRelative[m][n].x;
					int curY = row + contoursRelative[m][n].y;
					if (curX < 0 || curY < 0 || curX > grayImage.cols - 1 || curY > grayImage.rows - 1) {
						continue;
					}

					// 目标边缘梯度
					double sdx = gradx.at<float>(curY, curX);
					double sdy = grady.at<float>(curY, curX);

					// 模板边缘梯度
					double tdx = contoursInfo[m][n].DerivativeX;
					double tdy = contoursInfo[m][n].DerivativeY;

					// 计算匹配
					if ((sdy != 0 || sdx != 0) && (tdx != 0 || tdy != 0))
					{
						double nMagnitude = mag.at<float>(curY, curX);
						if (nMagnitude != 0)
							sum += (sdx * tdx + sdy * tdy) * contoursInfo[m][n].MagnitudeN / nMagnitude;
					}

					// 任意节点score之和必须大于最小阈值
					partialScore = sum / num;
					if (partialScore < min((minScore - 1) + (nGreediness * num), nMinScore * num))
						break;
				}
			}

			// 保存匹配起始点
			if (partialScore > resultScore)
			{
				resultScore = partialScore;
				resultX = col;
				resultY = row;
			} 
		}
	}
	cout << resultY << endl;
	cout << resultX << endl;
	CvPoint point;
	point.x = resultX;
	point.y = resultY;
	circle(src_search, point, 10, Scalar(255, 255, 255), 8);
	imshow("src", src_search);
	waitKey(0);

}

/* 对比两张图的形状是 否相似越小越相近 */
void Opencv_MatchShape::MatchShape_HU()
{
	cv::Mat src_template, hsv_base;
	cv::Mat src_search, hsv_test1;

	src_template = imread("./Resource/a.jpg");//模板
	src_search = imread("./Resource/b.jpg");//待测图
	int thresh = 100;
	double ans = 0, result = 0;

	Mat imageresult1, imageresult2;

	if (src_template.type() == CV_8UC3)
	{
		cvtColor(src_template, imageresult1, CV_RGB2GRAY);
		cvtColor(src_search, imageresult2, CV_RGB2GRAY);
	}
	else
	{
		src_template.copyTo(imageresult1);
		src_search.copyTo(imageresult2);
	}

	blur(imageresult1, imageresult1, Size(3, 3));
	blur(imageresult2, imageresult2, Size(3, 3));

	threshold(imageresult1, hsv_base, 20, 255, CV_THRESH_OTSU);
	threshold(imageresult2, hsv_test1, 20, 255, CV_THRESH_OTSU);	

	Canny(hsv_base, imageresult1, thresh, thresh * 2);
	Canny(hsv_test1, imageresult2, thresh, thresh * 2);	

	std::vector<std::vector<cv::Point>>contours1, contours2;
	std::vector<Vec4i>hierarchy1, hierarchy2;
	CvSize Ssize;
	Ssize.height = src_template.rows;;
	Ssize.width = src_template.cols;
	Mat drawing1(Ssize, CV_8UC3, Scalar(0, 0, 0));
	findContours(imageresult1, contours1, hierarchy1, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
	RNG rng(12345);
	int T_w, T_h;
	for (int i = 0; i<contours1.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing1, contours1, i, color, 1, 8, hierarchy1, 0, cv::Point());

		Rect boundRect = boundingRect(contours1[i]);//检测外轮廓//对外轮廓加加矩形框  ——不带旋转		
		rectangle(drawing1, boundRect, Scalar(0, 255, 0), 3);

		RotatedRect box = minAreaRect(Mat(contours1[i]));
		Point2f rect[4];
		box.points(rect);  //把最小外接矩形四个端点复制给rect数组
		for (int j = 0; j<4; j++)
		{
			line(drawing1, rect[j], rect[(j + 1) % 4], Scalar(0, 255, 0), 2, 8);  //绘制最小外接矩形每条边
		}
		if (box.size.height>box.size.width)
		{
			T_w = box.size.height;
			T_h = box.size.width;
		}
		else
		{
			T_h = box.size.height;
			T_w = box.size.width;
		}
		cout << T_w << endl<< T_h << endl;

	}
	namedWindow("imageresult2", 0);
	imshow("imageresult1", drawing1);
	
	CvSize Ssize2;
	Ssize2.height = src_search.rows;;
	Ssize2.width = src_search.cols;
	Mat drawing2(Ssize2, CV_8UC3, Scalar(0, 0, 0));;
	findContours(imageresult2, contours2, hierarchy2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cvPoint(0, 0));
	vector<Rect> boundRect(contours2.size());//包围矩形框
	vector<RotatedRect> box(contours2.size());
	for (int i = 0; i<contours2.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing2, contours2, i, color, 1, 8, hierarchy2, 0, cv::Point());
		
		boundRect[i] = boundingRect(contours2[i]);//检测外轮廓//对外轮廓加加矩形框  		
		rectangle(drawing2, boundRect[i], Scalar(0, 0, 255), 3);

		box[i] = minAreaRect(Mat(contours2[i]));
		Point2f rect[4];
		box[i].points(rect);  //把最小外接矩形四个端点复制给rect数组
		for (int j = 0; j<4; j++)
		{
			line(drawing2, rect[j], rect[(j + 1) % 4], Scalar(0, 255, 0), 2, 8);  //绘制最小外接矩形每条边
		}
	}	

	std::cout << "contours1.size()的值"<<contours1.size() << endl;
	int k = 0;
	
	for (int i = 0; i<contours1.size(); i++)
	{
		for (size_t j = 0; j < contours2.size(); j++)
		{			 
			ans = matchShapes(contours1[i], contours2[j], CV_CONTOURS_MATCH_I1, 0);
			k = j;
			std::cout << "第" << i << " 和 " << k << "的匹配值:" << ans << " " << endl;
		
			// string
			/*匹配值*/
			string label;
			stringstream stream;
			stream << (float)ans;
			/*角度*/
			//stream << ",";
			//stream << box[j].angle;			
			stream >> label;
			
			// 
			cout << box[j].size.width<< endl;
			cout << box[j].size.height << endl;
			float temp_size,w,h;
			if (box[j].size.width < box[j].size.height)
			{
				h = box[j].size.width;
				w = box[j].size.height;
			}
			else
			{
				w = box[j].size.width;
				h = box[j].size.height;
			}
			cout << w << endl;
			cout << h << endl;
			//筛选最接近尺寸的形状-长和宽的比较
			/*int T = 15;
			if (sqrt(abs((w - T_w)*(w - T_w) + (h - T_h)*(h - T_h))) < T)
			{
				putText(drawing2, label, Point(box[j].center.x, box[j].center.y), CV_FONT_BLACK, 1, Scalar(0, 255, 0), 2);
			}*/
			putText(drawing2, label, Point(box[j].center.x, box[j].center.y), CV_FONT_BLACK, 1, Scalar(0, 255, 0), 2);
		}			
	}
	namedWindow("imageresult2", 0);
	imshow("imageresult2", drawing2);
	waitKey(0);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

智能之心

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

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

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

打赏作者

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

抵扣说明:

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

余额充值