11using DlibFaceLandmarkDetector ;
22using DlibFaceLandmarkDetector . UnityUtils ;
33using System ;
4- using System . Collections ;
54using System . Collections . Generic ;
5+ using System . Threading ;
66using UnityEngine ;
77using UnityEngine . SceneManagement ;
8+ using UnityEngine . UI ;
89
910namespace DlibFaceLandmarkDetectorExample
1011{
@@ -13,6 +14,14 @@ namespace DlibFaceLandmarkDetectorExample
1314 /// </summary>
1415 public class BenchmarkExample : MonoBehaviour
1516 {
17+ [ Header ( "Output" ) ]
18+ /// <summary>
19+ /// The RawImage for previewing the result.
20+ /// </summary>
21+ public RawImage resultPreview ;
22+
23+ [ Space ( 10 ) ]
24+
1625 /// <summary>
1726 /// The number of benchmark times.
1827 /// </summary>
@@ -44,29 +53,35 @@ public class BenchmarkExample : MonoBehaviour
4453 /// </summary>
4554 FpsMonitor fpsMonitor ;
4655
47- #if UNITY_WEBGL
48- IEnumerator getFilePath_Coroutine ;
49- #endif
56+ /// <summary>
57+ /// The CancellationTokenSource.
58+ /// </summary>
59+ CancellationTokenSource cts = new CancellationTokenSource ( ) ;
60+
61+ public enum DetectMode
62+ {
63+ None ,
64+ ValueTuple ,
65+ NoAlloc
66+ }
5067
5168 // Use this for initialization
52- void Start ( )
69+ async void Start ( )
5370 {
5471 fpsMonitor = GetComponent < FpsMonitor > ( ) ;
5572
5673 dlibShapePredictorFileName = DlibFaceLandmarkDetectorExample . dlibShapePredictorFileName ;
57- #if UNITY_WEBGL
58- getFilePath_Coroutine = Utils . getFilePathAsync ( dlibShapePredictorFileName , ( result ) =>
59- {
60- getFilePath_Coroutine = null ;
6174
62- dlibShapePredictorFilePath = result ;
63- Run ( ) ;
64- } ) ;
65- StartCoroutine ( getFilePath_Coroutine ) ;
66- #else
67- dlibShapePredictorFilePath = Utils . getFilePath ( dlibShapePredictorFileName ) ;
75+ // Asynchronously retrieves the readable file path from the StreamingAssets directory.
76+ if ( fpsMonitor != null )
77+ fpsMonitor . consoleText = "Preparing file access..." ;
78+
79+ dlibShapePredictorFilePath = await Utils . getFilePathAsyncTask ( dlibShapePredictorFileName , cancellationToken : cts . Token ) ;
80+
81+ if ( fpsMonitor != null )
82+ fpsMonitor . consoleText = "" ;
83+
6884 Run ( ) ;
69- #endif
7085 }
7186
7287 private void Run ( )
@@ -83,22 +98,33 @@ private void Run()
8398 + " If you want to draw the result correctly, we recommend using the OpenCVForUnityUtils.DrawFaceLandmark method." ) ;
8499 }
85100
86- private void StartBenchmark ( Texture2D targetImg , FaceLandmarkDetector detector , int times = 100 , bool noAlloc = false )
101+ private void StartBenchmark ( Texture2D targetImg , FaceLandmarkDetector detector , int times = 100 , DetectMode detectMode = DetectMode . None )
87102 {
88- string result = noAlloc ? BenchmarkNoGCAlloc ( targetImg , detector , times ) : Benchmark ( targetImg , detector , times ) ;
89- Debug . Log ( result ) ;
90- if ( fpsMonitor != null )
103+ string result = null ;
104+ switch ( detectMode )
91105 {
92- fpsMonitor . consoleText = result ;
106+ case DetectMode . None :
107+ result = Benchmark ( targetImg , detector , times ) ;
108+ Debug . Log ( result ) ;
109+ ShowImage ( targetImg ) ;
110+ break ;
111+ case DetectMode . ValueTuple :
112+ result = BenchmarkValueTuple ( targetImg , detector , times ) ;
113+ Debug . Log ( result ) ;
114+ ShowImageValueTuple ( targetImg ) ;
115+ break ;
116+ case DetectMode . NoAlloc :
117+ result = BenchmarkNoGCAlloc ( targetImg , detector , times ) ;
118+ Debug . Log ( result ) ;
119+ ShowImageNoGCAlloc ( targetImg ) ;
120+ break ;
121+ default :
122+ break ;
93123 }
94124
95- if ( noAlloc )
96- {
97- ShowImageNoGCAlloc ( targetImg ) ;
98- }
99- else
125+ if ( fpsMonitor != null )
100126 {
101- ShowImage ( targetImg ) ;
127+ fpsMonitor . consoleText = result ;
102128 }
103129 }
104130
@@ -142,6 +168,46 @@ private string Benchmark(Texture2D targetImg, FaceLandmarkDetector detector, int
142168 return result ;
143169 }
144170
171+ private string BenchmarkValueTuple ( Texture2D targetImg , FaceLandmarkDetector detector , int times = 100 )
172+ {
173+ System . Diagnostics . Stopwatch sw = new System . Diagnostics . Stopwatch ( ) ;
174+
175+ string result = "sp_name: " + dlibShapePredictorFileName + "\n " ;
176+ result += "times: " + times + " (size: " + targetImg . width + "*" + targetImg . height + ")" + "\n " ;
177+
178+ detector . SetImage ( targetImg ) ;
179+
180+ // FaceLandmarkDetector.Detect() benchmark.
181+ sw . Start ( ) ;
182+ UnityEngine . Profiling . Profiler . BeginSample ( "GCAllocTest: DetectValueTuple()" ) ;
183+ for ( int i = 0 ; i < times ; ++ i )
184+ {
185+ detector . DetectValueTuple ( ) ;
186+ }
187+ UnityEngine . Profiling . Profiler . EndSample ( ) ;
188+ sw . Stop ( ) ;
189+ result += " Detect(): " + sw . ElapsedMilliseconds + "ms" + " Avg:" + sw . ElapsedMilliseconds / times + "ms" + "\n " ;
190+
191+
192+ // FaceLandmarkDetector.DetectLandmark() benchmark.
193+ ( double x , double y , double width , double height ) [ ] detectResult = detector . DetectValueTuple ( ) ;
194+ sw . Reset ( ) ;
195+ sw . Start ( ) ;
196+ UnityEngine . Profiling . Profiler . BeginSample ( "GCAllocTest: DetectLandmark()" ) ;
197+ for ( int i = 0 ; i < times ; ++ i )
198+ {
199+ foreach ( var rect in detectResult )
200+ {
201+ detector . DetectLandmark ( rect ) ;
202+ }
203+ }
204+ UnityEngine . Profiling . Profiler . EndSample ( ) ;
205+ sw . Stop ( ) ;
206+ result += " DetectLandmark(): " + sw . ElapsedMilliseconds + "ms" + " Avg:" + sw . ElapsedMilliseconds / times + "ms" ;
207+
208+ return result ;
209+ }
210+
145211 private string BenchmarkNoGCAlloc ( Texture2D targetImg , FaceLandmarkDetector detector , int times = 100 )
146212 {
147213 System . Diagnostics . Stopwatch sw = new System . Diagnostics . Stopwatch ( ) ;
@@ -169,7 +235,7 @@ private string BenchmarkNoGCAlloc(Texture2D targetImg, FaceLandmarkDetector dete
169235 UnityEngine . Profiling . Profiler . EndSample ( ) ;
170236 sw . Stop ( ) ;
171237 result += " Detect(): " + sw . ElapsedMilliseconds + "ms" + " Avg:" + sw . ElapsedMilliseconds / times + "ms" + "\n " ;
172-
238+
173239
174240 // FaceLandmarkDetector.DetectLandmark() benchmark.
175241 int detectLandmarkCount = detector . DetectLandmarkOnly ( detectResult [ 0 ] , detectResult [ 1 ] , detectResult [ 2 ] , detectResult [ 3 ] ) ;
@@ -205,22 +271,6 @@ private void ShowImage(Texture2D texture2D)
205271 dstTexture2D . SetPixels32 ( texture2D . GetPixels32 ( ) ) ;
206272 dstTexture2D . Apply ( ) ;
207273
208- gameObject . transform . localScale = new Vector3 ( texture2D . width , texture2D . height , 1 ) ;
209-
210- float width = gameObject . transform . localScale . x ;
211- float height = gameObject . transform . localScale . y ;
212-
213- float widthScale = ( float ) Screen . width / width ;
214- float heightScale = ( float ) Screen . height / height ;
215- if ( widthScale < heightScale )
216- {
217- Camera . main . orthographicSize = ( width * ( float ) Screen . height / ( float ) Screen . width ) / 2 ;
218- }
219- else
220- {
221- Camera . main . orthographicSize = height / 2 ;
222- }
223-
224274 faceLandmarkDetector . SetImage ( texture2D ) ;
225275
226276 //detect face rects
@@ -237,33 +287,46 @@ private void ShowImage(Texture2D texture2D)
237287 // draw face rect
238288 faceLandmarkDetector . DrawDetectResult ( dstTexture2D , 255 , 0 , 0 , 255 , 2 ) ;
239289
240- gameObject . GetComponent < Renderer > ( ) . material . mainTexture = dstTexture2D ;
290+ resultPreview . texture = dstTexture2D ;
291+ resultPreview . GetComponent < AspectRatioFitter > ( ) . aspectRatio = ( float ) dstTexture2D . width / dstTexture2D . height ;
241292 }
242293
243- private void ShowImageNoGCAlloc ( Texture2D texture2D )
294+ private void ShowImageValueTuple ( Texture2D texture2D )
244295 {
245296 if ( dstTexture2D != null )
246297 Texture2D . Destroy ( dstTexture2D ) ;
247298 dstTexture2D = new Texture2D ( texture2D . width , texture2D . height , texture2D . format , false ) ;
248299 dstTexture2D . SetPixels32 ( texture2D . GetPixels32 ( ) ) ;
249300 dstTexture2D . Apply ( ) ;
250301
251- gameObject . transform . localScale = new Vector3 ( texture2D . width , texture2D . height , 1 ) ;
302+ faceLandmarkDetector . SetImage ( texture2D ) ;
252303
253- float width = gameObject . transform . localScale . x ;
254- float height = gameObject . transform . localScale . y ;
304+ //detect face rects
305+ ( double x , double y , double width , double height ) [ ] detectResult = faceLandmarkDetector . DetectValueTuple ( ) ;
255306
256- float widthScale = ( float ) Screen . width / width ;
257- float heightScale = ( float ) Screen . height / height ;
258- if ( widthScale < heightScale )
259- {
260- Camera . main . orthographicSize = ( width * ( float ) Screen . height / ( float ) Screen . width ) / 2 ;
261- }
262- else
307+ foreach ( var rect in detectResult )
263308 {
264- Camera . main . orthographicSize = height / 2 ;
309+ //detect landmark points
310+ faceLandmarkDetector . DetectLandmark ( rect ) ;
311+ // draw landmark points
312+ faceLandmarkDetector . DrawDetectLandmarkResult ( dstTexture2D , 0 , 255 , 0 , 255 ) ;
265313 }
266314
315+ // draw face rect
316+ faceLandmarkDetector . DrawDetectResult ( dstTexture2D , 255 , 0 , 0 , 255 , 2 ) ;
317+
318+ resultPreview . texture = dstTexture2D ;
319+ resultPreview . GetComponent < AspectRatioFitter > ( ) . aspectRatio = ( float ) dstTexture2D . width / dstTexture2D . height ;
320+ }
321+
322+ private void ShowImageNoGCAlloc ( Texture2D texture2D )
323+ {
324+ if ( dstTexture2D != null )
325+ Texture2D . Destroy ( dstTexture2D ) ;
326+ dstTexture2D = new Texture2D ( texture2D . width , texture2D . height , texture2D . format , false ) ;
327+ dstTexture2D . SetPixels32 ( texture2D . GetPixels32 ( ) ) ;
328+ dstTexture2D . Apply ( ) ;
329+
267330 faceLandmarkDetector . SetImage ( texture2D ) ;
268331
269332 //detect face rects
@@ -294,7 +357,8 @@ private void ShowImageNoGCAlloc(Texture2D texture2D)
294357 // draw face rect
295358 faceLandmarkDetector . DrawDetectResult ( dstTexture2D , 255 , 0 , 0 , 255 , 2 ) ;
296359
297- gameObject . GetComponent < Renderer > ( ) . material . mainTexture = dstTexture2D ;
360+ resultPreview . texture = dstTexture2D ;
361+ resultPreview . GetComponent < AspectRatioFitter > ( ) . aspectRatio = ( float ) dstTexture2D . width / dstTexture2D . height ;
298362 }
299363
300364 // Update is called once per frame
@@ -314,13 +378,8 @@ void OnDisable()
314378 if ( faceLandmarkDetector != null )
315379 faceLandmarkDetector . Dispose ( ) ;
316380
317- #if UNITY_WEBGL
318- if ( getFilePath_Coroutine != null )
319- {
320- StopCoroutine ( getFilePath_Coroutine ) ;
321- ( ( IDisposable ) getFilePath_Coroutine ) . Dispose ( ) ;
322- }
323- #endif
381+ if ( cts != null )
382+ cts . Dispose ( ) ;
324383 }
325384
326385 /// <summary>
@@ -345,6 +404,28 @@ public void OnBenchmarkLargeImageButtonClick()
345404 StartBenchmark ( largeImage , faceLandmarkDetector , times ) ;
346405 }
347406
407+ /// <summary>
408+ /// Raises the benchmark small mage button click event.
409+ /// </summary>
410+ public void OnBenchmarkValueTupleSmallImageButtonClick ( )
411+ {
412+ if ( faceLandmarkDetector == null )
413+ return ;
414+
415+ StartBenchmark ( smallImage , faceLandmarkDetector , times , DetectMode . ValueTuple ) ;
416+ }
417+
418+ /// <summary>
419+ /// Raises the benchmark large image button click event.
420+ /// </summary>
421+ public void OnBenchmarkValueTupleLargeImageButtonClick ( )
422+ {
423+ if ( faceLandmarkDetector == null )
424+ return ;
425+
426+ StartBenchmark ( largeImage , faceLandmarkDetector , times , DetectMode . ValueTuple ) ;
427+ }
428+
348429 /// <summary>
349430 /// Raises the benchmark small mage button click event.
350431 /// </summary>
@@ -353,7 +434,7 @@ public void OnBenchmarkNoGCAllocSmallImageButtonClick()
353434 if ( faceLandmarkDetector == null )
354435 return ;
355436
356- StartBenchmark ( smallImage , faceLandmarkDetector , times , true ) ;
437+ StartBenchmark ( smallImage , faceLandmarkDetector , times , DetectMode . NoAlloc ) ;
357438 }
358439
359440 /// <summary>
@@ -364,7 +445,7 @@ public void OnBenchmarkNoGCAllocLargeImageButtonClick()
364445 if ( faceLandmarkDetector == null )
365446 return ;
366447
367- StartBenchmark ( largeImage , faceLandmarkDetector , times , true ) ;
448+ StartBenchmark ( largeImage , faceLandmarkDetector , times , DetectMode . NoAlloc ) ;
368449 }
369450
370451 /// <summary>
0 commit comments