OpenCV Contour 이미지 찾기. (Find OpenCV Contour images with NGM custom module.)

1

NGM RPA

목록 보기
2/3

원본 글 보기 - 엔지엠소프트웨어

안녕하세요. 엔지엠소프트웨어입니다. 오늘은 [ 이미지 서치 ]나 [ 이미지 매치 ]와 같은 템플릿 매칭이 아닌 컨투어(Contour)를 이용해서 비슷한 모양의 오브젝트를 찾는 방법을 알아보겠습니다. 일반적으로 대부분의 이미지 찾는 매크로나 RPA 소프트웨어들이 OpenCV의 Templete matching을 사용합니다. 여기에~ 사용하기 편하게 약간의 양념을 쳐둔거죠. 엔지엠 RPA도 OpenCV의 템플릿 매칭을 사용하고 있습니다. 이외에도 욜로 딥러닝도 있지만요^^;

아래 이미지는 찾을 이미지입니다.


아래 이미지는 바탕화면 또는 모니터라고 생각하세요.


아래는 커스텀 모듈로 동일한 오브젝트를 찾는 동영상입니다.


동일한 모양의 오브젝트(팔각형 도형)를 잘 찾아줍니다. 아래는 커스텀 모듈의 전체 소스입니다.

using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;

namespace CustomContourImageMatch
{
    [Serializable]
    public class ContourImageMatchModel : NGM.Models.Interface.BaseCustomToolModel
    {
        /// <summary>
        /// 도구 상자에 표시될 카테고리 이름을 가져옵니다.
        /// </summary>
        public override string DisplayCategory => "NGMsoftware";

        /// <summary>
        /// 도구 상자에 표시될 액션 이름을 가져옵니다.
        /// </summary>
        public override string DisplayName => "모양 찾기";

        [Category("Data")]
        [DisplayName("좌표 목록")]
        [Description("찾은 오브젝트의 위치 목록입니다.")]
        [Browsable(true)]
        [DefaultValue(null)]
        [ReadOnly(true)]
        public System.Drawing.Point[] Points { get; set; }

        [Category("Data")]
        [DisplayName("일치율 목록")]
        [Description("일치율 목록입니다. 이 값이 높을수록 원본 오브젝트와 유사합니다.")]
        [Browsable(true)]
        [DefaultValue(null)]
        [ReadOnly(true)]
        public double[] Scores { get; set; }

        [Category("Action")]
        [DisplayName("일치율")]
        [Description("일치율입니다. 이 값보다 큰 오브젝트만 검출합니다.")]
        [Browsable(true)]
        [DefaultValue(5.0)]
        public double MatchRate { get; set; } = 5.0;

        [Category("Action")]
        [DisplayName("이미지 선택")]
        [Description("찾을 이미지 파일을 선택합니다.")]
        [Browsable(true)]
        [DefaultValue(null)]
        [Editor(typeof(NGM.Models.TypeEditor.OpenFileSelectorEditor), typeof(UITypeEditor))]
        public string ImagePath { get; set; }

        public override void Execute()
        {
            var desktop = NGM.Utility.ScreenCaptureManager.ScreenShot.DesktopCapture();

            using (Mat source = Cv2.ImRead(ImagePath))
            {
                using (Mat target = OpenCvSharp.Extensions.BitmapConverter.ToMat((Bitmap)desktop))
                {
                    // 찾을 이미지를 흑백으로 변환
                    Cv2.CvtColor(source, source, ColorConversionCodes.BGR2GRAY);
                    // 바탕화면 이미지를 흑백으로 변환
                    Cv2.CvtColor(target, target, ColorConversionCodes.BGR2GRAY);

                    // 바이너리 변환
                    var sourceThreshod  = Cv2.Threshold(source, source, 127, 255, ThresholdTypes.BinaryInv);
                    var targetThreshod = Cv2.Threshold(target, target, 127, 255, ThresholdTypes.BinaryInv);
                    
                    Cv2.FindContours(source, 
                        out OpenCvSharp.Point[][] sourceContourPoints, 
                        out HierarchyIndex[] sourceHierarchyIndex, 
                        RetrievalModes.External, 
                        ContourApproximationModes.ApproxSimple);

                    Cv2.FindContours(target, 
                        out OpenCvSharp.Point[][] targetContourPoints,
                        out HierarchyIndex[] targetHierarchyIndex, 
                        RetrievalModes.External, 
                        ContourApproximationModes.ApproxSimple);

                    List<Contour> matchs = new List<Contour>();

                    // 매치 오브젝트를 처리합니다.
                    foreach (var contourPoints in targetContourPoints)
                    {
                        var match = Cv2.MatchShapes(sourceContourPoints.First(), contourPoints, ShapeMatchModes.I2);
                        var m = double.Parse(match.ToString().Substring(0, 8));

                        if (m > this.MatchRate)
                            matchs.Add(new Contour(m, contourPoints));
                    }

                    matchs = matchs.OrderByDescending(o => o.MatchScore).ToList();

                    this.Scores = matchs.Select(s => s.MatchScore).ToArray();
                    this.Points = matchs.Select(s => s.CenterPoint()).ToArray();
                }
            }
        }
    }
}

도형의 좌표에서 센터를 찾기 위한 컨투어 모델입니다.

using OpenCvSharp;

namespace CustomContourImageMatch
{
    public class Contour
    {
        public double MatchScore { get; set; }

        public OpenCvSharp.Point[] MatchPoints { get; set; }

        public Contour(double matchScore, OpenCvSharp.Point[] matchPoints)
        {
            this.MatchScore = matchScore;
            this.MatchPoints = matchPoints;
        }

        public System.Drawing.Point CenterPoint()
        {
            int totalX = 0, totalY = 0;

            foreach (Point p in MatchPoints)
            {
                totalX += p.X;
                totalY += p.Y;
            }
            
            int centerX = totalX / MatchPoints.Length;
            int centerY = totalY / MatchPoints.Length;

            return new System.Drawing.Point(centerX, centerY);
        }
    }
}

좀 더 다듬으면 유사한 오브젝트를 검출할 수 있을겁니다. 참고로, 컨투어는 외각선을 인식해야 하기 때문에 흑백화를 해준 후 임계값으로 흰색과 검은색만 남겨둡니다. 그러면 외각선을 검출하기가 용이하죠^^; 위 코드에서 적용하지는 않았지만... 노이즈를 제거하기 위해서는 가우시안 블러를 사용하면 좀 더 효과적일겁니다. 노이즈가 많으면 오브젝트를 찾는데 방해가 되거든요~ 이 예제에서 사용한 스크립트는 첨부되어 있으니 다운로드 받아서 테스트 해보세요.

원본 글 보기 - 엔지엠소프트웨어

0개의 댓글