微信跳一跳:基于Opencv 识别起始点及目标点位置

学习了一段时间opencv视觉编程,也不知道自己学了点啥,做一个小的东西练练手,作为入门学习的练习吧。如果要跳起来可以用调用ADB工具进行与手机通讯实现模拟人的点击。
  
ADB工具下载地址:https://download.csdn.net/download/llikestudy_/10826334

一、起始点识别:
在这里插入图片描述
  从图可以看到,棋子是图中不变得元素,我们可以通过模板匹配来确定妻子的位置然后通过棋子的位置,对座标进一步加工,得到起始点位置。

在这里插入图片描述

	//使用模板匹配匹配到图中棋子位置
	Mat src, playsrc,local_player;
	src = imread("1.jpg");  //带匹配图
	playsrc = imread("2.png"); //模板(棋子)
	src.copyTo(local_player);
	int resultImage_cols = local_player.cols - playsrc.cols + 1;
	int resultImage_rows = local_player.rows - playsrc.rows + 1;
	Mat resultImage;
	resultImage.create(resultImage_cols,resultImage_rows,CV_32FC1);
	matchTemplate(local_player, playsrc, resultImage, TM_CCOEFF_NORMED);   //模板匹配

匹配到了模板位置,用线框圈出棋子位置,标出起始点。

	Point max_Loc;     //max_Loc是最佳匹配的区域左上角点
	minMaxLoc(resultImage, 0,0,0, &max_Loc, Mat()); //minMaxLoc寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置,这里只需要最大值,即左上角点。
	Point sport = Point(max_Loc.x + 25, max_Loc.y + 150);
	Scalar color(0, 0, 255);
	circle(local_player, sport, 6, color, -1);
	rectangle(local_player, max_Loc,Point(max_Loc.x+50,max_Loc.y+150),Scalar(255,0,255), 2, 8);
	printf("玩家落点位置:(%d,%d)\n", max_Loc.x + 50, max_Loc.y + 150);

在这里插入图片描述
  可以看出,棋子位置已经被标出,起始点被标出为红点。下一步就是寻找目标点位置。

二、目标点位置:
  首先对图像先进行一些处理,以便操作。
  在这里插入图片描述
我们看出,其实我们所需要的是上半部分的区域,且上半区域有标志等部分干扰项也将其切除。

	Mat blur;
	GaussianBlur(src, blur, Size(5, 5), 0);
	Mat canny_image;
	Canny(blur, canny_image, 1, 10);//先预处理
	
	int height, width;
	height = canny_image.rows;
	width = canny_image.cols;
	Mat crop_img;
	Rect crop_rect;
	crop_rect = Rect(0, 300, width, int(height / 2 - 300));//左上角座标,宽,高
	crop_img = canny_image(crop_rect);//取出所需要的区域(这里记住,我们给图像上面去除了300像素,后面计算的纵座标得加回来)

得到的效果:
在这里插入图片描述
  图中看到,棋子还留有一点干扰项,也给它去掉。因为之前已经得出了棋子位置,遍历棋子位置,像素值置零就好了。

	for (int i = max_Loc.x; i <= max_Loc.x + 50; i++)
		for (int j = max_Loc.y; j <= max_Loc.y+150; j++)
		{
			canny_image.at<uchar>(j, i) = 0;
	
		}

效果图:
在这里插入图片描述
嗯啊,现在干净多了。

现在我们该计算这个目标跳台的中心点了啊,看下图:
  在这里插入图片描述
由图很容易看出,获得最上点的x,最右点的y。

	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(crop_img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point()); //找到关键的角点
	//遍历每一个轮廓,把多余的轮廓去掉
	Point point1;
	Point point2;
	vector<vector<Point> >::const_iterator it = contours.begin();
	while (it != contours.end()) {
		if (it->size() < 150)
			it = contours.erase(it);
		else
			++it;
	}
	int nYMin = crop_img.rows;
	int nXMin = crop_img.cols;
	int nYMax = 0;
	int nXMax = 0;
	int nIdY = 0;
	for (int i = 0; i < contours.size(); i++)
	{
		//contours[i]代表的是第i个轮廓,contours[i].size()代表的是第i个轮廓上所有的像素点数  
		for (int j = 0; j < contours[i].size(); j++)
		{
			if (contours[i][j].y < nYMin)
			{
				nYMin = contours[i][j].y;   //找到最低的y值
				point1 = contours[i][j];    //记录  y值最低点座标
				nIdY = i;                   //记录哪个区域内的
			}
		}
	}
	int minY = crop_img.cols;

	for (int j = 0; j < contours[nIdY].size(); j++) //在哪个区域内继续变量 找到x最大值
	{
		if (contours[nIdY][j].x > nXMax)
		{
			nXMax = contours[nIdY][j].x;
		}
	}
	for (int j = 0; j < contours[nIdY].size(); j++)
	{//找到x中最大值上的最小值
		if (contours[nIdY][j].x == nXMax && contours[nIdY][j].y < minY)
		{
			point2 = contours[nIdY][j];
			minY = contours[nIdY][j].y;     //记录X点的最大值
		}
	}
	point2.y = point2.y + 300; // y测得不准,因为之前上面切掉了300像素,得加上
	Point center =  Point(point1.x, point2.y);       //返回中点座标
	printf("中心的:(%d,%d)\n", point1.x, point2.y);
	circle(local_player, center, 6, Scalar(0, 0, 255), -1);

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

两点座标已知,求起始点和目标点距离,勾股定理。

	int A = max_Loc.x + 25 - point1.x;
	int B = max_Loc.y + 150 - point2.y;
	C = int(pow(pow(A, 2) + pow(B, 2), 0.5));

	line(local_player, sport, center, Scalar(255, 0, 255), 2, 8);

	printf("距离为:%d", C);

在这里插入图片描述

好吧,最主要的两点就得到了,剩下的自己慢慢完善就好了。如果要跳起来可以用调用ADB工具进行与手机通讯实现模拟人的点击。

ADB工具下载地址:https://download.csdn.net/download/llikestudy_/10826334

发布了2 篇原创文章 · 获赞 2 · 访问量 1064
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章