本文主要介绍了基于OpenCV识别圆形、正方形、长方形和三角形等基础图形的功能
场景中创建RawImage组件,用来展示图片,创建PatternRecognation空物体,空物体上挂载新脚本shapeDectedScript.cs
public RawImage Pic; //UI
private Mat scrMat; //Mat格式存放处理的图片
//读取图片
scrMat = Imgcodecs.imread(Application.dataPath + "/Resources/FindingContours.png", 1);
//定义Texture2D设置其宽高随scrMat材质颜色模式为RGBA32
Texture2D texture = new Texture2D(scrMat.cols(), scrMat.rows(), TextureFormat.RGBA32, false);
//把Mat格式转换成texture格式
Utils.matToTexture2D(scrMat, texture);
//把texture贴在UI RawImage上
Pic.texture = texture;
//图片颜色模式转换
Imgproc.cvtColor(scrMat, scrMat, Imgproc.COLOR_BGR2GRAY);
//图片高斯模糊处理
Imgproc.GaussianBlur(scrMat, scrMat, new Size(5, 5), 0);
//图片二值化处理
Imgproc.threshold(scrMat, scrMat, 128, 255, Imgproc.THRESH_BINARY);
处理后的图片只有黑白两个颜色,想要在图片上添加图形的文字描述需要再创建一个Mat用来显示OpenCV绘制后的图片。
private Mat dstMat; //Mat格式存放处理的图片
//读取图片
dstMat = Imgcodecs.imread(Application.dataPath + "/Resources/shapes_and_colors.jpg", 1);
//Imgproc.COLOR_BGR2RGB的颜色模式可以让图片保持原色
Imgproc.cvtColor(dstMat, dstMat, Imgproc.COLOR_BGR2RGB);
新建Mat后记得修改图片导入部分的格式转换此处scrMat修改为dstMat
//把Mat格式转换成texture格式(原)
Utils.matToTexture2D(scrMat, texture);
此处scrMat修改为dstMat
//把Mat格式转换成texture格式(修改后)
Utils.matToTexture2D(scrMat, texture);
List srcContours = new List();
Mat srcHierarchy = new Mat();
//寻找轮廓
Imgproc.findContours(scrMat, srcContours, srcHierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_NONE);
for (int i = 0; i < srcContours.Count; i++)
{
//轮廓描边
Imgproc.drawContours(dstMat, srcContours, i, new Scalar(255, 255, 255), 2, 8, srcHierarchy, 0, new Point());
Point point = new Point();
float[] radius = new float[1];
//获取点集最小外接圆点
Imgproc.minEnclosingCircle(new MatOfPoint2f(srcContours[i].toArray()), point, radius);
//在圆点位置绘制圆形
Imgproc.circle(dstMat, point, 7, new Scalar(0, 0, 255), -1);
}
public string detect(MatOfPoint mp, MatOfPoint2f mp2f)
{
string shape = "unidentified";
double peri;
//主要是计算图像轮廓的周长
peri = Imgproc.arcLength(mp2f, true);
//对图像轮廓点进行多边形拟合
MatOfPoint2f polyShape = new MatOfPoint2f();
Imgproc.approxPolyDP(mp2f, polyShape, 0.04 * peri, true);
int shapeLen = polyShape.toArray().Length;
//根据轮廓凸点拟合结果,判断属于那个形状
switch (shapeLen)
{
case 3:
shape = "triangle";
break;
case 4:
OpenCVForUnity.Rect rect = Imgproc.boundingRect(mp);
float width = rect.width;
float height = rect.height;
float ar = width / height;
//计算宽高比,判断是矩形还是正方形
if (ar >= 0.95 && ar <= 1.05)
{
shape = "square";
}
else
{
shape = "rectangle";
}
break;
case 5:
shape = "pentagon";
break;
default:
shape = "circle";
break;
}
return shape;
}
之后我们只需要在描边找圆心之后加上图形对比就可以了,
MatOfPoint2f newMatOfPoint2f = new MatOfPoint2f(srcContours[i].toArray());
shape = shapeDector.detect(srcContours[i], newMatOfPoint2f);
//在图形圆心的(20,20)的右上方会绘制该轮廓的名字
Imgproc.putText(dstMat, shape, new Point(point.x - 20, point.y - 20), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar(255, 0, 0), 2, Imgproc.LINE_AA, false);