OpenCV学習+共通関数記録③:ホーフ変換と輪郭抽出


OpenCVホフ変換と輪郭抽出
  • 3. ホフ変換
  • 3.1ホフ直線
  • 3.2ホフ円
  • 4. 輪郭抽出
  • 4.1輪郭検索
  • 4.2描画輪郭

  • 3.ホフ変換
    まずホフ変換公式ドキュメントを置きます:[ホフ直線変換公式ドキュメント]
    3.1ホフ直線
    import cv2 as cv
    import matplotlib.pyplot as plt
    import numpy as np
    
    # 1.              
    img = cv.imread("../img/weiqi.jpg", cv.IMREAD_COLOR)
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    # 2.         
    _, thresh_img = cv.threshold(gray_img, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
    
    # 3.     
    #              ,double   ,   1.0
    rho = 1
    #              ,   numpy.pi/180(       )
    theta = np.pi / 180
    #          ,int  ,             ,   ,             ,         。(             )
    threshold = 10
    #              
    min_line_length = 25
    #                        (  ),      ,            ,   ,          ,            
    max_line_gap = 3
    
    lines = cv.HoughLinesP(thresh_img, rho, theta, threshold, minLineLength=min_line_length, maxLineGap=max_line_gap)
    
    dst_img = img.copy()
    
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv.line(dst_img, (x1, y1), (x2, y2), (0, 0, 255), 2)
    
    cv.imshow("src", img)
    cv.imshow("gray_img", gray_img)
    cv.imshow("thresh_img", thresh_img)
    cv.imshow("dst_img", dst_img)
    
    cv.waitKey(0)
    

    3.2ホフ円
    import cv2 as cv
    import numpy as np
    
    # 1.              
    img = cv.imread("../img/weiqi.jpg", cv.IMREAD_COLOR)
    gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    
    # 2.       
    def hough_circle(gray_img):
        #            。          cv2.HOUGH_GRADIENT
        method = cv.HOUGH_GRADIENT
        #                。  ,  dp = 1,                 。  dp = 2,              。
        dp = 1
        #               。  minDist  ,              。  minDist  ,            。
        minDist = 20
        # param1 Canny      
        # param2 cv2.HOUGH_GRADIENT        。    ,        。
        # minRadius :      ,     ,    
        # maxRadius :      ,    ,    
        circles = cv.HoughCircles(gray_img, method, dp, minDist=minDist, param1=70, param2=30, minRadius=0, maxRadius=20)
    
        dst_img = img.copy()
        for circle in circles[0, :]:
            #     ,  
            x, y, r = circle
            #     
            cv.circle(dst_img, (x, y), 2, (0, 255, 0), 1)
            #     
            cv.circle(dst_img, (x, y), r, (0, 0, 255), 2)
    
            cv.imshow("src", img)
            cv.imshow("result", dst_img)
    
    
    # 3.     ,     
    hough_circle(gray_img)
    
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    4.輪郭抽出
  • 画像エッジ抽出または二値化に基づく対象輪郭探索
  • エッジ抽出の閾値が最終的に輪郭発見結果に影響する
  • 主要APIは以下の2つ
  • findContours輪郭発見
  • drawContours描画輪郭

  • 4.1輪郭の検索
         ,     ,      = cv.findContours(  ,       ,       )
    
    # hierarchy[i][3],     i         、     、   、         
    

    輪郭検索モード:RETR_EXTERNAL最外層プロファイルのみ検出RETR_LISTすべてのプロファイルを抽出しリストに配置し、検出したプロファイルは等級関係を確立しないRETR_CCOMPすべてのプロファイルを抽出し、プロファイルを二層構造(two-level hierarchy)に組織し、最上位層は連通域の周辺境界であり、二次層位内層境界RETR_TREE全ての輪郭を抽出し網状輪郭構造を再構築
    輪郭検索アルゴリズム:CHAIN_APPROX_NONE各輪郭の各画素を取得し、隣接する2点の画素位置差が1を超えないCHAIN_APPROX_SIMPLE水平方向、垂直方向、対角線方向の要素を圧縮し、その方向の重点座標のみを保持し、長方形の輪郭が4点で輪郭情報を保存する場合CHAIN_APPROX_TC89_L1Teh-Chinlチェーン近似アルゴリズムCHAIN_APPROX_TC89_KCOSTeh-Chinlチェーン近似アルゴリズム
    4.2輪郭の描画
    cv.drawContours(  ,     ,       -1     ,     ,      )
    
    ((x,y),radius) = cv.minEnclosingCircle(contour)		#      
    

    実装手順:
  • 画像を読み取る
  • 1枚グレーにして
  • 画像の二値化処理
  • findContoursで輪郭を探す
  • 輪郭の処理
  • import cv2 as cv
    
    # 1.     
    def read_rgb_img(img_name):
        rgb_img = cv.imread(img_name, cv.IMREAD_COLOR)
        cv.imshow("rgb img", rgb_img)
        return rgb_img
    
    # 2.            
    def convert_rgb2gray(img):
        gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        return gray_img
    
    # 3.           
    def convert_gray2binary(img):
        # binary_img = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 2)
        _, binary_img = cv.threshold(img, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
        return binary_img
    
    # 4.   findContours    
    def getContours(img):
        _, contours, hierarchy = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
        print(contours, hierarchy)
        return contours
    
    # 5.        
    def draw_contours(img, contours):
        index = -1                  			#      
        thickness = 2              	 			#      
        color = (255, 125, 125)    				#      
        imgg = cv.drawContours(img, contours, index, color, thickness)
        cv.imshow('draw contours', imgg)		#      
        for i, c in enumerate(contours):
            circle = cv.minEnclosingCircle(c)
            ((x, y), radius) = circle
            cv.circle(imgg, (int(x), int(y)), int(radius), (0, 0, 255), 2)
    
    
    if __name__ == '__main__':
        img_name = "../img/shape.jpg"
    
        rgb_img = read_rgb_img(img_name)
        gray_img = convert_rgb2gray(rgb_img)
        binary_imgage = convert_gray2binary(gray_img)
        contours = getContours(binary_imgage)
        draw_contours(rgb_img, contours)
    
        cv.imshow("gray_img", gray_img)					#      
        cv.imshow("binary_img", binary_imgage)			#      
        cv.imshow('draw_contours_circle', rgb_img)		#           
        cv.waitKey(0)
        cv.destroyAllWindows()