OpenCVforUnity中识别图片中的基础图形

本文主要介绍了基于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<MatOfPoint> srcContours = new List<MatOfPoint>();
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);

}
  • 比较图形
    创建一个函数detect()作为比较方法,根据轮廓点的个数推断图形
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);

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

猜你喜欢

转载自blog.csdn.net/u013293580/article/details/84710933