1+ using OpenCVForUnity . CoreModule ;
2+ using OpenCVForUnity . ImgprocModule ;
3+ using OpenCVForUnity . UnityUtils ;
4+ using RenderHeads . Media . AVProLiveCamera ;
5+ using UnityEngine ;
6+ using UnityEngine . Experimental . Rendering ;
7+ using UnityEngine . Rendering ;
8+ using UnityEngine . SceneManagement ;
9+ using UnityEngine . UI ;
10+
11+ namespace AVProWithOpenCVForUnityExample
12+ {
13+ /// <summary>
14+ /// AVProLiveCamera AsyncGPUReadback Example
15+ /// An example of converting an AVProLiveCamera image frame to an OpenCV Mat using AsyncGPUReadback.
16+ /// </summary>
17+ public class AVProLiveCameraAsyncGPUReadbackExample : MonoBehaviour
18+ {
19+ public AVProLiveCamera _camera ;
20+ private AVProLiveCameraDevice _device ;
21+
22+ private int _frameWidth ;
23+ private int _frameHeight ;
24+ private uint _lastFrame ;
25+
26+ private bool _graphicsFormatIsFormatSupported ;
27+
28+ /// <summary>
29+ /// The texture.
30+ /// </summary>
31+ Texture2D texture ;
32+
33+ /// <summary>
34+ /// The rgba mat.
35+ /// </summary>
36+ Mat rgbaMat ;
37+
38+ /// <summary>
39+ /// The m sepia kernel.
40+ /// </summary>
41+ Mat mSepiaKernel ;
42+
43+ /// <summary>
44+ /// The m size0.
45+ /// </summary>
46+ Size mSize0 ;
47+
48+ /// <summary>
49+ /// The m intermediate mat.
50+ /// </summary>
51+ Mat mIntermediateMat ;
52+
53+ public enum modeType
54+ {
55+ original ,
56+ sepia ,
57+ pixelize ,
58+ }
59+
60+ /// <summary>
61+ /// The mode.
62+ /// </summary>
63+ modeType mode ;
64+
65+
66+ /// <summary>
67+ /// The original mode toggle.
68+ /// </summary>
69+ public Toggle originalModeToggle ;
70+
71+
72+ /// <summary>
73+ /// The sepia mode toggle.
74+ /// </summary>
75+ public Toggle sepiaModeToggle ;
76+
77+
78+ /// <summary>
79+ /// The pixelize mode toggle.
80+ /// </summary>
81+ public Toggle pixelizeModeToggle ;
82+
83+ // Use this for initialization
84+ void Start ( )
85+ {
86+ if ( originalModeToggle . isOn )
87+ {
88+ mode = modeType . original ;
89+ }
90+ if ( sepiaModeToggle . isOn )
91+ {
92+ mode = modeType . sepia ;
93+ }
94+ if ( pixelizeModeToggle . isOn )
95+ {
96+ mode = modeType . pixelize ;
97+ }
98+
99+ // sepia
100+ mSepiaKernel = new Mat ( 4 , 4 , CvType . CV_32F ) ;
101+ mSepiaKernel . put ( 0 , 0 , /* R */ 0.189f , 0.769f , 0.393f , 0f ) ;
102+ mSepiaKernel . put ( 1 , 0 , /* G */ 0.168f , 0.686f , 0.349f , 0f ) ;
103+ mSepiaKernel . put ( 2 , 0 , /* B */ 0.131f , 0.534f , 0.272f , 0f ) ;
104+ mSepiaKernel . put ( 3 , 0 , /* A */ 0.000f , 0.000f , 0.000f , 1f ) ;
105+
106+
107+ // pixelize
108+ mIntermediateMat = new Mat ( ) ;
109+ mSize0 = new Size ( ) ;
110+ }
111+
112+ void Update ( )
113+ {
114+ if ( _camera != null )
115+ _device = _camera . Device ;
116+
117+ if ( _device != null && _device . IsActive && ! _device . IsPaused && _device . OutputTexture != null )
118+ {
119+ if ( _device . CurrentWidth != _frameWidth || _device . CurrentHeight != _frameHeight )
120+ {
121+ CreateBuffer ( _device . CurrentWidth , _device . CurrentHeight ) ;
122+ }
123+
124+ uint lastFrame = AVProLiveCameraPlugin . GetLastFrame ( _device . DeviceIndex ) ;
125+
126+ // Reset _lastFrame at the timing when the camera is reset.
127+ if ( lastFrame < _lastFrame )
128+ _lastFrame = 0 ;
129+
130+ if ( lastFrame != _lastFrame )
131+ {
132+ _lastFrame = lastFrame ;
133+
134+ //Debug.Log("FrameReady " + lastFrame);
135+
136+ if ( _graphicsFormatIsFormatSupported )
137+ {
138+ AsyncGPUReadback . Request ( _device . OutputTexture , 0 , TextureFormat . RGBA32 , ( request ) => { OnCompleteReadback ( request , lastFrame ) ; } ) ;
139+ }
140+ }
141+ }
142+ }
143+
144+ void OnCompleteReadback ( AsyncGPUReadbackRequest request , long frameIndex )
145+ {
146+
147+ if ( request . hasError )
148+ {
149+ Debug . Log ( "GPU readback error detected. " + frameIndex ) ;
150+
151+ }
152+ else if ( request . done )
153+ {
154+ //Debug.Log("Start GPU readback done. "+frameIndex);
155+
156+ //Debug.Log("Thread.CurrentThread.ManagedThreadId " + Thread.CurrentThread.ManagedThreadId);
157+
158+ MatUtils . copyToMat ( request . GetData < byte > ( ) , rgbaMat ) ;
159+
160+ Core . flip ( rgbaMat , rgbaMat , 0 ) ;
161+
162+
163+ if ( mode == modeType . original )
164+ {
165+
166+ }
167+ else if ( mode == modeType . sepia )
168+ {
169+
170+ Core . transform ( rgbaMat , rgbaMat , mSepiaKernel ) ;
171+
172+ }
173+ else if ( mode == modeType . pixelize )
174+ {
175+
176+ Imgproc . resize ( rgbaMat , mIntermediateMat , mSize0 , 0.1 , 0.1 , Imgproc . INTER_NEAREST ) ;
177+ Imgproc . resize ( mIntermediateMat , rgbaMat , rgbaMat . size ( ) , 0.0 , 0.0 , Imgproc . INTER_NEAREST ) ;
178+
179+ }
180+
181+
182+ Imgproc . putText ( rgbaMat , "AVPro With OpenCV for Unity Example" , new Point ( 50 , rgbaMat . rows ( ) / 2 ) , Imgproc . FONT_HERSHEY_SIMPLEX , 2.0 , new Scalar ( 255 , 0 , 0 , 255 ) , 5 , Imgproc . LINE_AA , false ) ;
183+ 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 ) ;
184+
185+ //Convert Mat to Texture2D
186+ Utils . matToTexture2D ( rgbaMat , texture ) ;
187+
188+ //Debug.Log("End GPU readback done. " + frameIndex);
189+
190+ }
191+ }
192+
193+ private void CreateBuffer ( int width , int height )
194+ {
195+ _frameWidth = width ;
196+ _frameHeight = height ;
197+
198+ texture = new Texture2D ( _frameWidth , _frameHeight , TextureFormat . RGBA32 , false , false ) ;
199+
200+ rgbaMat = new Mat ( texture . height , texture . width , CvType . CV_8UC4 ) ;
201+
202+
203+ gameObject . GetComponent < Renderer > ( ) . material . mainTexture = texture ;
204+
205+ gameObject . transform . localScale = new Vector3 ( texture . width , texture . height , 1 ) ;
206+ Debug . Log ( "Screen.width " + Screen . width + " Screen.height " + Screen . height + " Screen.orientation " + Screen . orientation ) ;
207+
208+ float widthScale = ( float ) Screen . width / width ;
209+ float heightScale = ( float ) Screen . height / height ;
210+ if ( widthScale < heightScale )
211+ {
212+ Camera . main . orthographicSize = ( width * ( float ) Screen . height / ( float ) Screen . width ) / 2 ;
213+ }
214+ else
215+ {
216+ Camera . main . orthographicSize = height / 2 ;
217+ }
218+
219+
220+ _graphicsFormatIsFormatSupported = SystemInfo . IsFormatSupported ( _device . OutputTexture . graphicsFormat , FormatUsage . ReadPixels ) ;
221+
222+ if ( ! _graphicsFormatIsFormatSupported )
223+ {
224+ Imgproc . rectangle ( rgbaMat , new OpenCVForUnity . CoreModule . Rect ( 0 , 0 , rgbaMat . width ( ) , rgbaMat . height ( ) ) , new Scalar ( 0 , 0 , 0 , 255 ) , - 1 ) ;
225+ Imgproc . putText ( rgbaMat , _device . OutputTexture . graphicsFormat + " is not supported for AsyncGPUReadback." , new Point ( 5 , rgbaMat . rows ( ) - 10 ) , Imgproc . FONT_HERSHEY_SIMPLEX , 1.0 , new Scalar ( 255 , 255 , 255 , 255 ) , 2 , Imgproc . LINE_AA , false ) ;
226+
227+ Utils . matToTexture2D ( rgbaMat , texture ) ;
228+ }
229+ }
230+
231+ private void FreeBuffer ( )
232+ {
233+ if ( texture )
234+ {
235+ Texture2D . DestroyImmediate ( texture ) ;
236+ texture = null ;
237+ }
238+
239+ if ( rgbaMat != null )
240+ rgbaMat . Dispose ( ) ;
241+ }
242+
243+ void OnDestroy ( )
244+ {
245+ AsyncGPUReadback . WaitAllRequests ( ) ;
246+
247+ FreeBuffer ( ) ;
248+
249+ if ( mSepiaKernel != null )
250+ {
251+ mSepiaKernel . Dispose ( ) ;
252+ mSepiaKernel = null ;
253+ }
254+
255+ if ( mIntermediateMat != null )
256+ {
257+ mIntermediateMat . Dispose ( ) ;
258+ mIntermediateMat = null ;
259+ }
260+ }
261+
262+ /// <summary>
263+ /// Raises the back button event.
264+ /// </summary>
265+ public void OnBackButton ( )
266+ {
267+ SceneManager . LoadScene ( "AVProWithOpenCVForUnityExample" ) ;
268+ }
269+
270+ /// <summary>
271+ /// Raises the original mode toggle event.
272+ /// </summary>
273+ public void OnOriginalModeToggle ( )
274+ {
275+
276+ if ( originalModeToggle . isOn )
277+ {
278+ mode = modeType . original ;
279+ }
280+ }
281+
282+ /// <summary>
283+ /// Raises the sepia mode toggle event.
284+ /// </summary>
285+ public void OnSepiaModeToggle ( )
286+ {
287+
288+ if ( sepiaModeToggle . isOn )
289+ {
290+ mode = modeType . sepia ;
291+ }
292+ }
293+
294+ /// <summary>
295+ /// Raises the pixelize mode toggle event.
296+ /// </summary>
297+ public void OnPixelizeModeToggle ( )
298+ {
299+
300+ if ( pixelizeModeToggle . isOn )
301+ {
302+ mode = modeType . pixelize ;
303+ }
304+ }
305+ }
306+ }
0 commit comments