NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 팁 앤 테크
  • 매뉴얼

    팁과 테크니컬 노하우를 확인하세요.

    팁 앤 테크

    팁과 테크니컬 노하우를 확인하세요.

    본 사이트의 컨텐츠는 저작권법의 보호를 받으므로 무단 복사, 게재, 배포 등을 금합니다.

    커스텀 엔지엠 커스텀으로 OpenCV Contour 이미지 찾기. (Find OpenCV Contour images with NGM …

    페이지 정보

    본문

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

     

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

    PjRtlLn.png

     

     

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

    LZZEFQq.png

     

     

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

    nSjIepk.gif

     

     

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

    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);
            }
        }
    }

     

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

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    첨부파일

    댓글목록

    등록된 댓글이 없습니다.