c# Winform 개발/UI

앵커찾기 (With OpenCV)

bw50233 2021. 6. 21. 09:31

 

마우스로 클릭할때 OpenCV로 그린오브젝트(네모,폴리곤)에 포함되는지 확인하고할 때 썼었다.

 

OpenCVOjbect  = 그려진 오브젝트(네모,폴리곤).

 

각 꼭지점은 앵커라고 부르며 앵커의 경우 BLK로 조금 더 진하게 보이도록 UI에서 변경한 다음

 

마우스 클릭 이벤트에서 아래 함수를 호출하도록 해서 사용함. 

 

ex)

TL = Top Left

TM = Top Middle

TR = Top Right

BL = Bottom Left

...

 

public class Constant
    {
        public const int ANCHOR_LOC_TL = 1;
        public const int ANCHOR_LOC_TM = 2;
        public const int ANCHOR_LOC_TR = 3;
        public const int ANCHOR_LOC_LM = 4;
        public const int ANCHOR_LOC_RM = 5;
        public const int ANCHOR_LOC_BL = 6;
        public const int ANCHOR_LOC_BM = 7;
        public const int ANCHOR_LOC_BR = 8;
        
        public const int BLK = 4;
    }

 

#region 네모 앵커 찾기
        public bool pointInBoundRectangle(int x, int y, OpenCVOjbect dragObj)
        {
            bool isFind = false;
            if (pointInRect(x, y, dragObj.outRect.X - Constant.BLK, dragObj.outRect.Y - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_TL;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X + dragObj.outRect.Width - Constant.BLK, dragObj.outRect.Y - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_TR;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X - Constant.BLK, dragObj.outRect.Y + dragObj.outRect.Height - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_BL;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X + dragObj.outRect.Width - Constant.BLK, dragObj.outRect.Y + dragObj.outRect.Height - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_BR;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X + dragObj.outRect.Width / 2 - Constant.BLK, dragObj.outRect.Y - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_TM;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X + dragObj.outRect.Width / 2 - Constant.BLK, dragObj.outRect.Y + dragObj.outRect.Height - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_BM;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X - Constant.BLK, dragObj.outRect.Y + dragObj.outRect.Height / 2 - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_LM;
                isFind = true;
            }
            // endif
            if (pointInRect(x, y, dragObj.outRect.X + dragObj.outRect.Width - Constant.BLK, dragObj.outRect.Y + dragObj.outRect.Height / 2 - Constant.BLK, Constant.BLK * 4, Constant.BLK * 4))
            {
                dragObj.selectRectangleAnchor = Constant.ANCHOR_LOC_RM;
                isFind = true;
            }

            return isFind;
        }
        #endregion 네모 앵커 찾기
        #region 네모안에 포함되는지 찾기
        // 주의 : rx,ry,rw,rh는 음수가 되면 안됨. 2020.12.28
        public bool pointInRect(
            int pX,
            int pY,
            int rX,
            int rY,
            int rW,
            int rH)
        {
            if (((rX <= pX) && pX <= (rX + rW)) && ((rY <= pY) && pY <= (rY + rH)))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion 네모안에 포함되는지 찾기 끝

        #region 폴리곤 안에 포함되는지 찾기
        // Given three colinear points p, q, r, the function checks if 
        // point q lies on line segment 'pr' 
        bool onSegment(OpenCvSharp.Point p, OpenCvSharp.Point q, OpenCvSharp.Point r)
        {

            if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) &&
                    q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y))
                return true;
            return false;
        }

        // To find orientation of ordered triplet (p, q, r). 
        // The function returns following values 
        // 0 --> p, q and r are colinear 
        // 1 --> Clockwise 
        // 2 --> Counterclockwise 
        int orientation(OpenCvSharp.Point p, OpenCvSharp.Point q, OpenCvSharp.Point r)
        {
            int val = (q.Y - p.Y) * (r.X - q.X) -
                    (q.X - p.X) * (r.Y - q.Y);

            if (val == 0) return 0; // colinear 
            return (val > 0) ? 1 : 2; // clock or counterclock wise 
        }

        bool doIntersect(OpenCvSharp.Point p1, OpenCvSharp.Point q1, OpenCvSharp.Point p2, OpenCvSharp.Point q2)
        {
            // Find the four orientations needed for general and 
            // special cases 
            int o1 = orientation(p1, q1, p2);
            int o2 = orientation(p1, q1, q2);
            int o3 = orientation(p2, q2, p1);
            int o4 = orientation(p2, q2, q1);

            // General case 
            if (o1 != o2 && o3 != o4)
                return true;

            // Special Cases 
            // p1, q1 and p2 are colinear and p2 lies on segment p1q1 
            if (o1 == 0 && onSegment(p1, p2, q1)) return true;

            // p1, q1 and p2 are colinear and q2 lies on segment p1q1 
            if (o2 == 0 && onSegment(p1, q2, q1)) return true;

            // p2, q2 and p1 are colinear and p1 lies on segment p2q2 
            if (o3 == 0 && onSegment(p2, p1, q2)) return true;

            // p2, q2 and q1 are colinear and q1 lies on segment p2q2 
            if (o4 == 0 && onSegment(p2, q1, q2)) return true;

            return false; // Doesn't fall in any of the above cases 
        }
        public bool isInside(List<Point> polygon, int n, Point p)
        {
            // There must be at least 3 vertices in polygon[] 
            if (n < 3) return false;

            // Create a point for line segment from p to infinite 
            Point extreme = new Point(Constant.INF, p.Y);

            // Count intersections of the above line with sides of polygon 
            int count = 0, i = 0;
            do
            {
                int next = (i + 1) % n;

                // Check if the line segment from 'p' to 'extreme' intersects 
                // with the line segment from 'polygon[i]' to 'polygon[next]' 
                if (doIntersect(polygon[i], polygon[next], p, extreme))
                {
                    // If the point 'p' is colinear with line segment 'i-next', 
                    // then check if it lies on segment. If it lies, return true, 
                    // otherwise false 
                    if (orientation(polygon[i], p, polygon[next]) == 0)
                        return onSegment(polygon[i], p, polygon[next]);

                    count++;
                }
                i = next;
            } while (i != 0);

            // Return true if count is odd, false otherwise 
            return (count % 2 == 1);
        }
        #endregion 폴리곤 안에 포함되는지 찾기 끝
        #region 폴리곤 앵커 찾기
        public bool pointInBoundPolygon(int x, int y, OpenCVOjbect dragObj)
        {
            bool isFind = false;
            int polygonidx = 0;
            foreach (Point point in dragObj.polygonPoints)
            {
                if (pointInRect(x, y, point.X - Constant.BLK*2, point.Y - Constant.BLK*2, Constant.BLK * 4, Constant.BLK * 4))
                {
                    dragObj.selectPolygonAnchor = polygonidx;
                    
                    isFind = true;
                    break;
                }
                polygonidx++;
            }

            return isFind;
        }
        #endregion 폴리곤 앵커 찾기

300x250