【机器视觉系统】基于3DOF机械臂的五子棋机器人(4)

基于3DOF机械臂的五子棋机器人–图像处理

1. 前言

  在前面的文章中,机械设计部分和下位机的程序设计思路业已完成。接下来该讲解上位机的设计思路了,上位机主要包括两个部分,分别是:图像处理部分,用于实现棋盘网格的分割以及棋子的识别,最终得到当前棋局的棋盘数据;人工智能部分,通过输入当前棋盘的数据,进行分析下一手的棋子位置。
  上位机的类和头文件中的公有函数和公有数据结构如图
在这里插入图片描述

  下面,我们先来讲解一下图像处理部分,实现棋盘数据的读取

2. 图像处理的思路

2.1 棋盘网格构建

  棋盘网格识别主要的原理就是,

  • 对图片进行预处理(旋转和高斯滤波)
  • 在棋盘外围有一层绿色的框,通过颜色识别找出绿色区域(HSV获得绿色掩膜,与原图进行与运算即可得到边框)
  • 对绿色区域进行轮廓识别。
  • 找到识别得到的最大轮廓
  • 对找到的最大轮廓做多边形拟合,当且仅当拟合边数为4的时候,认为图片是有效的,如果边数不为4,图片无效,会进行重新采集
  • 找到四个边界点,通过仿射变换矫正图片,使得网格图片占满界面
  • 因为棋盘线是均匀的,按等分法对图像进行分割,横竖线的交界处就是棋盘网格线
//图像处理
bool ImageProcessor(cv::Mat& src) //图片预处理函数,输出图片为放射变换之后的图片
{
	// 一、图片旋转
	Rotation(src);
	
	//二、高斯滤波
	cv::GaussianBlur(src, src, cv::Size(3, 3), 0);

	//三、提取轮廓边界点
	vector<cv::Point2f> rect_Point;
	if (!GetRectPoint(src, rect_Point))return false; //如果没有提取边界点成功,返回false
	

	//四、放射变换
	warp(src, rect_Point);



	return true;
	

}

//网格分割
ChessPad chp;
chp.ReloadGrid(src); //输入仿射变换之后的图片,并且进行等分分割,得到网格

2.2 棋子的识别

  因为棋子是红色和蓝色的,通过在网格点处进行颜色识别,即可判断棋子类型,并加入到棋盘中
  默认蓝色棋子代表黑色,是人工下的。红色代表白色棋子,是计算机下的。


bool ChessPad::addBlackList() //加入黑色棋子
{
	//01 仿射变换以后的图片转转hsv图片
	cv::Mat hsv;
	cv::cvtColor(src, hsv, CV_BGR2HSV);

	//02 识别黑棋(实际使用的是蓝色的)
	for (int i = 0; i < 9; i++)
	{
		for (int j = 0; j < 9; j++)
		{

			int h, s, v; //记录格点的hsv值
			int flag = 0; //用于判断是否连续两次检测都是蓝色棋子
			for (int time = 0; time < 2; time++)
			{

				//获取网格点的hsv值,识别蓝色棋子,这是我们的棋子。但是棋盘可能出现误识别,所以识别了2次,必须连续2次都是蓝色,才
				//被认为是我们下的棋子
				h = hsv.at<cv::Vec3b>(P(i,j))[0];
				s = hsv.at<cv::Vec3b>(P(i, j))[1];
				v = hsv.at<cv::Vec3b>(P(i, j))[2];

				if (h >= 110 && h <= 124 && s >= 43 && s <= 255 && v >= 43 && v <= 255)
				{

					flag++;
					if (flag == 2)
					{
						if (find(BlackList.begin(), BlackList.end(), cv::Point(i, j)) == BlackList.end())//如果这个位置的黑棋还没有加入棋盘,就加入
						{
							chess.at<uchar>(j, i) = BLACK;
							BlackList.push_back(cv::Point(i, j));
							return  true; //本次有插入棋子
						}
						

					}
				}
				else
				{
					break;
				}

			}
		}
	}
	return false;

}

3. 盘点上位机设计中的一些问题

3.1 命名空间

  在写开始写库函数的时候,因为直接开放的命名空间,发现串口库中调用的一些windows函数和opencv中的函数是冲突的。而不开放命名空间,能够确认函数的来源,会更少的发生重名冲突的事件。

3.2 网格识别

  也使用过边缘检测+霍夫变换的方法识别过网格。但是霍夫变换会出现很多的重线,需要用最小二乘的方法进行重线合并,并且识别效率比较差。
  这种方法可能开始只需要识别一次网格获得坐标,后期就不需要继续识别了(后面下了棋子了,也没有办法通过这种方法继续识别了)。不过,因为后面需要判断我什么时候下好了棋子,通过检测棋盘轮廓是否为四边形来实现的,因此需要进行实时的图片检测,因此不能只做一次网格识别。

3.3 棋子识别

  一开始我是用的标准的黑白棋子来做的,因为棋盘背景也是白色的,非常不好实现。
  比如用颜色识别的话,判断网格点周围一小块区域的平均灰度值,来判断是黑色、白色还是无子。但是因为网格不是非常准,有可能对着空白区域,加了很多矫正方案也不行,因此放弃了这种方案
  也使用了轮廓识别+霍夫圆变换的方法识别棋子,因为背景是白色的,白色棋子轮廓区别度特别小。并且白色特别容易反光。后来在镜头端增加了一个偏振光滤光片,希望能够解决反光问题。但是发现偏振光滤光片对平面的反光效果非常好,但是对凹凸面的反光其实是没有效果的,因此也放弃了。
  还用了多模板匹配的方法希望找到黑白棋,但是由于棋盘是白色的,还是与白棋比较像,模板匹配找白色棋子效果非常差。
  因此最终得到一个结论,如果想非常好的识别棋子,那么,棋盘和棋子一定要具有比较好的对比度。而且如果有条件配光源的话,最后搞一个,配置好环境光,减少反光,在输入层面解决问题,比图像处理上容易多了。
  展示一些中间的过程图吧。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值