> 技术文档 > 2025-07-24 Unity插件 OpenCVForUnity1——OpenCVForUnity 简介

2025-07-24 Unity插件 OpenCVForUnity1——OpenCVForUnity 简介


文章目录

  • 1 插件介绍
  • 2 OpenCV基础
    • 2.1 Mat
    • 2.2 CvType
    • 2.3 Scalar
  • 3 基础操作
    • 3.1 图像读取Mat
    • 3.2 Mat基本操作
    • 3.3 Mat输出图像
    • 3.4 合理的操作

1 插件介绍

​ OpenCV for Unity是一款强大的Unity资产插件,它将流行的计算机视觉库OpenCV无缝集成到Unity引擎中,使开发者能够在游戏开发、AR/VR应用、工业自动化等多个领域实现复杂的图像处理功能。它基于OpenCV 4.4.0(最新版本3.0.0支持OpenCV 4.12.0),提供与OpenCV Java相同的API接口。

  • 支持 iOSAndroid
  • 支持 Windows10 UWP
  • 支持 Lumin ( MagicLeap )
  • 支持 WebGL
  • 支持 WinMacLinux 平台
  • 支持在编辑器中预览

资源链接:OpenCV for Unity | Unity Asset Store

screenshot

​ 学习OpenCV for Unity,建议以下方式:

  • 查看Unity中插件Samples代码。
  • 搜索插件API文档:OpenCV for Unity: Class List
  • 学习OpenCV文档:OpenCV: OpenCV modules

2 OpenCV基础

2.1 Mat

​ Mat是OpenCV中最基础的数据结构,代表一个N*M的矩阵,用于存储图像数据。创建Mat对象的基本语法

// 创建一个3x3的单通道8位无符号整数矩阵Mat mat1 = new Mat(3, 3, CvType.CV_8UC1);// 创建一个全零矩阵Mat zeros = Mat.zeros(3, 3, CvType.CV_8UC1);// 创建一个全1矩阵Mat ones = Mat.ones(3, 3, CvType.CV_8UC1);// 创建单位矩阵(对角线为1)Mat eyes = Mat.eye(3, 3, CvType.CV_8UC1);

​ Mat结构有两个部分:

  1. 矩阵头(用于记录大小、存储方式、地址等)
  2. 包含像素(用于记录具体数据)。头文件大小是固定的,而具体数据则不是。

​ OpenCV使用引用计数系统,每个Mat对像都有自己的头,通过使它们的矩阵指针指向相同的地址。他们可同共享这这个地址,而复制操作则只是复制指针,而不是数据本身。

​ 定期检查未释放的Mat对象,大型Mat会快速消耗内存。许多OpenCV类实现了IDisposable接口,应使用using语句或手动调用Dispose()来释放资源:

using (Mat image = Imgcodecs.imread(\"image.jpg\")) { // 使用image...} // 自动释放

2.2 CvType

​ CvType的命名遵循特定的模式,格式为:CV_,例如CV_8UC1CV_32FC3等。

  1. CV_:所有类型的前缀,表示这是OpenCV的类型定义
  2. 位数:表示每个通道使用的位数
    • 8U:8位无符号整数(0-255)
    • 8S:8位有符号整数(-128-127)
    • 16U:16位无符号整数(0-65535)
    • 16S:16位有符号整数(-32768-32767)
    • 32S:32位有符号整数
    • 32F:32位浮点数
    • 64F:64位浮点数(双精度)
  3. 类型:表示数据类型
    • U:无符号整数(unsigned)
    • S:有符号整数(signed)
    • F:浮点数(float)
  4. 通道数:表示矩阵的通道数
    • C1:单通道(如灰度图像)
    • C2:双通道(较少使用)
    • C3:三通道(如RGB/BGR彩色图像)
    • C4:四通道(如RGBA带透明度的图像)

​ 偶尔会发现不带通道数的类型,如:CV_32SCV_8U等等。不这些带通道数的类型默认通道数为1。

​ 例如,CV_8U就等同于CV_8UC1CV_32S就等同于CV_32SC1

注意:

  1. 颜色顺序:OpenCV默认使用BGR顺序而非RGB,在显示或处理时需要注意
  2. 性能考虑:8位整数运算比浮点运算快,在可能的情况下优先使用8位类型

2.3 Scalar

​ Scalar是OpenCV中用于表示多通道数值的基础数据结构,本质上是一个4元素的double数组。在图像处理中常用于表示和传递像素值(BGR/RGB颜色值)或填充值。

// 1. 单值构造(适用于灰度图像)Scalar grayValue = new Scalar(128); // 等同于Scalar(128, 0, 0, 0)// 2. 三值构造(BGR彩色图像)Scalar blueColor = new Scalar(255, 0, 0); // 纯蓝色(BGR格式)// 3. 四值构造(带Alpha通道)Scalar transparentRed = new Scalar(0, 0, 255, 128); // 半透明红色(BGRA)// 4. 使用静态方法Scalar white = Scalar.all(255); // 所有通道设为255

3 基础操作

配置环境:

  • Unity 6000.0.42f
  • OpenCV for Unity 3.0.0

3.1 图像读取Mat

(1)从文件系统读取图像

​ 在OpenCV for Unity中,最常用的图像读取方式是使用Imgcodecs.imread()函数:

// 获取图片路径(注意:Application.dataPath在移动平台需要特殊处理)string imagePath = Application.dataPath + \"/OpenCVForUnity/Examples/Resources/face.jpg\";// 读取图像Mat image = Imgcodecs.imread(OpenCVEnv.GetFilePath(imagePath), Imgcodecs.IMREAD_COLOR);// 检查是否成功加载if (image.empty()){ Debug.LogError(\"无法加载图像: \" + imagePath); return;}// 释放资源image.Dispose();

参数说明

  • OpenCVEnv.GetFilePath():处理不同平台的路径问题
  • 加载标志(常用):
    • Imgcodecs.IMREAD_COLOR:始终将图像转换为3通道BGR彩色
    • Imgcodecs.IMREAD_GRAYSCALE:始终将图像转换为单通道灰度
    • Imgcodecs.IMREAD_UNCHANGED:按原样加载(包括alpha通道)

(2)从Texture2D读取图像

​ OpenCV默认使用BGR顺序,而Unity通常使用RGB,需要注意转换:

Texture2D tex = Resources.Load<Texture2D>(\"face\");Mat image = new Mat(tex.height, tex.width, CvType.CV_8UC4);OpenCVMatUtils.Texture2DToMat(tex, image);// 如果需要从BGR(A)转换为RGB(A)if(image.channels() == 3) { Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2RGB);} else if(image.channels() == 4) { Imgproc.cvtColor(image, image, Imgproc.COLOR_BGRA2RGBA);}// 释放资源image.Dispose();

(3)OpenCVMatUtils

​ 命名空间OpenCVForUnity.UnityIntegrationOpenCVMatUtils类提供了图像转Mat的其他方法。

image-20250724035030381

3.2 Mat基本操作

(1)创建空Mat

// 创建黑色空白图像(3通道BGR)Mat blankMat = new Mat(480, 640, CvType.CV_8UC3, new Scalar(0, 0, 0));// 创建白色空白图像Mat whiteMat = Mat.ones(480, 640, CvType.CV_8UC3);Core.multiply(whiteMat, new Scalar(255, 255, 255), whiteMat);// 创建特定颜色的图像Mat redMat = new Mat(480, 640, CvType.CV_8UC3, new Scalar(0, 0, 255)); // OpenCV使用BGR顺序

(2)访问和修改像素

  1. 单通道图像(灰度):
var row = 0;var col = 0;byte[] pixel = new byte[1];image.get(row, col, pixel); // 读取像素pixel[0] = 255; // 修改像素值image.put(row, col, pixel); // 写回像素
  1. 多通道图像(彩色):
byte[] pixel = new byte[3]; // 3通道image.get(row, col, pixel);// pixel[0]: 蓝色通道// pixel[1]: 绿色通道// pixel[2]: 红色通道pixel[0] = 0; // 将蓝色通道设为0image.put(row, col, pixel);

3.3 Mat输出图像

(1)保存到文件系统

// 保存为JPEG(质量参数0-100)Imgcodecs.imwrite(Application.dataPath + \"/output.jpg\", image, new MatOfInt(Imgcodecs.IMWRITE_JPEG_QUALITY, 95));// 保存为PNG(压缩级别0-9)Imgcodecs.imwrite(Application.dataPath + \"/output.png\", image, new MatOfInt(Imgcodecs.IMWRITE_PNG_COMPRESSION, 5));

(2)显示在Unity UI中

  1. 使用RawImage
using OpenCVForUnity.UnityIntegration;using UnityEngine;using UnityEngine.UI;public class ReadImgTest : MonoBehaviour{ // 在Unity中创建一个RawImage组件并关联 public RawImage rawImage; private Mat image; void Start() { image = new Mat(480, 640, CvType.CV_8UC3, new Scalar(0, 0, 0)); // 将Mat转换为Texture2D Texture2D texture = new Texture2D(image.cols(), image.rows(), TextureFormat.RGBA32, false); OpenCVMatUtils.MatToTexture2D(image, texture); // 应用纹理 rawImage.texture = texture; }}

image-20250724040618114

  1. 使用Renderer
// 适用于3D对象的材质Renderer renderer = GetComponent<Renderer>();Texture2D texture = new Texture2D(image.cols(), image.rows(), TextureFormat.RGBA32, false);OpenCVMatUtils.MatToTexture2D(image, texture);renderer.material.mainTexture = texture;

3.4 合理的操作

  1. 避免频繁分配内存

    // 不好:每次Update都新建Mat和Texture2D// 好:在Start/Awake中初始化,重复使用
  2. 使用Mat的ROI(Region of Interest)

    // 只处理图像的一部分Rect roi = new Rect(100, 100, 200, 200);Mat subMat = new Mat(image, roi);
  3. 批量操作代替逐像素操作

    // 不好:逐像素循环// 好:使用OpenCV内置函数(如add, subtract, multiply等)
  4. 适当降低分辨率

    // 对实时处理,可以缩小图像Mat small = new Mat();Imgproc.resize(image, small, new Size(image.cols()/2, image.rows()/2));