Skip to content

Commit

Permalink
feat: FaceDetector Sample
Browse files Browse the repository at this point in the history
  • Loading branch information
homuler committed Jul 29, 2023
1 parent 4ef3f28 commit b652f11
Show file tree
Hide file tree
Showing 11 changed files with 1,407 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ public ImageFrame BuildImageFrame()
return new ImageFrame(imageFormat, width, height, 4 * width, GetRawTextureData<byte>());
}

public Image BuildCPUImage()
{
return new Image(imageFormat, width, height, 4 * width, GetRawTextureData<byte>());
}

public GpuBuffer BuildGpuBuffer(GlContext glContext)
{
#if UNITY_EDITOR_LINUX || UNITY_STANDALONE_LINUX || UNITY_ANDROID
Expand Down
107 changes: 107 additions & 0 deletions Assets/MediaPipeUnity/Samples/Common/Scripts/TaskApiRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) 2023 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System;
using System.Collections;
using UnityEngine;

using Stopwatch = System.Diagnostics.Stopwatch;

namespace Mediapipe.Unity
{
public abstract class TaskApiRunner : MonoBehaviour
{
#pragma warning disable IDE1006
// TODO: make it static
protected virtual string TAG => GetType().Name;
#pragma warning restore IDE1006

public Bootstrap bootstrap;
protected bool isPaused;

private readonly Stopwatch _stopwatch = new();

protected virtual IEnumerator Start()
{
bootstrap = FindBootstrap();
yield return new WaitUntil(() => bootstrap.isFinished);

Play();
}

/// <summary>
/// Start the main program from the beginning.
/// </summary>
public virtual void Play()
{
isPaused = false;
_stopwatch.Restart();
}

/// <summary>
/// Pause the main program.
/// <summary>
public virtual void Pause()
{
isPaused = true;
}

/// <summary>
/// Resume the main program.
/// If the main program has not begun, it'll do nothing.
/// </summary>
public virtual void Resume()
{
isPaused = false;
}

/// <summary>
/// Stops the main program.
/// </summary>
public virtual void Stop()
{
isPaused = true;
_stopwatch.Stop();
}

private long GetCurrentTimestampMicrosec()
{
return _stopwatch.IsRunning ? -1 : _stopwatch.ElapsedTicks / (TimeSpan.TicksPerMillisecond / 1000);
}

protected Timestamp GetCurrentTimestamp()
{
var microsec = GetCurrentTimestampMicrosec();
return microsec < 0 ? Timestamp.Unset() : new Timestamp(microsec);
}

protected Bootstrap FindBootstrap()
{
var bootstrapObj = GameObject.Find("Bootstrap");

if (bootstrapObj != null)
{
return bootstrapObj.GetComponent<Bootstrap>();
}

Logger.LogWarning(TAG, "Global Bootstrap instance is not found (maybe running a sample scene directly), "
+ "so activating a fallback Bootstrap instance attached to each Solution object");

var bootstrap = GetComponent<Bootstrap>();
bootstrap.enabled = true;

// hide menu button when trying a single scene.
DisableMenuButton();
return bootstrap;
}

private void DisableMenuButton()
{
var menuButton = GameObject.Find("MenuButton");
menuButton.SetActive(false);
}
}
}
11 changes: 11 additions & 0 deletions Assets/MediaPipeUnity/Samples/Common/Scripts/TaskApiRunner.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) 2021 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

using System.Collections;
using UnityEngine;

namespace Mediapipe.Unity
{
public abstract class VisionTaskApiRunner : TaskApiRunner
{
[SerializeField] protected Screen screen;

private Coroutine _coroutine;

public RunningMode runningMode;

public override void Play()
{
if (_coroutine != null)
{
Stop();
}
base.Play();
_coroutine = StartCoroutine(Run());
}

public override void Pause()
{
base.Pause();
ImageSourceProvider.ImageSource.Pause();
}

public override void Resume()
{
base.Resume();
var _ = StartCoroutine(ImageSourceProvider.ImageSource.Resume());
}

public override void Stop()
{
base.Stop();
StopCoroutine(_coroutine);
ImageSourceProvider.ImageSource.Stop();
}

protected abstract IEnumerator Run();

protected virtual void SetupScreen(ImageSource imageSource)
{
// NOTE: The screen will be resized later, keeping the aspect ratio.
screen.Initialize(imageSource);
}

protected virtual void RenderCurrentFrame(TextureFrame textureFrame)
{
screen.ReadSync(textureFrame);
}

protected static void ReadFromImageSource(ImageSource imageSource, TextureFrame textureFrame)
{
var sourceTexture = imageSource.GetCurrentTexture();

// For some reason, when the image is coiped on GPU, latency tends to be high.
// So even when OpenGL ES is available, use CPU to copy images.
var textureType = sourceTexture.GetType();

if (textureType == typeof(WebCamTexture))
{
textureFrame.ReadTextureFromOnCPU((WebCamTexture)sourceTexture);
}
else if (textureType == typeof(Texture2D))
{
textureFrame.ReadTextureFromOnCPU((Texture2D)sourceTexture);
}
else
{
textureFrame.ReadTextureFromOnCPU(sourceTexture);
}
}

protected static void SetupAnnotationController<T>(AnnotationController<T> annotationController, ImageSource imageSource, bool expectedToBeMirrored = false) where T : HierarchicalAnnotation
{
annotationController.isMirrored = expectedToBeMirrored ^ imageSource.isHorizontallyFlipped ^ imageSource.isFrontFacing;
annotationController.rotationAngle = imageSource.rotation.Reverse();
annotationController.imageSize = new Vector2Int(imageSource.textureWidth, imageSource.textureHeight);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Assets/MediaPipeUnity/Samples/Scenes/Tasks.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b652f11

Please sign in to comment.