상위 목록: 하위 목록: 작성 날짜: 읽는 데 19 분 소요

윤곽 추적(Snake Image)

SnakeImage 함수를 이용하여 이미지나 영상의 윤곽을 추적합니다.

원본(Source, src)은 영상이나 이미지를 사용합니다.

  • 영상 사용하기 : [3강 바로가기][3강]

  • 이미지 사용하기 : [4강 바로가기][4강]



메인 코드

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

namespace Project
{
    class OpenCV : IDisposable
    {  
        IplImage snake;

        public IplImage SnakeImage(IplImage src)
        {
            IplImage snake_calc = new IplImage(src.Size, BitDepth.U8, 1);
            snake = new IplImage(src.Size, BitDepth.U8, 3);

            Cv.CvtColor(src, snake_calc, ColorConversion.BgrToGray);
            Cv.Threshold(snake_calc, snake_calc, 150, 255, ThresholdType.Binary);
            Cv.Smooth(snake_calc, snake_calc, SmoothType.Gaussian, 9);

            int contour_num = 2000;
            CvPoint[] contour = new CvPoint[contour_num];
            CvPoint center = new CvPoint(snake_calc.Width / 2, snake_calc.Height / 2);

            for (int i = 0; i < contour.Length; i++)
            {
                contour[i].X = (int)(center.X * Math.Cos(2 * Math.PI * i / contour.Length) + center.X);
                contour[i].Y = (int)(center.Y * Math.Sin(2 * Math.PI * i / contour.Length) + center.Y);
            }

            CvWindow window = null;

            int k = 0;
            while ( k < contour_num / 2)
            {
                k++;

                window = new CvWindow("SnakeImage", WindowMode.StretchImage);
                window.Resize(640, 480);

                Cv.SnakeImage(snake_calc, contour, 0.50f, 0.40f, 0.30f, new CvSize(15, 15), new CvTermCriteria(1), true);
                            
                Cv.Copy(src, snake);

                for (int i = 0; i < contour.Length - 1; i++)
                {
                    Cv.Line(snake, contour[i], contour[i + 1], CvColor.Red, 5);
                }
                Cv.Line(snake, contour[contour.Length - 1], contour[0], CvColor.Red, 5);

                window.Image = snake;
                Application.DoEvents();
            }
            window.Close();
            return snake;
        }
    
        public void Dispose()
        {
            if (snake != null) Cv.ReleaseImage(snake);
        }
    }
}


세부 코드

IplImage snake_calc = new IplImage(src.Size, BitDepth.U8, 1);
snake = new IplImage(src.Size, BitDepth.U8, 3);

계산에 사용할 snake_calc와 결과에 사용할 snake를 생성합니다.


Cv.CvtColor(src, snake_calc, ColorConversion.BgrToGray);
Cv.Threshold(snake_calc, snake_calc, 150, 255, ThresholdType.Binary);
Cv.Smooth(snake_calc, snake_calc, SmoothType.Gaussian, 9);

snake_calc그레이스케일로 변환 후, 이진화를 적용합니다.

이 후 가우시안 블러를 적용하여 이미지를 단순화합니다.


int contour_num = 2000;
CvPoint[] contour = new CvPoint[contour_num];
CvPoint center = new CvPoint(snake_calc.Width / 2, snake_calc.Height / 2);

윤곽의 개수로 사용할 contour_num을 생성합니다.

contour를 생성하여 contour_num의 개수만큼 생성합니다.

center를 생성하여 윤곽 추적을 위한 이미지의 중심점을 생성합니다.


for (int i = 0; i < contour.Length; i++)
{
    contour[i].X = (int)(center.X * Math.Cos(2 * Math.PI * i / contour.Length) + center.X);
    contour[i].Y = (int)(center.Y * Math.Sin(2 * Math.PI * i / contour.Length) + center.Y);
}

for문을 사용하여 중심점을 기준으로 coutour_num 개수만큼 둘러싸게 합니다.

윤곽의 X 좌표Y 좌표를 저장합니다.

  • Tip : 초기 윤곽은 중심점(center)을 기준으로 둥글게 생성됩니다.


CvWindow window = null;

윤곽 추적을 보여줄 window를 생성합니다.


int k = 0;
while ( k < contour_num / 2)
{
    k++;
    ...
}

윤곽 추적을 위하여 contour_num의 절반만큼 반복합니다.


window = new CvWindow("SnakeImage", WindowMode.StretchImage);
window.Resize(640, 480);

window를 생성하고 크기 모드를 StretchImage로 사용하며 크기를 적절하게 변경합니다.


Cv.SnakeImage(snake_calc, contour, 0.50f, 0.40f, 0.30f, new CvSize(15, 15), new CvTermCriteria(1), true);

Cv.SnakeImage를 사용하여 윤곽을 추적합니다.

Cv.SnakeImage(이미지, 윤곽선, 알파, 베타, 감마, 이웃 크기, 종료 기준, 그라디언트 플래그)입니다.

  • 알파 : 연속성의 가중치입니다.

  • 베타 : 곡률의 가중치입니다.

  • 감마 : 이미지의 가중치입니다.

  • 이웃크기 : 최솟값을 검색하는데 사용되는 모든 이웃 점의 크기입니다.

  • 종료 기준 : 반복 알고리즘의 종료 기준입니다. 최대 반복 횟수를 의미합니다.

  • 그라디언트 플래그 : 모든 이미지 픽셀에 대한 그래디언트 크기를 계산하고이를 에너지 필드로 간주 유/무 입니다.


Cv.Copy(src, snake);

그려진 윤곽선을 지우고 새롭게 그리기 위하여 원본을 덧씌웁니다.


for (int i = 0; i < contour.Length - 1; i++)
{
    Cv.Line(snake, contour[i], contour[i + 1], CvColor.Red, 5);
}
Cv.Line(snake, contour[contour.Length - 1], contour[0], CvColor.Red, 5);

for문을 이용하여 윤곽점을 이어 윤곽선으로 그립니다.

for문에서는 첫 번째 윤곽점과 마지막 윤곽점을 잇지 못하므로 for문이 모두 반복된 후 남은 점을 잇습니다.


window.Image = snake;
Application.DoEvents();

window에 윤곽 추적 결과를 표시합니다.

Application.DoEvents()를 사용하여 while문이 반복중에도 윈도우 창이 업데이트되도록 합니다.

  • Tip : 네임스페이스에 using System.Windows.Forms;이 포함되어야 합니다.


window.Close();

추적이 완료되면 window를 닫습니다.



출력 결과


댓글 남기기