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

중심점(Moments)

영상이나 이미지의 중심점을 찾기 위해 사용합니다.

영상이나 이미지에서 ContourMoments를 이용해 물체(덩어리)의 중심점을 찾을 수 있습니다.

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



클래스 코드

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

namespace Project
{
    class OpenCV : IDisposable
    {  
        IplImage bin;    
        IplImage mom;        
        
        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 Moment(IplImage src)
        {
            mom = new IplImage(src.Size, BitDepth.U8, 3);
            bin = new IplImage(src.Size, BitDepth.U8, 1);

            Cv.Copy(src, mom);
            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);
                    
            CvMoments moments;
            int cX = 0, cY = 0;

            for (CvSeq<CvPoint> c = apcon_seq; c != null; c = c.HNext)
            {
                if (c.Total > 4)
                {
                    Cv.Moments(c, out moments, true);

                    cX = Convert.ToInt32(moments.M10 / moments.M00);
                    cY = Convert.ToInt32(moments.M01 / moments.M00);

                    Cv.Circle(mom, new CvPoint(cX, cY), 5, CvColor.Red, -1);
                }
            }
            return mom;  
        }            
        public void Dispose()
        {
            if (bin != null) Cv.ReleaseImage(bin);        
            if (mom != null) Cv.ReleaseImage(mom);        
        }
    }
}


세부 코드

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

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

원본 이미지를 복사한 mom과 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()를 적용합니다.


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

다각형 곡선을 근사화 하기 위해 Cv.ApproxPoly()를 사용하여 근사합니다.


CvMoments moments;
int cX = 0, cY = 0;

moments를 선언하여 중심점에 관한 정보를 포함하고 있습니다.

cXcY를 선언하여 중심점의 좌표(center_x, center_y)로 사용합니다.


for (CvSeq<CvPoint> c = apcon_seq; c != null; c = c.HNext)
{
    if (c.Total > 4)
    {
        Cv.Moments(c, out moments, true);

        cX = Convert.ToInt32(moments.M10 / moments.M00);
        cY = Convert.ToInt32(moments.M01 / moments.M00);

        Cv.Circle(mom, new CvPoint(cX, cY), 5, CvColor.Red, -1);
    }
}  

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

Cv.Moments()를 이용하여 중심점에 대한 정보를 받아옵니다. Cv.Moments(물체의 코너점들, 중심점 데이터, Binary조건)입니다.

out moments를 통하여 검출된 moments를 저장하며, Binary조건참일 경우 0의 값이 아닌 이미지 픽셀은 1의 값으로 처리하게됩니다.

cX, cY에 중심점을 계산하여 저장합니다. moments.*double형이기 때문에 int형식으로 변환합니다.

moments.*에는 Spatial Moments, Central Moments가 저장되어 있으며, 계산을 통하여 Central Normalized Moments를 얻을 수 있습니다.

  • Spatial Moments : M00, M01, M02, M03, M10, M11, M12, M20, M21, M30
  • Central Moments : Mu02, Mu03, Mu11, Mu12, Mu20, Mu21, Mu30
  • Central Normalized Moments : Nu02, Nu03, Nu11, Nu12, Nu20, Nu21, Nu30
  • Mu00 = M00, Mu01 = 0, Mu10 = 0
  • Nu00 = 1, Nu01 = 0, Nu10 = 0


질량 중심 공식


Central Normalized Moments 공식

위의 공식을 이용하여 중심점Central Normalized Moments를 구할 수 있습니다.



출력 결과

댓글 남기기