核心思路
1.使用OpenCV for Unity 获取画面的所有图形,拿到相应轮廓点
2.将获取的点进行优化,轮廓拟合,优化轮廓点
3.创建碰撞体,将获取的点赋值给PolygonCollider2D
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using OpenCVForUnity.UnityUtils;
public class MainScripts1 : MonoBehaviour
{
//显示相机画面
public RawImage display;
private WebCamTexture webcamTexture;
//canvas画布
public GameObject testPointParent;
//一个预制体 仅有RectTransform和PolygonCollider2D,均Reset
public GameObject Collider;
public double epsilon = 0.01;
public List<GameObject> gameObjects;
float time = 0;
bool istime = true;
//识别间隔
public float timeDelta = 0.3f;
void Start()
{
ShowCamera();
}
void Update()
{
//一定时间刷新碰撞体
if (istime)
{
time += Time.deltaTime;
if (time > timeDelta)
{
time = 0;
ResetList();
Recongize();
}
}
}
//开启相机画面
void ShowCamera()
{
WebCamDevice[] devices = WebCamTexture.devices;
if (devices.Length > 0)
{
webcamTexture = new WebCamTexture(devices[0].name);
display.texture = webcamTexture;
webcamTexture.Play();
}
else
{
Debug.LogError("No camera detected on the device!");
}
}
void Recongize()
{
//将摄像机画面转Texture2D
Color32[] colors = webcamTexture.GetPixels32();
Texture2D texture2D = new Texture2D(webcamTexture.width, webcamTexture.height);
texture2D.SetPixels32(colors);
texture2D.Apply();
//创建OpenCV的材质
Texture2D srcTexture = texture2D;
Mat srcMat = new Mat(srcTexture.height, srcTexture.width, CvType.CV_8UC1);
Utils.texture2DToMat(srcTexture, srcMat);
//二值化
Imgproc.threshold(srcMat, srcMat, 127, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> srcContours = new List<MatOfPoint>();
Mat srcHierarchy = new Mat();
//核心,查找图形
Imgproc.findContours(srcMat, srcContours, srcHierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);
foreach (MatOfPoint contour in srcContours)
{
//轮廓拟合,优化轮廓点
MatOfPoint2f approxCurve = new MatOfPoint2f();
double epsilonPixels = epsilon * Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true);
Imgproc.approxPolyDP(new MatOfPoint2f(contour.toArray()), approxCurve, epsilonPixels, true);
// 将近似的轮廓点转换为MatOfPoint
MatOfPoint approxContour = new MatOfPoint(approxCurve.toArray());
//计算面积,剔除过大和过小的形状
double area = Imgproc.contourArea(approxContour);
if (area > 500000 || area < 5000) continue;
//创建PolygonCollider2D
GameObject collider = Instantiate(Collider, testPointParent.transform);
gameObjects.Add(collider);
PolygonCollider2D collider2d = collider.GetComponent<PolygonCollider2D>();
List<Vector2> customPoints = new List<Vector2>();
// 获取轮廓点的坐标
Point[] points = approxCurve.toArray();
//添加碰撞体
foreach (Point point in points)
{
customPoints.Add(new Vector2((float)point.x - Screen.width / 2, Screen.height / 2 - (float)point.y));
}
collider2d.SetPath(0, customPoints.ToArray());
}
}
//刷新碰撞体
void ResetList()
{
for (int i = 0; i < gameObjects.Count; i++)
{
Destroy(gameObjects[i]);
}
gameObjects.Clear();
}
}