윤곽에서 사각형을 감지

13703 단어 파이썬OpenCV
OpenCV에서 윤곽을 얻을 수 있지만 원과 같은 허프 변환 기사는
인터넷에 많이 있지만 사각형을 감지하는 곳까지의 기사가
인터넷에서는 적었기 때문에 써 보자고 생각했습니다.
내 블로그에서도 Canny에서 가장자리를 얻고 결정하는 기사를 썼습니다.
이진화 처리가 조금 복잡하고, 에센스의 부분을 알기 어려웠기 때문에,
한층 더 심플한 것을 게재하려고 합니다.

처리 흐름



프로그램은 Python과 OpenCV를 사용합니다.
  • 이미지로드
  • 이미지의 그레이 스케일 및 이진화
  • 윤곽 얻기
  • 윤곽의 근사
    근사 조건의 근사 곡선 최대 거리를 윤곽 길이의 0.02로 한다(0.02는 임의)
    근사 처리에는 cv2.approxPolyDP()를 사용합니다.
  • 각 객체의 윤곽 사각형 결정

  •  1. 뿔이 4개 있다
     2. 면적값이 조건 이상 있음
     3. 볼록 형상이다
      isContourConvex() 사용
     4. 각 변이 이루는 모서리의 최대 코사인이 0.3 이하.
      삼각함수 코사인이 0.3을 취하는 것은 아래 그림을 보는 조정이 됩니다.
       정사각형은 코사인 1.0이 이상적인 값입니다.

    삼각 함수 그래프
      

    샘플 코드



    findSquares.py
    import cv2
    import math
    import numpy as np
    
    # pt0-> pt1およびpt0-> pt2からの
    # ベクトル間の角度の余弦(コサイン)を算出
    def angle(pt1, pt2, pt0) -> float:
        dx1 = float(pt1[0,0] - pt0[0,0])
        dy1 = float(pt1[0,1] - pt0[0,1])
        dx2 = float(pt2[0,0] - pt0[0,0])
        dy2 = float(pt2[0,1] - pt0[0,1])
        v = math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) )
        return (dx1*dx2 + dy1*dy2)/ v
    
    # 画像上の四角形を検出
    def findSquares(bin_image, image, cond_area = 1000):
        # 輪郭取得
        contours, _ = cv2.findContours(bin_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
        for i, cnt in enumerate(contours):
            # 輪郭の周囲に比例する精度で輪郭を近似する
            arclen = cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, arclen*0.02, True)
    
            #四角形の輪郭は、近似後に4つの頂点があります。
            #比較的広い領域が凸状になります。
    
            # 凸性の確認 
            area = abs(cv2.contourArea(approx))
            if approx.shape[0] == 4 and area > cond_area and cv2.isContourConvex(approx) :
                maxCosine = 0
    
                for j in range(2, 5):
                    # 辺間の角度の最大コサインを算出
                    cosine = abs(angle(approx[j%4], approx[j-2], approx[j-1]))
                    maxCosine = max(maxCosine, cosine)
    
                # すべての角度の余弦定理が小さい場合
                #(すべての角度は約90度です)次に、quandrangeを書き込みます
                # 結果のシーケンスへの頂点
                if maxCosine < 0.3 :
                    # 四角判定!!
                    rcnt = approx.reshape(-1,2)
                    cv2.polylines(image, [rcnt], True, (0,0,255), thickness=2, lineType=cv2.LINE_8)
        return image
    
    def main():
        image = cv2.imread('shapes_image.png', cv2.IMREAD_COLOR)
        if image is None :
            exit(1)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        _, bw = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
        rimage = findSquares(bw, image)
        cv2.imshow('Square Detector', rimage)
        c = cv2.waitKey()
        return 0;
    
    if __name__ == '__main__':
        main()
    

    입력 이미지




    위의 도형에서 사각형을 감지합니다.

    결과 이미지




    윤곽을 빨간색으로 둘러싼 곳이 검출한 사각형입니다.
    임계값은 단맛이 되어 있으므로, 좌하의 사다리꼴도 검출하고 있습니다.

    운영 환경



    Windows10
    아나콘다 3
    파이썬 3.9.0
    OpenCV 4.4.0
    numpy 1.19.2

    요약



    이 방법은 docs.opencv.org - samples/cpp/squares.cpp의 샘플 코드를보고,
    그것을 참고로 하고 있습니다.
    기하학 계산뿐이므로이 트릭은 그리 어렵지 않고 잘하는 방법입니다.
    감탄했습니다.
    실제로 이미지 처리로 사용하려면 이진화 또는 에지 감지 및 윤곽 근사 조정이
    간이 될까 생각합니다.

    참고



    Emotion Explorer - OpenCV 사각형 감지
    docs.opencv.org - samples/cpp/squares.cpp
    docs.opencv.org - Structural Analysis and Shape Descriptors

    좋은 웹페이지 즐겨찾기