C# OpenCV 강좌 : 제 57강 - 광학 흐름 - HS

   

광학 흐름 - HS (Optical Flow HS)


1 카메라와 피사체의 상대 운동에 의하여 발생하는 피사체의 운동에 대한 패턴을 검출합니다.

HS(Horn Schunck) 방법은 입력 이미지의 모든 픽셀에 대하여 광학 흐름을 검출합니다.


이전 프레임(Previous)현재 프레임(Current)은 영상이나 이미지를 사용하면 됩니다.


영상 사용하기 : 3강 바로가기
이미지 사용하기 : 4강 바로가기


Main Code


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;

namespace test
{
    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 OpticalFlowHS(IplImage previous, IplImage current)
        {
            IplImage prev = this.GrayScale(previous);
            IplImage curr = this.GrayScale(current);
            optical = current;

            int rows = optical.Height;
            int cols = optical.Width;

            CvMat velx = Cv.CreateMat(rows, cols, MatrixType.F32C1);
            CvMat vely = Cv.CreateMat(rows, cols, MatrixType.F32C1);

            Cv.SetZero(velx);
            Cv.SetZero(vely);

            CvTermCriteria criteria = Cv.TermCriteria(CriteriaType.Iteration | CriteriaType.Epsilon, 10, 0.01);

            Cv.CalcOpticalFlowHS(prev, curr, false, velx, vely, 150.0, criteria);

            for (int i = 0; i < rows; i += 15)
            {
                for (int j = 0; j < cols; j += 15)
                {
                    int dx = (int)Cv.GetReal2D(velx, i, j);
                    int dy = (int)Cv.GetReal2D(vely, i, j);

                    Cv.DrawLine(optical, Cv.Point(j, i), Cv.Point(j + dx, i + dy), CvColor.Red, 3, LineType.AntiAlias);
                }
            }

            return optical;
        }

        public void Dispose()
        {
            if (gray!= null) Cv.ReleaseImage(gray);   
            if (optical != null) Cv.ReleaseImage(optical);  
        }
    }
}


Class Code


public IplImage OpticalFlowHS(IplImage previous, IplImage current)
{
    ...
}

이전 프레임 previous와 현재 프레임 current를 매개변수로 사용하여 검출을 진행합니다.


IplImage prev = this.GrayScale(previous);
IplImage curr = this.GrayScale(current);
optical = current;

광학 흐름 함수는 그레이스케일을 적용하여 검출을 진행합니다.

계산이미지로 사용할 prevcurr 변수에 그레이스케일을 적용합니다.

이후, 결과로 사용할 optical 필드에 현재 프레임을 사용합니다.


  • Tip : 그레이스케일을 사용하여 검출하므로 급격한 밝기 변화노이즈에는 정확한 검출을 얻어낼 수 없습니다.


int rows = optical.Height;
int cols = optical.Width;

CvMat velx = Cv.CreateMat(rows, cols, MatrixType.F32C1);
CvMat vely = Cv.CreateMat(rows, cols, MatrixType.F32C1);

Cv.SetZero(velx);
Cv.SetZero(vely);

을 설정합니다. 매트릭스는 행의 개수 x 열의 개수로 사용합니다.

X 방향 속도 벡터를 저장할 velxY 방향 속도 벡터를 저장할 vely매트릭스 형식으로 생성합니다.

행의 개수높이의 크기와 같으며, 열의 개수너비의 크기와 같습니다.

매트릭스를 생성하였으므로, SetZero()를 통하여 매트릭스의 값을 0으로 초기화합니다.


CvTermCriteria criteria = Cv.TermCriteria(CriteriaType.Iteration | CriteriaType.Epsilon, 10, 0.01);

Cv.TermCriteria()를 사용하여 종료 기준을 설정합니다.

Cv.TermCriteria(만족 조건, 최대 반복 횟수, 정확도)입니다.


  • 만족 조건
    • CriteriaType.Iteration : 최대 반복 횟수에 도달 후, 알고리즘을 종료합니다.
    • CriteriaType.Epsilon : 정확도보다 낮아진 후, 알고리즘을 종료합니다.
    • CriteriaType.Iteration | CriteriaType.Epsilon : 최대 반복 횟수정확도 중 더 빠르게 만족하는 조건을 사용합니다.


Cv.CalcOpticalFlowHS(prev, curr, false, velx, vely, 150.0, criteria);

Cv.CalcOpticalFlowHS()을 사용하여 광학 흐름을 구합니다.

Cv.CalcOpticalFlowHS(이전 프레임, 현재 프레임, 초기 근사값 속도 필드 사용 유/무, x 방향 속도 벡터, y 방향 속도 벡터, 라그랑지안 승수, 종료 기준)입니다.


초기 근사값 속도 필드 사용 유/무는 초기 근사값으로 입력 속도를 사용할지 여부를 결정합니다.

x 방향 속도 벡터y 방향 속도 벡터에 광학 흐름의 값이 담깁니다.

라그랑지안 승수는 매끄러움도를 뜻합니다. 값이 클수록 더 부드러운 광학 흐름을 얻습니다.


for (int i = 0; i < rows; i += 15)
{
    for (int j = 0; j < cols; j += 15)
    {
        ...
    }
}

이중 for문을 사용하여 속도 벡터의 값을 출력합니다.

로 반복을 실행합니다.

변환식에서 값을 +=15로 두어, 화면을 15 픽셀마다 광학흐름을 검출합니다.


int dx = (int)Cv.GetReal2D(velx, i, j);
int dy = (int)Cv.GetReal2D(vely, i, j);

Cv.GetReal2D() 함수를 사용하여 매트릭스에 담겨있는 속도 벡터 성분을 불러옵니다.

Cv.GetReal2D(matrix, index0, index1)을 의미합니다.

index0행 방향(↓)을 의미합니다.

index1열 방향(→)을 의미합니다.


Cv.DrawLine(optical, Cv.Point(j, i), Cv.Point(j + dx, i + dy), CvColor.Red, 3, LineType.AntiAlias);

Cv.DrawLine()을 사용하여 광학 흐름을 optical 필드에 표시합니다.

광학 흐름의 발생 지점은 (j, i)입니다.

광학 흐름의 도착 지점은 (j + dx, i + dy)입니다.

dxdy의 값을 사용하여 광학 흐름의 속도를 출력할 수 있습니다.


  • Tip : dxdy를 이용하여 일정 속도 이상, 이하의 값을 무시하거나 출력할 수 있습니다.


Result


2



도움이 되셨다면 광고 클릭 부탁드립니다.

⤧  Next post C# OpenCV 강좌 : 제 58강 - 광학 흐름 - LK ⤧  Previous post C# OpenCV 강좌 : 제 56강 - 광학 흐름 - BM