OpenCVForUnity之MatToTextureInRenderThreadExample

news/2025/2/7 16:54:05/

MatToTextureInRenderThreadExample演示了如何在Unity中使用多线程技术,将OpenCV的Mat对象转换为Unity中的纹理对象。

在Unity中,渲染线程是负责在屏幕上绘制图像的线程。在这个线程中,Unity会将场景中的游戏对象渲染成一个或多个纹理对象。然而,在渲染线程中直接访问OpenCV的Mat对象是不安全的,因为Mat对象的数据可能在渲染线程和主线程之间共享,这可能导致数据竞争和其他线程安全问题。

为了解决这个问题,MatToTextureInRenderThreadExample使用了多线程技术,将Mat对象的数据复制到一个临时的缓冲区中,并将缓冲区中的数据复制到Unity的纹理对象中。这样,就可以在渲染线程中安全地访问OpenCV的Mat对象,而不会对主线程或其他线程造成干扰。

该示例程序使用Unity的RenderTexture对象作为渲染目标,并使用OpenCVForUnity库中的MatToTexture函数将Mat对象的数据复制到一个临时的纹理对象中。然后,该示例程序使用Unity的Graphics.CopyTexture函数将临时纹理对象的数据复制到Unity的RenderTexture对象中。最后,该示例程序使用Unity的Graphics.Blit函数将RenderTexture对象的数据显示在屏幕上。

MatToTextureInRenderThreadExample是一个非常有用的示例程序,因为它演示了如何在Unity中使用OpenCV进行图像处理,并且确保了在多线程环境下安全地访问数据。

#if !(PLATFORM_LUMIN && !UNITY_EDITOR)using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;
using System.Collections;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.UnityUtils.Helper;
using OpenCVForUnity.ImgprocModule;namespace OpenCVForUnityExample
{/// <summary>/// Mat To Texture In RenderThread Example/// RenderThread 示例中的垫到纹理/// </summary>[RequireComponent(typeof(WebCamTextureToMatHelper))]public class MatToTextureInRenderThreadExample : MonoBehaviour{/// <summary>/// The requested resolution dropdown./// 请求的分辨率下拉列表。/// </summary>public Dropdown requestedResolutionDropdown;/// <summary>/// The requested resolution./// 要求的分辨率。/// </summary>public ResolutionPreset requestedResolution = ResolutionPreset._640x480;/// <summary>/// The requestedFPS dropdown./// 请求的 FPS 下拉列表。/// </summary>public Dropdown requestedFPSDropdown;/// <summary>/// The requestedFPS./// 请求的 FPS。/// </summary>public FPSPreset requestedFPS = FPSPreset._30;/// <summary>/// The rotate 90 degree toggle./// 旋转 90 度切换。/// </summary>public Toggle rotate90DegreeToggle;/// <summary>/// The flip vertical toggle./// 翻转垂直切换。/// </summary>public Toggle flipVerticalToggle;/// <summary>/// The flip horizontal toggle./// 翻转水平切换。/// </summary>public Toggle flipHorizontalToggle;/// <summary>/// The texture./// 纹理。/// </summary>Texture2D texture;/// <summary>/// The webcam texture to mat helper./// OpenCVForUnity库中提供的一个帮助类,用于在Unity中将WebCamTexture对象转换为OpenCV中的Mat对象。/// </summary>WebCamTextureToMatHelper webCamTextureToMatHelper;/// <summary>/// The FPS monitor./// 帧率监测器。/// </summary>FpsMonitor fpsMonitor;/// <summary>/// The rgba mat./// rgba矩阵。/// </summary>Mat rgbaMat;/// <summary>/// The render thread coroutine./// 渲染线程协同程序。/// </summary>IEnumerator renderThreadCoroutine;// Use this for initializationvoid Start(){
#if UNITY_WEBGL && !UNITY_EDITORUtils.registerWebGLPlugin();//用于在WebGL平台上注册OpenCVForUnity库的插件。
#endif//renderThreadCoroutine是一个协程对象,用于在Unity中启动一个协程,以便在渲染线程中执行一些任务。//CallAtEndOfFrames是一个私有方法,用于创建一个协程对象,并在渲染线程的每一帧结束时调用该协程对象。renderThreadCoroutine = CallAtEndOfFrames();fpsMonitor = GetComponent<FpsMonitor>();//获取了 FpsMonitor 组件,用于在游戏运行期间监视游戏的帧率。webCamTextureToMatHelper = gameObject.GetComponent<WebCamTextureToMatHelper>();//获取了 WebCamTextureToMatHelper 组件,用于在Unity中将WebCamTexture对象转换为OpenCV中的Mat对象。int width, height;Dimensions(requestedResolution, out width, out height);//计算出了requestedResolution参数所指定的分辨率对应的宽度和高度,并将它们存储在width和height变量中。webCamTextureToMatHelper.requestedWidth = width;webCamTextureToMatHelper.requestedHeight = height;webCamTextureToMatHelper.requestedFPS = (int)requestedFPS;//将requestedFPS转换为整数,并将其赋值给webCamTextureToMatHelper对象的requestedFPS属性,以指定所需的帧率。webCamTextureToMatHelper.Initialize();//调用Initialize方法初始化webCamTextureToMatHelper对象// Update GUI staterequestedResolutionDropdown.value = (int)requestedResolution;//请求的分辨率下拉列表初始化。string[] enumNames = System.Enum.GetNames(typeof(FPSPreset));//获取了FPSPreset枚举类型中所有元素的名称,并将它们存储在enumNames数组中。int index = Array.IndexOf(enumNames, requestedFPS.ToString());//使用Array.IndexOf方法查找requestedFPS参数在enumNames数组中的索引,并将该索引存储在index变量中。requestedFPSDropdown.value = index;//将index赋值给requestedFPSDropdown下拉列表控件的value属性。requestedFPSDropdown是一个Dropdown对象,用于显示可选的帧率。rotate90DegreeToggle.isOn = webCamTextureToMatHelper.rotate90Degree;//旋转90°切换的初始化flipVerticalToggle.isOn = webCamTextureToMatHelper.flipVertical;//数值翻转切换的初始化flipHorizontalToggle.isOn = webCamTextureToMatHelper.flipHorizontal;//水平切换翻转的初始化}/// <summary>/// Raises the webcam texture to mat helper initialized event./// 将网络摄像机纹理引发到mat helper初始化事件。/// </summary>public void OnWebCamTextureToMatHelperInitialized(){Debug.Log("OnWebCamTextureToMatHelperInitialized");Mat webCamTextureMat = webCamTextureToMatHelper.GetMat();//通过webCamTextureToMatHelper.GetMat()方法获取相机捕获的图像数据texture = new Texture2D(webCamTextureMat.cols(), webCamTextureMat.rows(), TextureFormat.RGBA32, false);Utils.matToTexture2D(webCamTextureMat, texture);//将OpenCV Mat格式的webCamTextureMat转换为Unity的Texture2D格式,并将其赋值给变量texture。gameObject.GetComponent<Renderer>().material.mainTexture = texture;//通过将Texture2D对象设置为GameObject的主纹理,可以将图像显示在屏幕上。gameObject.transform.localScale = new Vector3(webCamTextureMat.cols(), webCamTextureMat.rows(), 1);Debug.Log("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);if (fpsMonitor != null){fpsMonitor.Add("deviceName", webCamTextureToMatHelper.GetDeviceName().ToString());fpsMonitor.Add("width", webCamTextureToMatHelper.GetWidth().ToString());fpsMonitor.Add("height", webCamTextureToMatHelper.GetHeight().ToString());fpsMonitor.Add("videoRotationAngle", webCamTextureToMatHelper.GetWebCamTexture().videoRotationAngle.ToString());fpsMonitor.Add("videoVerticallyMirrored", webCamTextureToMatHelper.GetWebCamTexture().videoVerticallyMirrored.ToString());fpsMonitor.Add("isFrontFacing", webCamTextureToMatHelper.IsFrontFacing().ToString());fpsMonitor.Add("rotate90Degree", webCamTextureToMatHelper.rotate90Degree.ToString());fpsMonitor.Add("flipVertical", webCamTextureToMatHelper.flipVertical.ToString());fpsMonitor.Add("flipHorizontal", webCamTextureToMatHelper.flipHorizontal.ToString());fpsMonitor.Add("orientation", Screen.orientation.ToString());}/// <summary>/// 根据屏幕和图像的比例关系来调整相机的正交大小。/// </summary> //取Screen的宽度和高度,并计算屏幕与图像宽度和高度的比例(widthScale和heightScale)。float width = webCamTextureMat.width();float height = webCamTextureMat.height();float widthScale = (float)Screen.width / width;float heightScale = (float)Screen.height / height;if (widthScale < heightScale){Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;}else{Camera.main.orthographicSize = height / 2;}StartCoroutine(renderThreadCoroutine);//将之前创建的renderThreadCoroutine协程对象添加到渲染事件中,在每一帧结束时自动调用该对象,并在渲染线程中执行指定的任务。}/// <summary>/// Raises the webcam texture to mat helper disposed event./// 用于在webCamTextureToMatHelper对象被销毁时清理资源。/// </summary>public void OnWebCamTextureToMatHelperDisposed(){Debug.Log("OnWebCamTextureToMatHelperDisposed");StopCoroutine(renderThreadCoroutine);rgbaMat = null;if (texture != null){Texture2D.Destroy(texture);texture = null;}}/// <summary>/// Raises the webcam texture to mat helper error occurred event./// 将网络摄像机纹理提高到mat helper错误发生事件。/// </summary>/// <param name="errorCode">Error code.</param>public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.ErrorCode errorCode){Debug.Log("OnWebCamTextureToMatHelperErrorOccurred " + errorCode);}// Update is called once per framevoid Update(){if (webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame())//检查摄像头是否正在播放,并且当前帧是否已更新。如果满足条件,则进入下一行代码。{rgbaMat = webCamTextureToMatHelper.GetMat();//获取从摄像头捕获的图像数据,并将其存储在 rgbaMat 变量中。//Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false);//Utils.matToTexture2D (rgbaMat, texture);}}/// <summary>/// Calls at end of frames./// 用于在渲染线程的每一帧结束时执行一些任务。/// </summary>private IEnumerator CallAtEndOfFrames(){while (true)//无限循环{// Wait until all frame rendering is done// 等待所有帧渲染完成,等待下一帧的渲染结束后再继续执行协程。yield return new WaitForEndOfFrame();if (rgbaMat != null){//matToTextureInRenderThread方法是OpenCVForUnity库中的一个实用方法,用于将OpenCV的Mat对象转换为Unity的纹理对象,并在渲染线程中更新显示。//通过在渲染线程中更新显示,可以保证图像的流畅性和稳定性。Utils.matToTextureInRenderThread(rgbaMat, texture);//将rgbaMat转换为Unity的纹理对象,并将其更新到屏幕上。}}}/// <summary>/// Raises the destroy event./// </summary>void OnDestroy(){webCamTextureToMatHelper.Dispose();}/// <summary>/// Raises the back button click event./// </summary>public void OnBackButtonClick(){SceneManager.LoadScene("OpenCVForUnityExample");}/// <summary>/// Raises the play button click event./// </summary>public void OnPlayButtonClick(){webCamTextureToMatHelper.Play();}/// <summary>/// Raises the pause button click event./// </summary>public void OnPauseButtonClick(){webCamTextureToMatHelper.Pause();}/// <summary>/// Raises the stop button click event./// </summary>public void OnStopButtonClick(){webCamTextureToMatHelper.Stop();}/// <summary>/// Raises the change camera button click event./// </summary>public void OnChangeCameraButtonClick(){webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.requestedIsFrontFacing;}/// <summary>/// Raises the requested resolution dropdown value changed event./// 引发请求的分辨率下拉值更改事件。/// </summary>public void OnRequestedResolutionDropdownValueChanged(int result){if ((int)requestedResolution != result){requestedResolution = (ResolutionPreset)result;int width, height;Dimensions(requestedResolution, out width, out height);// 计算出了requestedResolution参数所指定的分辨率对应的宽度和高度,并将它们存储在width和height变量中。webCamTextureToMatHelper.Initialize(width, height);//使用width和height重新初始化webCamTextureToMatHelper}}/// <summary>/// Raises the requestedFPS dropdown value changed event./// 引发requestedFPS下拉值更改事件。/// </summary>public void OnRequestedFPSDropdownValueChanged(int result){string[] enumNames = Enum.GetNames(typeof(FPSPreset));int value = (int)System.Enum.Parse(typeof(FPSPreset), enumNames[result], true);if ((int)requestedFPS != value){requestedFPS = (FPSPreset)value;webCamTextureToMatHelper.requestedFPS = (int)requestedFPS;//使用requestedFPS重新初始化webCamTextureToMatHelper}}/// <summary>/// Raises the rotate 90 degree toggle value changed event./// 引发旋转90度切换值更改事件。/// </summary>public void OnRotate90DegreeToggleValueChanged(){if (rotate90DegreeToggle.isOn != webCamTextureToMatHelper.rotate90Degree){webCamTextureToMatHelper.rotate90Degree = rotate90DegreeToggle.isOn;//设置旋转90°,rotate90Degree的设置函数自动重新初始化 webCamTextureToMatHelper}if (fpsMonitor != null)fpsMonitor.Add("rotate90Degree", webCamTextureToMatHelper.rotate90Degree.ToString());}/// <summary>/// Raises the flip vertical toggle value changed event/// .引发翻转垂直切换值更改事件。/// </summary>public void OnFlipVerticalToggleValueChanged(){if (flipVerticalToggle.isOn != webCamTextureToMatHelper.flipVertical){webCamTextureToMatHelper.flipVertical = flipVerticalToggle.isOn;//设置竖直翻转, webCamTextureToMatHelper不初始化}if (fpsMonitor != null)fpsMonitor.Add("flipVertical", webCamTextureToMatHelper.flipVertical.ToString());}/// <summary>/// Raises the flip horizontal toggle value changed event./// 引发翻转水平切换值更改事件。/// </summary>public void OnFlipHorizontalToggleValueChanged(){if (flipHorizontalToggle.isOn != webCamTextureToMatHelper.flipHorizontal){webCamTextureToMatHelper.flipHorizontal = flipHorizontalToggle.isOn;//设置水平翻转,webCamTextureToMatHelper不初始化}if (fpsMonitor != null)fpsMonitor.Add("flipHorizontal", webCamTextureToMatHelper.flipHorizontal.ToString());}//帧率预设枚举public enum FPSPreset : int{_0 = 0,_1 = 1,_5 = 5,_10 = 10,_15 = 15,_30 = 30,_60 = 60,}//分辨率预设枚举public enum ResolutionPreset : byte{_50x50 = 0,_640x480,_1280x720,_1920x1080,_9999x9999,}//由帧率预设枚举转换为矩阵的宽度和高度private void Dimensions(ResolutionPreset preset, out int width, out int height){switch (preset){case ResolutionPreset._50x50:width = 50;height = 50;break;case ResolutionPreset._640x480:width = 640;height = 480;break;case ResolutionPreset._1280x720:width = 1280;height = 720;break;case ResolutionPreset._1920x1080:width = 1920;height = 1080;break;case ResolutionPreset._9999x9999:width = 9999;height = 9999;break;default:width = height = 0;break;}}}
}#endif

http://www.ppmy.cn/news/245722.html

相关文章

OpenCVForUnity之DocumentScannerExample

DocumentScannerExample是OpenCVForUnity库的一个示例场景&#xff0c;用于演示如何使用OpenCVForUnity库实现文档扫描器应用程序。文档扫描器应用程序是一种常见的应用程序&#xff0c;它可以将纸质文档转换为数字格式&#xff0c;并进行后续处理和存储。 在DocumentScannerE…

OpenCVForUnity之KeyFrameGreenScreenExample

KeyFrameGreenScreenExample是一个演示如何使用OpenCVForUnity库和Unity引擎实现绿幕抠像的示例项目。该项目使用了多张图像作为关键帧&#xff0c;并通过对关键帧进行透视变换和色彩校正等操作&#xff0c;将绿幕背景替换为指定的背景图像。 具体来说&#xff0c;KeyFrameGre…

Unity立方体六个面不同贴图

可用Unity官方材质&#xff1a;skybox下的Cubemap&#xff1a; 但是&#xff0c;有些面没有渲染上&#xff1a; 原因在于官方Shader里面的Cull off&#xff0c;将其改为Cull back就好了&#xff0c;或者ZWrite Off改为ZWrite On。附上代码&#xff1a; Shader "Custom…

2021/4/21日记

总文 今天早上下了蒙蒙的小雨&#xff0c;昨晚孙帅说早上要训练女篮&#xff0c;如果我去他就跟我拍几个抖音小视频&#xff0c;然后因为昨晚看缘之空看的很晚&#xff0c;而且好像被子厚了&#xff0c;盖着特别的燥热&#xff0c;也睡不着&#xff0c;早上我朦胧中记得孟佩豪来…

OpenCVForUnity之Comic Filter Example

首先打开场景定位到主脚本&#xff1a;ComicFilterExample&#xff0c;然后定位到主函数&#xff1a;Update&#xff0c;会发现他首先把摄像头mat取出来&#xff0c;再用cvtColor函数将rgba转gray参考&#xff1a;https://blog.csdn.net/keith_bb/article/details/53470170 先…

Galgame研发日志:预算爆炸,问题不大

很多独立游戏制作路上遇到的问题&#xff0c;说到底就是钱的事儿&#xff0c;之所以这些问题成为问题&#xff0c;原因多半是没钱&#xff0c;今天就来谈谈关于游戏制作当中找钱和用钱的事儿。刚开始gal制作的事情&#xff0c;我初步定了一个40万的预算&#xff0c;不算高&…

轻音乐集锦

我相信好的轻音乐能修身养性&#xff0c;对人的性格塑造影响比较大的。本人这几年收集了一些轻音乐&#xff0c;在这里分享一下。我下面介绍的曲子会有少量背景音乐、电影插曲、新世纪音乐、还有一些钢琴曲。分类比较粗糙&#xff0c;希望能耐心看完。这些音乐的特点都是轻柔的…

动漫迷看的一点动漫

个人看过的动漫 (注&#xff1a;排名不分先后) 宗旨&#xff1a;技术的学习是有限的&#xff0c;分享的精神是无限的。 1、魔法科高中的劣等生&#xff1a;国立魔法大学附属第一高校——通称“魔法科高校”&#xff0c;是由成绩优秀的“一科生”&#xff0c;和作为一科生替补的…