C# OpenCV 강좌 : 제 23강 - 블록 껍질

   

블록 껍질 (ConvexHull)


1 영상이나 이미지의 외곽점들을 잇기 위해 사용합니다. 영상이나 이미지에서 ContourConvexHull2를 이용해 최외곽점들이 연결된 다각형을 만들 수 있습니다.


원본(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 convex;        
        
        public IplImage Binary(IplImage src)
        {
            bin = new IplImage(src.Size, BitDepth.U8, 1);
            Cv.CvtColor(src, bin, ColorConversion.RgbToGray);
            Cv.Threshold(bin, bin, 150, 255, ThresholdType.Binary);
            return bin;
        }
            
        public IplImage ConvexHull(IplImage src)
        {
            convex = new IplImage(src.Size, BitDepth.U8, 3);
            bin = new IplImage(src.Size, BitDepth.U8, 1);
            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)
            {
                CvPoint[] ptseq = new CvPoint[c.Total];

                if (c.Total > 4)
                {
                    for (int i = 0; i < c.Total; i++)
                    {
                        CvPoint? p = Cv.GetSeqElem(c, i);
                        ptseq[i] = new CvPoint
                        {
                            X = p.Value.X,
                            Y = p.Value.Y
                        };
                    }

                    foreach (CvPoint pt in ptseq)
                    {
                        Cv.Circle(convex, pt, 4, CvColor.Red, -1);
                    }

                    CvPoint[] hull;
                    Cv.ConvexHull2(ptseq, out hull, ConvexHullOrientation.Clockwise);

                    CvPoint pt0 = hull.Last();
                    foreach (CvPoint pt in hull)
                    {
                        Cv.Line(convex, pt0, pt, CvColor.Green, 2);
                        pt0 = pt;
                    }
                }
            }  
            return convex;
        }
            
        public void Dispose()
        {
            if (bin != null) Cv.ReleaseImage(bin);        
            if (convex != null) Cv.ReleaseImage(convex);        
        }
    }
}

Class Code


convex = new IplImage(src.Size, BitDepth.U8, 3);
bin = new IplImage(src.Size, BitDepth.U8, 1);
bin = this.Binary(src);

검은 이미지인 convex과 Binary 이미지인 bin을 선언하고 적용시킵니다.

  • Tip : convex는 원본을 복사하지 않아 검은색 이미지입니다.


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()를 사용하여 근사합니다.


ApproxPoly 알아보기 : 22강 바로가기


for (CvSeq<CvPoint> c = apcon_seq; c != null; c = c.HNext)
{
    CvPoint[] ptseq = new CvPoint[c.Total];

    if (c.Total > 4)
    {
        for (int i = 0; i < c.Total; i++)
        {
            CvPoint? p = Cv.GetSeqElem(c, i);
            ptseq[i] = new CvPoint
            {
                X = p.Value.X,
                Y = p.Value.Y
            };
        }

        foreach (CvPoint pt in ptseq)
        {
            Cv.Circle(convex, pt, 4, CvColor.Red, -1);
        }

        CvPoint[] hull;
        Cv.ConvexHull2(ptseq, out hull, ConvexHullOrientation.Clockwise);

        CvPoint pt0 = hull.Last();
        foreach (CvPoint pt in hull)
        {
            Cv.Line(convex, pt0, pt, CvColor.Green, 2);
            pt0 = pt;
        }
    }
}  

if문 까지는 22강과 흡사합니다. 코너를 검출하기 위해 사용합니다. 자세한 사항은 22강의 설명을 참고하시기 바랍니다.

CvPoint[] ptseq = new CvPoint[c.Total]을 이용하여 다각형을 만들기 위해 생성자를 만듭니다. 생성될 다각형과 다각형 안의 모든 점의 개수c.Total값과 동일합니다.

ptseq[i] = new CvPoint를 이용하여 하나의 다각형 안에 있는 점의 좌표들을 배열로 저장합니다. 이 정보들을 통하여 최외곽점들을 알 수 있습니다.

ptseq[i] = new CvPoint{ ... }에서 각 점들의 위치를 저장합니다.

foreach문을 이용하여 모든 점들을 그립니다. 이 구문은 점을 표현하기 위한 구문이므로 생략하셔도 가능합니다.

CvPoint[] hull을 선언합니다. 이 구문은 최 상단의 for문 밖에 선언하셔도 됩니다. 코드의 원활한 설명을 위하여 for문 안에 삽입하였습니다.

Cv.ConvexHull2()를 이용하여 블록 껍질을 찾습니다. ConvexHull2(코너점들의 집합, 최외곽 점, 회전 방향)입니다. 코너점들을 이용하여 최외곽점들을 찾습니다. ConvexHullOrientation은 시계방향인 Clockwise와 반시계방향인 Counterclockwise가 있습니다.

CvPoint pt0 = hull.Last()을 이용하여 블록 껍질을 만들기 위해 최초 지점을 설정합니다.

모든 점들을 그리는 방법과 동일하게 foreach문을 이용하여 선들을 연결합니다. pt0를 현재의 pt점으로 대체해서 다음 지점과 연결되게 만듭니다.


Result


2



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

⤧  Next post C# OpenCV 강좌 : 제 24강 - 중심점 ⤧  Previous post C# OpenCV 강좌 : 제 22강 - 코너 검출 (2)