C# OpenCV 강좌 : 제 60강 - 광학 흐름 - Farneback
광학 흐름 - Farneback(Optical Flow Farneback)
카메라와 피사체의 상대 운동
에 의하여 발생하는 피사체의 운동에 대한 패턴
을 검출합니다.
Farneback
방법은 Gunnar Farneback의 알고리즘을 사용하여 밀도가 높은 광학 흐름
을 계산합니다.
이전 프레임(Previous)
과 현재 프레임(Current)
은 영상이나 이미지를 사용합니다.
원본(Source, src)
은 영상을 사용합니다.
영상 사용하기
: 3강 바로가기
메인 코드
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
namespace Project
{
class OpenCV : IDisposable
{
IplImage gray;
IplImage optical;
public IplImage GrayScale(IplImage src)
{
gray = new IplImage(src.Size, BitDepth.U8, 1);
Cv.CvtColor(src, gray, ColorConversion.BgrToGray);
return gray;
}
public IplImage OpticalFlowFarneback(IplImage previous, IplImage current)
{
IplImage prev = this.GrayScale(previous);
IplImage curr = this.GrayScale(current);
optical = current;
int rows = optical.Height;
int cols = optical.Width;
IplImage flow = new IplImage(optical.Size, BitDepth.F32, 2);
double pyrScale = 0.5;
int level = 3;
int winSize = 15;
int iterations = 3;
int polyN = 5;
double polySigma = 1.1;
Cv.CalcOpticalFlowFarneback(prev, curr, flow, pyrScale, level, winSize, iterations, polyN, polySigma, LKFlowFlag.PyrAReady);
for (int i = 0; i < cols; i += winSize)
{
for (int j = 0; j < rows; j += winSize)
{
int dx = (int)flow[j, i][0];
int dy = (int)flow[j, i][1];
if(dx != 0 || dy != 0)
{
Cv.DrawLine(optical, Cv.Point(i, j), Cv.Point(i + dx, j + dy), CvColor.Blue, 1, LineType.AntiAlias, 0);
Cv.DrawCircle(optical, new CvPoint(i + dx, j + dy), 3, CvColor.Blue, -1);
}
}
}
return optical;
}
public void Dispose()
{
if (gray!= null) Cv.ReleaseImage(gray);
if (optical != null) Cv.ReleaseImage(optical);
}
}
}
세부 코드
public IplImage OpticalFlowFarneback(IplImage previous, IplImage current)
{
...
}
이전 프레임 previous
와 현재 프레임 current
를 매개변수로 사용하여 검출을 진행합니다.
IplImage prev = this.GrayScale(previous);
IplImage curr = this.GrayScale(current);
optical = current;
광학 흐름 함수는 그레이스케일
을 적용하여 검출을 진행합니다.
계산이미지로 사용할 prev
와 curr
변수에 그레이스케일
을 적용합니다.
이후, 결과로 사용할 optical
필드에 현재 프레임
을 사용합니다.
- Tip : 그레이스케일을 사용하여 검출하므로
급격한 밝기 변화
나노이즈
에는 정확한 검출을 얻어낼 수 없습니다.
int rows = optical.Height;
int cols = optical.Width;
행
과 열
을 설정합니다.
IplImage flow = new IplImage(optical.Size, BitDepth.F32, 2);
double pyrScale = 0.5;
int level = 3;
int winSize = 15;
int iterations = 3;
int polyN = 5;
double polySigma = 1.1;
광학 흐름 검출 함수에 사용할 인수들을 설정합니다.
flow
는 광학 흐름에 대한 정보를 저장합니다. 비트 깊이는 F32
, 채널은 2
를 사용합니다.
pyrScale
는 프레임의 피라미드를 만들기 위한 이미지 크기를 설정합니다. 값은 0~1
의 값을 사용합니다. 0.5
는 고전적인 피라미드의 크기입니다.
level
은 피라미드 이미지의 레벨값을 설정합니다. 1
로 사용할 경우, 원본 이미지로 사용합니다.
winSize
는 윈도우 창의 크기를 의미합니다. 값이 클수록 노이즈의 영향과 처리속도가 짧아지지만, 검출 결과가 흐릿해집니다.
iterations
는 각 피라미드에서 알고리즘이 반복 수행
할 횟수입니다.
polyN
은 각 픽셀에서 다항식 확장을 찾는 데 사용되는 인접 픽셀 영역 크기
입니다. 값이 클수록 매끄러워지지만, 검출 결과가 흐릿해집니다. 값은 5~7
의 값을 가장 많이 사용합니다.
polySigma
는 부드럽게 하기 위한 가우시안의 표준 편차
입니다. polyN의 값이 5일 경우, 1.1의 값을 주로 사용하며, polyN의 값이 7일 경우, 1.5의 값을 주로 사용합니다.
Cv.CalcOpticalFlowFarneback(prev, curr, flow, pyrScale, level, winSize, iterations, polyN, polySigma, LKFlowFlag.PyrAReady);
Cv.CalcOpticalFlowFarneback()
을 사용하여 광학 흐름
을 구합니다.
Cv.CalcOpticalFlowFarneback(이전 프레임, 현재 프레임, 광학 흐름 저장 변수, 피라미드 스케일, 레벨, 윈도우 창 크기, 반복 횟수, 인접 픽셀 영역 크기, 가우시안 표준 편차, 플래그)
를 의미합니다.
for (int i = 0; i < cols; i += winSize)
{
for (int j = 0; j < rows; j += winSize)
{
...
}
}
이중 for
문을 사용하여 윈도우 창 크기
의 간격 만큼 반복합니다.
int dx = (int)flow[j, i][0];
int dy = (int)flow[j, i][1];
flow
에 저장되어있는 광학 흐름
에 대한 값을 받아옵니다.
(j ,i)
지점에서 index 0
과 index 1
값을 dx
, dy
에 저장합니다.
index 0
은 x
좌표에 대한 정보가 담겨있으며, index 1
은 y
좌표에 대한 정보가 담겨있습니다.
if(dx != 0 || dy != 0)
{
Cv.DrawLine(optical, Cv.Point(i, j), Cv.Point(i + dx, j + dy), CvColor.Blue, 1, LineType.AntiAlias, 0);
Cv.DrawCircle(optical, new CvPoint(i + dx, j + dy), 3, CvColor.Blue, -1);
}
if
문을 이용하여 광학 흐름
이 발생되지 않았을 때는 표시하지 않습니다.
Cv.DrawLine()
과 Cv.DrawCircle()
을 사용하여 광학 흐름을 optical
필드에 표시합니다.
출력 결과
공유하기


댓글 남기기