Computer Vision 실시간 동영상 분석하기
본문에서는 라이브 동영상 스트림으로부터 가져온 프레임을 대상으로 거의 실시간에 가까운 분석을 수행하는 방법을 살펴봅니다.
이를 위한 시스템의 기본 구성 요소들은 다음과 같습니다:
-
동영상 원본에서 프레임 가져오기
-
분석할 프레임 선택하기
-
선택한 프레임을 API에 제출하기
-
API 호출로부터 반환된 각각의 분석 결과 사용하기
본문의 예제들은 C#으로 작성되었으며, 실제 코드는 GitHub의 https://github.com/Microsoft/Cognitive-Samples-VideoFrameAnalysis/ 저장소에서 확인할 수 있습니다.
접근방식
실시간에 근접한 동영상 스트림 분석을 수행하기 위한 방법은 다양합니다.
지금부터 보다 세련된 순서에 따라 세 가지 접근방식을 개략적으로 살펴보겠습니다.
간단한 접근방식
실시간에 가까운 분석 시스템을 구현하기 위한 가장 간단한 설계는 무한 루프로, 매번 루프가 반복될 때마다 프레임을 잡아서 분석한 다음, 그 결과를 사용합니다:
while (true)
{
Frame f = GrabFrame();
if (ShouldAnalyze(f))
{
AnalysisResult r = await Analyze(f);
ConsumeResult(r);
}
}
만약 필요로 하는 분석이 가벼운 클라이언트 측 알고리즘으로 구성된다면 이렇게 간단한 접근방식도 무난할 것입니다.
그러나 이 방식은 클라우드에서 분석이 처리되는 동안 필연적으로 대기 시간이 발생하게 되며, 경우에 따라서는 API 호출이 완료될 때까지 몇 초가 걸릴 수도 있습니다.
따라서 그 동안에는 이미지 캡처 작업이 진행되지 않을뿐만 아니라, 본질적으로 스레드는 아무런 작업도 수행하지 않습니다.
결국 이 방식의 최대 프레임 속도는 API 호출의 대기 시간에 의해서 결정됩니다.
API 호출 병렬화
간단한 단일-스레드 루프는 가벼운 클라이언트 측 알고리즘에는 적합하지만, 클라우드 API 호출과 관련된 대기 시간이 발생한다는 문제점이 존재합니다.
이 문제점에 대한 한 가지 해결 방안은 장기 실행 API 호출과 프레임 캡처 작업을 병렬로 동시에 수행하는 것입니다.
가령, C#에서는 다음과 같이 Task 기반 병렬 처리를 통해서 이를 구현할 수 있습니다:
while (true)
{
Frame f = GrabFrame();
if (ShouldAnalyze(f))
{
var t = Task.Run(async () =>
{
AnalysisResult r = await Analyze(f);
ConsumeResult(r);
});
}
}
이 방식을 사용하면 각각의 분석이 별도의 Task로 시작되므로, 새로운 프레임을 가져오는 동안 백그라운드에서는 계속해서 분석 처리를 수행할 수 있습니다.
다만, 호출한 API가 반환되기를 기다리는 동안 메인 스레드가 잠기는 상황은 피할 수 있지만, 앞에서 살펴본 간단한 버전의 구현이 보장해주는 이점을 일부 잃어버리게 됩니다.
즉, API가 동시에 여러 번 호출될 수 있으며, 결과가 잘못된 순서로 반환될 수도 있습니다.
여러 스레드가 동시에 ConsumeResult() 함수에 진입할 수 있으며, 결과적으로 이 함수가 스레드에 안전하지 않을 경우 위험해질 수도 있습니다.
마지막으로, 이 간단한 코드는 생성된 Task들을 추적하지 않기 때문에, 예외가 소리소문 없이 사라집니다.
따라서 마지막으로 검토해 볼 접근방식은, 분석 작업을 추적하고, 예외를 발생시키며, 장기 실행 작업을 중단하고, 올바른 순서로 결과를 한 번에 하나씩 소비할 수 있게 보장해주는 "소비자" 스레드입니다.
생산자-소비자 디자인 패턴
마지막으로 살펴볼 "생산자-소비자" 시스템은 앞에서 살펴본 무한 루프와 매우 비슷한 생산자 스레드를 갖고 있습니다.
그러나 생산자는 분석 결과를 그 즉시 사용하는 대신, 그저 단순히 작업을 큐에 넣고 이를 추적합니다.
// 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();
// Await 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);
}
}
솔루션 구현하기
시작하기
가급적 간단하게 응용 프로그램을 구현하고 실행해볼 수 있도록, 지금까지 설명한 시스템을 예제로 구현했습니다.
다양한 시나리오에 대응한 구현이 가능하면서도 사용이 쉽도록 유연하게 작성되었습니다.
실제 코드는 https://github.com/Microsoft/Cognitive-Samples-VideoFrameAnalysis/ 저장소에서 확인할 수 있습니다.
라이브러리에는 웹 캠의 동영상 프레임을 처리하기 위해 앞에서 살펴본 생산자-소비자 시스템을 구현한 클래스인 FrameGrabber 클래스가 포함되어 있습니다.
사용자는 API 호출의 정확한 형식을 지정할 수 있으며, 이 클래스는 이벤트를 이용해서 호출한 코드가 새 프레임을 가져왔는지, 또는 새로운 분석 결과를 사용할 수 있는지 여부를 알려줍니다.
사용 가능한 몇 가지 사례를 설명하기 위한, 라이브러리를 활용한 두 가지 예제 응용 프로그램이 제공됩니다.
먼저 첫 번째 예제는 간단한 콘솔 응용 프로그램으로, 다음은 이 예제를 간단히 정리한 코드입니다.
이 예제 응용 프로그램은 기본 웹 캠의 프레임을 잡고, 이를 Face API에 제출해서 얼굴을 인식합니다.
using System;
using VideoFrameAnalyzer;
using Microsoft.ProjectOxford.Face;
using Microsoft.ProjectOxford.Face.Contract;
namespace VideoFrameConsoleApplication
{
class Program
{
static void Main(string[] args)
{
// Create grabber, with analysis type Face[].
FrameGrabber<Face[]> grabber = new FrameGrabber<Face[]>();
// Create Face API Client. Insert your Face API key here.
FaceServiceClient faceClient = new FaceServiceClient("<subscription key>");
// Set up our Face API call.
grabber.AnalysisFunction = async frame => return await faceClient.DetectAsync(frame.Image.ToMemoryStream(".jpg"));
// Set up a listener for when we receive a new result from an API call.
grabber.NewResultAvailable += (s, e) =>
{
if (e.Analysis != null)
Console.WriteLine("New result received for frame acquired at {0}. {1} faces detected", e.Frame.Metadata.Timestamp, e.Analysis.Length);
};
// Tell grabber to call the Face API every 3 seconds.
grabber.TriggerAnalysisOnInterval(TimeSpan.FromMilliseconds(3000));
// Start running.
grabber.StartProcessingCameraAsync().Wait();
// Wait for keypress to stop
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
// Stop, blocking until done.
grabber.StopProcessingAsync().Wait();
}
}
}
두 번째 예제 응용 프로그램은 보다 흥미로운데, 이번에는 UI에서 동영상 프레임을 대상으로 호출할 API를 선택할 수 있습니다.
응용 프로그램의 좌측에는 실시간 동영상의 미리보기가 출력되고, 그 우측에는 해당 프레임에 대해 가장 최근에 반환된 API의 결과가 출력되어 표시됩니다.
대부분의 모드에서 좌측의 라이브 동영상과 우측의 시각화된 분석 결과 간에 두드러지는 지연이 존재하는 것을 확인할 수 있습니다.
이는 API 호출을 수행하는 데 소요되는 시간으로 인한 것입니다.
한 가지 예외는 이미지를 Cognitive Services에 제출하기 전, OpenCV를 이용해서 클라이언트 컴퓨터에서 로컬로 미리 얼굴 인식을 수행하는 "EmotionsWithClientFaceDetect" 모드입니다.
이 방식을 사용하면, 우선 감지된 얼굴부터 즉시 시각화한 다음, 이어서 API 호출이 반환되면 감정에 관한 정보를 갱신할 수 있습니다.
이 예제는, 먼저 클라이언트 측에서 수행할 수 있는 일부 간단한 처리를 수행한 다음, 필요할 경우에만 Cognitive Services API를 이용한 보다 고급의 분석으로 결과를 보완하는 "하이브리드" 접근 방식의 가능성을 보여줍니다.
자신의 코드베이스에 통합하기
본문의 예제를 시작하려면 다음 과정을 수행해야 합니다:
-
Cognitive Services 체험하기 페이지에서 Vision API들의 API 키를 발급받습니다.
동영상 프레임 분석을 위해서 필요한 API들은 다음과 같습니다:
-
Cognitive-Samples-VideoFrameAnalysis GitHub 저장소를 복제합니다.
-
Visual Studio 2015 이상에서 예제 솔루션을 열고 빌드한 다음, 응용 프로그램을 실행합니다:
-
BasicConsoleSample 예제의 Face API 키는 BasicConsoleSample/Program.cs 파일에 직접 하드 코딩되어 있습니다.
-
LiveCameraSample 예제의 키들은 응용 프로그램의 Settings 패인에 입력해야 합니다.
이 정보들은 사용자 데이터로 세션 간에 유지됩니다.
통합할 준비를 마쳤다면, 여러분의 프로젝트에서 VideoFrameAnalyzer 라이브러리를 참조하기만 하면 됩니다.
개발자 준수 사항
모든 다른 Cognitive Services와 마찬가지로, API 및 본문의 예제를 활용하여 개발을 진행하는 개발자는 "Microsoft Cognitive Services 개발자 준수 사항"을 준수해야 합니다.
VideoFrameAnalyzer 라이브러리의 이미지, 음성, 비디오 및 텍스트 인식 기능은 Microsoft Cognitive Services를 사용합니다.
Microsoft는 서비스 개선을 목적으로 예제 응용 프로그램을 통해서 업로드 한 이미지, 오디오, 비디오 및 기타 데이터를 활용할 수 있습니다.
여러분의 응용 프로그램이 Microsoft Cognitive Services로 전송하는 사용자의 데이터를 보호할 수 있도록 여러분의 도움을 요청합니다.
요약
본문에서는 Face, Computer Vision 및 Emotion API를 사용해서 라이브 동영상 스트림을 실시간에 가깝게 분석하는 방법과, 예제 코드를 활용하고 시작하는 방법을 알아봤습니다.
Cognitive Services 체험하기 페이지에서 무료로 발급받을 수 있는 API 키만으로도 충분히 응용 프로그램 구축을 시작할 수 있습니다
언제든지 GitHub 저장소를 통해서 의견이나 제안을 보내주십시오.
또는 UserVoice 사이트를 통해서 API에 관한 보다 다양한 의견도 받습니다.