C# OpenCV 강좌 : 제 22강 - 코너 검출 (2)

   

코너 (Corner)


1 영상이나 이미지의 모서리(코너)를 검출하기 위해 사용합니다. 영상이나 이미지에서 ContourApproxPoly를 이용하여 검출 할 수 있습니다.


원본(Source, src)를 영상이나 이미지를 사용하면 됩니다.

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


Class


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

namespace test
{
    class OpenCV : IDisposable
    {  
        IplImage bin;    
        IplImage apcon;        
        
        public IplImage Binary(IplImage src)
        {
            bin = new IplImage(src.Size, BitDepth.U8, 1);
            Cv.CvtColor(src, bin, ColorConversion.RgbToGray);
            Cv.Threshold(bin, bin, 200, 255, ThresholdType.Binary);
            return bin;
        }
                
        public IplImage ApproxPoly_Contour(IplImage src)
        {
            apcon = new IplImage(src.Size, BitDepth.U8, 3);
            bin = new IplImage(src.Size, BitDepth.U8, 1);

            Cv.Copy(src, apcon);
            bin = this.Binary(src);

            CvMemStorage Storage = new CvMemStorage();
            CvSeq<CvPoint> contours;
            Cv.FindContours(bin, Storage, out contours, CvContour.SizeOf, ContourRetrieval.List, ContourChain.ApproxNone);

            CvSeq<CvPoint> apcon_seq = Cv.ApproxPoly(contours, CvContour.SizeOf, Storage, ApproxPolyMethod.DP, 3, true);

            for (CvSeq<CvPoint> c = apcon_seq; c != null; c = c.HNext)
            {
                if (c.Total > 4)
                {
                    for (int i = 0; i < c.Total; i++)
                    {
                        CvPoint? p = Cv.GetSeqElem(c, i);
                        CvPoint conpt;
                        conpt.X = p.Value.X;
                        conpt.Y = p.Value.Y;

                        Cv.Circle(apcon, conpt, 3, CvColor.Black, -1);
                    }
                }
            }
            return apcon;
        }
            
        public void Dispose()
        {
            if (bin != null) Cv.ReleaseImage(bin);        
            if (apcon != null) Cv.ReleaseImage(apcon);        
        }
    }
}

Class Code


apcon = new IplImage(src.Size, BitDepth.U8, 3);
bin = new IplImage(src.Size, BitDepth.U8, 1);

Cv.Copy(src, apcon);
bin = this.Binary(src);

원본 이미지를 복사한 apcon과 Binary 이미지인 bin을 선언하고 적용시킵니다.


CvMemStorage Storage = new CvMemStorage();
CvSeq<CvPoint> contours;
Cv.FindContours(bin, Storage, out contours, CvContour.SizeOf, ContourRetrieval.List, ContourChain.ApproxNone);

윤곽(Contour)을 검출하기 위하여 Storage, contours를 선언하고 Cv.FindContours()를 적용합니다.


Contour 알아보기 : 20강 바로가기


CvSeq<CvPoint> apcon_seq = Cv.ApproxPoly(contours, CvContour.SizeOf, Storage, ApproxPolyMethod.DP, 3, true);

Cv.ApproxPoly()를 이용하여 다각형 곡선을 근사합니다. Cv.ApproxPoly(시퀸스, 자료구조의 크기, 메모리 저장소, 근사방법, 근사정확도, 시퀀스결정)입니다. 근사정확도의 값이 낮을수록 세밀하며, 너무 높거나 낮을 경우 코너점이 너무 많이 검출되거나 적게 검출됩니다. 시퀀스결정은 단일시퀀스로 근사화하기 위해 true로 설정합니다.

  • Tip : 근사방법은 Douglas-Peucker Algorithm인 ApproxPolyMethod.DP만 사용할 수 있습니다.


for (CvSeq<CvPoint> c = apcon_seq; c != null; c = c.HNext)
{
    if (c.Total > 4)
    {
        for (int i = 0; i < c.Total; i++)
        {
            CvPoint? p = Cv.GetSeqElem(c, i);
            CvPoint conpt;
            conpt.X = p.Value.X;
            conpt.Y = p.Value.Y;

            Cv.Circle(apcon, conpt, 3, CvColor.Black, -1);
        }
    }
}

for문을 이용하여 코너를 검출합니다. apcon_seq를 변수로 하여 검출합니다. c값이 null값이 라면 멈추며, c.HNext를 이용하여 다음 값으로 넘어갑니다.

if문을 이용하여 코너점의 개수를 파악하여 4개보다 적으면 무시하게 합니다. 화면상의 각 모서리도 하나의 물체(덩어리)이며 코너점으로 판단하게됩니다. 화면의 모서리 부분을 무시하기 위해 5개 이상의 코너점부터 검출합니다.

c는 검출된 하나의 물체(덩어리)이며, 그때의 c.Total이 그 물체(덩어리)에 포함된 코너점입니다.

다시 for문을 이용하여 검출된 코너점들을 그려줍니다. Cv.GetSeqElem()을 이용하여 해당 인덱스에 따라 시퀀스 요소에 대한 포인터를 반환합니다. Cv.GetSeqElem(시퀀스, 인덱스)입니다. conpt.Xconpt.Y에 받아온 포인터의 값을 저장합니다.

그 후, Cv.Circle()을 이용하여 원을 그려 확인합니다.


Result


No Change

2

ApproxPoly - 근사정확도 = 1

3

ApproxPoly - 시퀀스결정 = false

4

if - c.total > 3

4



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

⤧  Next post C# OpenCV 강좌 : 제 23강 - 블록 껍질 ⤧  Previous post C# OpenCV 강좌 : 제 21강 - 코너 검출 (1)