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