이 문서에서는 Foundry Tools API에서 Azure Vision을 사용하여 라이브 비디오 스트림의 프레임을 거의 실시간으로 분석하는 방법을 보여 줍니다. 이 분석의 기본 요소는 다음과 같습니다.
- 비디오 원본에서 프레임 가져오기
- 분석할 프레임 선택
- 이러한 프레임을 API로 보내기
- API가 반환하는 각 분석 결과 사용
Tip
이 문서의 샘플은 C#으로 작성되었습니다. 코드에 액세스하려면 GitHub의 비디오 프레임 분석 샘플 페이지로 이동합니다.
거의 실시간으로 분석을 실행하는 방법
다양한 방법을 사용하여 비디오 스트림에서 거의 실시간으로 분석을 실행하는 문제를 해결할 수 있습니다. 이 문서에서는 그 중 세 가지 방법을 복잡성 순서대로 간략하게 설명합니다.
방법 1: 무한 루프 디자인
거의 실시간으로 분석하기 위한 가장 간단한 디자인은 무한 루프입니다. 이 루프의 각 반복에서 애플리케이션은 프레임을 검색하고 분석한 다음, 결과를 처리합니다.
while (true)
{
Frame f = GrabFrame();
if (ShouldAnalyze(f))
{
AnalysisResult r = await Analyze(f);
ConsumeResult(r);
}
}
분석이 간단한 클라이언트 쪽 알고리즘으로 구성된 경우 이 방법이 적합합니다. 그러나 클라우드에서 분석이 발생하는 경우 그로 인한 대기 시간 때문에 API 호출에 수 초가 걸릴 수 있습니다. 이 시간 동안에는 이미지를 캡처하지 않으며 스레드는 기본적으로 아무 작업도 수행하지 않습니다. 최대 프레임 속도는 API 호출의 대기 시간에 의해 제한됩니다.
방법 2: API 호출이 병렬로 실행되도록 허용
간단한 단일 스레드 루프는 경량 클라이언트 쪽 알고리즘에 적합하지만, 클라우드 API 호출과 관련된 대기 시간에는 적합하지 않습니다. 이 문제에 대한 해결 방법은 장기 실행 API 호출이 프레임 잡기와 병렬로 실행되도록 허용하는 것입니다. C#에서는 작업 기반 병렬 처리를 사용하여 이 작업을 수행할 수 있습니다. 예를 들어 다음 코드를 실행하면 됩니다.
while (true)
{
Frame f = GrabFrame();
if (ShouldAnalyze(f))
{
var t = Task.Run(async () =>
{
AnalysisResult r = await Analyze(f);
ConsumeResult(r);
}
}
}
이 방법을 사용하면 각 분석을 별도의 작업에서 시작합니다. 새 프레임을 가져오는 동안 작업을 백그라운드에서 실행할 수 있습니다. 이 방법은 API 호출이 반환되기를 기다리는 동안 주 스레드가 차단되지 않습니다. 그러나 이 방법은 다음과 같은 단점이 있습니다.
- 간단한 버전이 제공한 일부 보장을 잃게 됩니다. 즉, 여러 API 호출이 병렬로 발생할 수 있으며, 그 결과가 잘못된 순서로 반환될 수 있습니다.
- 이로 인해 여러 스레드가 동시에 함수에
ConsumeResult()진입할 수 있으며, 이는 함수가 스레드로부터 안전하지 않은 경우 위험할 수 있습니다. - 마지막으로, 이 간단한 코드는 생성되는 작업을 추적하지 않으므로 예외가 자동으로 사라집니다. 따라서 분석 작업을 추적하고 예외를 발생시키고 장기 실행 작업을 종료하고 결과가 올바른 순서로 사용되도록 보장하는 “소비자” 스레드를 추가해야 합니다.
방법 3: 생산자-소비자 시스템 디자인
"생산자-소비자" 시스템을 설계하려면 이전 섹션의 무한 루프와 유사한 생산자 스레드를 빌드합니다. 그러면 생산자는 분석 결과가 제공되는 즉시 사용하는 대신, 간단하게 작업을 큐에 배치하여 추적합니다.
// Queue that will contain the API call tasks.
var taskQueue = new BlockingCollection<Task<ResultWrapper>>();
// Producer thread.
while (true)
{
// Grab a frame.
Frame f = GrabFrame();
// Decide whether to analyze the frame.
if (ShouldAnalyze(f))
{
// Start a task that will run in parallel with this thread.
var analysisTask = Task.Run(async () =>
{
// Put the frame, and the result/exception into a wrapper object.
var output = new ResultWrapper(f);
try
{
output.Analysis = await Analyze(f);
}
catch (Exception e)
{
output.Exception = e;
}
return output;
}
// Push the task onto the queue.
taskQueue.Add(analysisTask);
}
}
또한 큐에서 작업을 꺼내 완료될 때까지 대기한 후, 결과를 표시하거나 발생된 예외를 전달하는 소비자 스레드를 만듭니다. 큐를 사용하면 시스템의 최대 프레임 속도를 제한하지 않고 결과가 한 번에 하나씩, 올바른 순서로 사용되도록 보장할 수 있습니다.
// Consumer thread.
while (true)
{
// Get the oldest task.
Task<ResultWrapper> analysisTask = taskQueue.Take();
// Wait until the task is completed.
var output = await analysisTask;
// Consume the exception or result.
if (output.Exception != null)
{
throw output.Exception;
}
else
{
ConsumeResult(output.Analysis);
}
}
솔루션 구현
샘플 코드 가져오기
앱을 최대한 빨리 실행할 수 있도록 이전 섹션에서 설명한 시스템을 구현했습니다. 이 시스템은 여러 시나리오를 수용할 수 있도록 유연하면서도 쉽게 사용할 수 있도록 제작되었습니다. 코드에 액세스하려면 GitHub의 비디오 프레임 분석 샘플 리포지토리로 이동합니다.
라이브러리에는 생산자-소비자 시스템을 구현하여 웹캠의 비디오 프레임을 처리하는 FrameGrabber 클래스가 있습니다. 사용자는 API 호출의 정확한 형식을 지정할 수 있으며, 클래스는 이벤트를 사용하여 새 프레임을 획득할 때 또는 새 분석 결과를 사용할 수 있는 시기를 호출 코드에 알릴 수 있습니다.
샘플 구현 보기
몇 가지 가능성을 설명하기 위해 라이브러리를 사용하는 두 개의 샘플 앱을 제공합니다.
첫 번째 샘플 앱은 기본 웹캠에서 프레임을 가져와 얼굴 감지용 Face 서비스로 전송하는 간단한 콘솔 앱입니다. 이 앱의 간소화된 버전이 다음 코드에 나와 있습니다.
using System;
using System.Linq;
using Microsoft.Azure.CognitiveServices.Vision.Face;
using Microsoft.Azure.CognitiveServices.Vision.Face.Models;
using VideoFrameAnalyzer;
namespace BasicConsoleSample
{
internal class Program
{
const string ApiKey = "<your API key>";
const string Endpoint = "https://<your API region>.api.cognitive.microsoft.com";
private static async Task Main(string[] args)
{
// Create grabber.
FrameGrabber<DetectedFace[]> grabber = new FrameGrabber<DetectedFace[]>();
// Create Face Client.
FaceClient faceClient = new FaceClient(new ApiKeyServiceClientCredentials(ApiKey))
{
Endpoint = Endpoint
};
// Set up a listener for when we acquire a new frame.
grabber.NewFrameProvided += (s, e) =>
{
Console.WriteLine($"New frame acquired at {e.Frame.Metadata.Timestamp}");
};
// Set up a Face API call.
grabber.AnalysisFunction = async frame =>
{
Console.WriteLine($"Submitting frame acquired at {frame.Metadata.Timestamp}");
// Encode image and submit to Face service.
return (await faceClient.Face.DetectWithStreamAsync(frame.Image.ToMemoryStream(".jpg"))).ToArray();
};
// Set up a listener for when we receive a new result from an API call.
grabber.NewResultAvailable += (s, e) =>
{
if (e.TimedOut)
Console.WriteLine("API call timed out.");
else if (e.Exception != null)
Console.WriteLine("API call threw an exception.");
else
Console.WriteLine($"New result received for frame acquired at {e.Frame.Metadata.Timestamp}. {e.Analysis.Length} faces detected");
};
// Tell grabber when to call the API.
// See also TriggerAnalysisOnPredicate
grabber.TriggerAnalysisOnInterval(TimeSpan.FromMilliseconds(3000));
// Start running in the background.
await grabber.StartProcessingCameraAsync();
// Wait for key press to stop.
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
// Stop, blocking until done.
await grabber.StopProcessingAsync();
}
}
}
두 번째 샘플 앱은 더 많은 기능을 제공합니다. 두 번째 앱은 비디오 프레임에서 호출할 API를 선택할 수 있습니다. 앱의 왼쪽에는 라이브 비디오의 미리 보기가 표시됩니다. 오른쪽에는 해당 프레임의 최신 API 결과가 중첩됩니다.
대부분의 모드에서는 왼쪽의 라이브 비디오와 오른쪽의 시각화된 분석 간에 시각적 지연이 발생합니다. 이 지연은 API 호출을 수행하는 데 걸리는 시간입니다. 예외는 EmotionsWithClientFaceDetect 이미지를 Foundry 도구에 제출하기 전에 OpenCV를 사용하여 클라이언트 컴퓨터에서 로컬로 얼굴 감지를 수행하는 모드입니다.
이 접근 방식을 사용하면 감지된 얼굴을 즉시 시각화할 수 있습니다. 그런 다음, API 호출이 반환된 후 나중에 특성을 업데이트할 수 있습니다. 이 방법은 "하이브리드" 접근 방식의 가능성을 보여 줍니다. 클라이언트에서 몇 가지 간단한 처리를 수행할 수 있으며, 필요한 경우 Foundry 도구 API는 고급 분석을 통해 이 처리를 보강할 수 있습니다.
코드베이스에 샘플 통합
이 샘플을 시작하려면 다음 단계를 완료합니다.
- Azure 계정을 만듭니다. 계정이 이미 있는 경우 다음 단계로 이동합니다.
- Azure Portal에서 Azure Vision 및 Face에 대한 리소스를 만들어 키와 엔드포인트를 가져옵니다. 설치 중에 체험 계층(F0)을 선택했는지 확인합니다.
- Azure Vision을 활용한 Foundry 도구
- 얼굴 포털에서 리소스를 배포한 후 리소스로 이동하여 각 리소스 에 대한 키와 엔드포인트를 수집합니다.
- Cognitive-Samples-VideoFrameAnalysis GitHub 리포지토리를 복제합니다.
- Visual Studio 2015 이상에서 샘플을 연 다음 샘플 애플리케이션을 빌드하고 실행합니다.
- BasicConsoleSample의 경우 BasicConsoleSample/Program.cs 직접 Face 키를 하드 코딩합니다.
- LiveCameraSample의 경우 앱의 설정 창에 키를 입력합니다. 앱은 세션 간에 키를 사용자 데이터로 유지합니다.
샘플을 통합할 준비가 완료되면 해당 프로젝트에서 VideoFrameAnalyzer 라이브러리를 참조합니다.
VideoFrameAnalyzer의 이미지, 음성, 비디오 및 텍스트 이해 기능은 Foundry 도구를 사용합니다. Microsoft는 이 앱을 통해 업로드하는 이미지, 오디오, 비디오 및 기타 데이터를 수신하며 서비스 개선을 위해 사용할 수 있습니다. 앱이 Foundry 도구로 보내는 데이터를 가진 사람들을 보호하는 데 도움을 요청합니다.
다음 단계
이 문서에서는 Face 및 Azure Vision을 사용하여 라이브 비디오 스트림에서 거의 실시간 분석을 실행하는 방법을 알아보았습니다.
GitHub 리포지토리에서 자유롭게 피드백과 의견을 남겨주세요. 보다 광범위한 API 피드백을 제공하려면 UserVoice 사이트로 이동하세요.