这篇文章是我在学习OpenCV基础功能过程中的一个记录,方便自己加深记忆,也帮大家避坑
PS:获取插件环境配置好直接把所有场景打包,很好玩(建议把 OpenCVForUnityExample (主菜单场景)设置为第一个场景就好)
先贴三篇文章:
[A] 环境配置:https://www.jianshu.com/p/09d93a7cc3ed
[B] 启蒙我的文章:OpenCVforUnity中识别图片中的基础图形 https://blog.csdn.net/u013293580/article/details/84710933
[C] 反面教材:看了上一篇文章最后没学完的文章 https://blog.csdn.net/qq_40544338/article/details/104613413
B文章中贴的代码其实是他自己慢慢调整的一个过程,顺序上和逻辑上对C文章作者造成了误解,也促使我进行了更深入的学习...
目标:获取一张图上存在的所有图形并对他们进行标记
流程:
1.读取图片变成Mat(OpenCV用的一种什么数据形式,隐约记得本科线性代数用过,矩阵?马上要吃饭,懒得查了)
2.对图片做处理(处理为便于解析的版本)
3.再次读图片存为另一个Mat(原图已经处理成黑白的了,换一个新的)
4.遍历所有图形信息,并把信息贴到新Mat上
5.把图片显示到unity场景中的一个RawImage上
脚本:
using System.Collections;
using System.Collections.Generic;
using System;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgcodecsModule;
using UnityEngine;
using UnityEngine.UI;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils.Helper;
public class TestFindShape : MonoBehaviour
{
public RawImage Pic; //UI
private Mat scrMat; //Mat格式存放处理的图片
private Mat dstMat; //Mat格式存放处理的图片
string shape;
void Start()
{
FindShape();
}
public void FindShape()
{
//1.读取图片变成Mat
//读取图片
scrMat = Imgcodecs.imread(Application.dataPath + "/Resources/FindingContours.png", 1);
//2.对图片做处理(处理为便于解析的版本)
//图片颜色模式转换
Imgproc.cvtColor(scrMat, scrMat, Imgproc.COLOR_BGR2GRAY);
//图片高斯模糊处理
Imgproc.GaussianBlur(scrMat, scrMat, new Size(5, 5), 0);
//图片二值化处理
Imgproc.threshold(scrMat, scrMat, 64, 255, Imgproc.THRESH_BINARY);
//3.再次读图片存为另一个Mat(原图已经处理成黑白的了,换一个新的)
//读取图片
dstMat = Imgcodecs.imread(Application.dataPath + "/Resources/FindingContours.png", 1);
//Imgproc.COLOR_BGR2RGB的颜色模式可以让图片保持原色
Imgproc.cvtColor(dstMat, dstMat, Imgproc.COLOR_BGR2RGB);
//4.遍历所有图形信息,并把信息贴到dstMat上
//获取图形列表
List srcContours = new List();
Mat srcHierarchy = new Mat();
//寻找轮廓
Imgproc.findContours(scrMat, srcContours, srcHierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_NONE);
Debug.Log("srcContours.Count = " + srcContours.Count);
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);
MatOfPoint2f newMatOfPoint2f = new MatOfPoint2f(srcContours[i].toArray());
shape = GetComponent().detect(srcContours[i], newMatOfPoint2f);
//在图形圆心的(20,20)的右上方会绘制该轮廓的名字
Imgproc.putText(dstMat, shape, new Point(point.x - 20, point.y - 20), Core.Formatter_FMT_C, 0.5, new Scalar(255, 0, 0), 2, Imgproc.LINE_AA, false);
}
//5.把图片显示到unity场景中的一个RawImage上
//定义Texture2D设置其宽高随scrMat材质颜色模式为RGBA32
Texture2D texture = new Texture2D(scrMat.cols(), scrMat.rows(), TextureFormat.RGBA32, false);
//把texture贴在UI RawImage上
Pic.texture = texture;
//把Mat格式转换成texture格式(修改后)
Utils.matToTexture2D(dstMat, texture);
}
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;
}
}



GetComponent().detect(srcContours[i], newMatOfPoint2f);这句报错,说GetComponent()需要格式,
@lgd666666:有这句吗,是不是没挂组件,Demo场景里的脚本上有挂东西的。