<button id="ssm6u"><optgroup id="ssm6u"></optgroup></button>
  • 跳轉至

    連通域的外接矩形

    概要

    阿凱在連通域的輪廓點集 中介紹了尋找二值化圖像輪廓的方法. 接下來我們還想找到輪廓對應的矩形區域(外接矩形).

    尋找外接矩形有兩種策略. 一種是尋找輪廓邊緣的部分, 找到最外面的那個外接矩形, 為了區分, 我們稱之為正外接矩形 boundingRect, 如下圖綠色矩形部分.

    另外一種策略是矩形可以旋轉, 找到面積最小的矩形, 剛剛好可以把輪廓套在里面,我們稱之為*最小外接矩形 * minAreaRect, 如下圖藍色矩形部分.

    cv2_min_rect_rect_bounding.jpg

    圖片來源: Python+OpenCV教程14:輪廓特征

    接下來阿凱會分別介紹opencv中的這兩個函數.

    keywords 外接矩形 最小外借矩形 boundingRect minAreaRect

    1. 知識回顧-findContours

    阿凱手繪了這幾個數字. 接下來呢,阿凱想把這些數字所在的矩形區域表示出來, 并截取出單獨的圖片.

    color_number_handwriting.png

    連通域的輪廓點集 中阿凱介紹了四種提取輪廓的模式, 那么我們應該用哪個呢?

    首先問幾個問題:

    1. 我們是否關心內輪廓 ? -> 否

    如果識別內輪廓的話, 以6舉例, 就會識別到左邊的這個矩形區域.

    Screenshot_20180212_100416.png

    1. 我們是否關系繼承關系 ? -> 否

    數字圖片 沒有繼承關系。

    ?

    所以我們應該使用cv2.RETR_EXTERNAL模式

    源代碼

    import numpy as np
    import cv2
    
    # 讀入黑背景下的彩色手寫數字
    img = cv2.imread("color_number_handwriting.png")
    # 轉換為gray灰度圖
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 尋找輪廓
    bimg, contours, hier = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    

    2. 正外接矩形 boudningRect

    函數比較簡單, 傳入唯一的參數是輪廓點集(單個) Points.

    rect = cv2.boundingRect(cnt)
    (x, y, w, h) = rect
    

    返回值 rect , 數據結構是tuple, 分別為矩形左上角坐標(x, y), 與矩形的寬度w 高度h

    我們依次打印矩形區域的信息.

    for cidx,cnt in enumerate(contours):
        (x, y, w, h) = cv2.boundingRect(cnt)
        print('RECT: x={}, y={}, w={}, h={}'.format(x, y, w, h))
    

    OUTPUT

    RECT: x=92, y=378, w=94, h=64
    RECT: x=381, y=328, w=69, h=102
    RECT: x=234, y=265, w=86, h=70
    RECT: x=53, y=260, w=61, h=95
    RECT: x=420, y=184, w=49, h=66
    RECT: x=65, y=124, w=48, h=83
    RECT: x=281, y=71, w=70, h=108
    

    繪制在畫布上比較直觀:

    number_boundingrect_canvas.png

    截取ROI圖片的操作比較簡單img[y:y+h, x:x+w]

    # 截取ROI圖像
    cv2.imwrite("number_boudingrect_cidx_{}.png".format(cidx), img[y:y+h, x:x+w])
    

    這樣我們就截取到了獨立的單個數字的圖片.

    Screenshot_20180212_100512.png

    源代碼 CH5.2_bounding_rect.py

    import numpy as np
    import cv2
    
    # 讀入黑背景下的彩色手寫數字
    img = cv2.imread("color_number_handwriting.png")
    # 轉換為gray灰度圖
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 尋找輪廓
    bimg, contours, hier = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # 聲明畫布 拷貝自img
    canvas = np.copy(img)
    
    for cidx,cnt in enumerate(contours):
        (x, y, w, h) = cv2.boundingRect(cnt)
        print('RECT: x={}, y={}, w={}, h={}'.format(x, y, w, h))
        # 原圖繪制圓形
        cv2.rectangle(canvas, pt1=(x, y), pt2=(x+w, y+h),color=(255, 255, 255), thickness=3)
        # 截取ROI圖像
        cv2.imwrite("number_boudingrect_cidx_{}.png".format(cidx), img[y:y+h, x:x+w])
    
    cv2.imwrite("number_boundingrect_canvas.png", canvas)
    

    3. 最小外接矩形 minAreaRect

    minAreaRect 函數用于獲取最小面積的矩形。

    minAreaRect = cv2.minAreaRect(cnt)
    

    我們打印一下minAreaRect 查看其返回的數據結構:

    ((133.10528564453125, 404.7727966308594), (100.10702514648438, 57.51853942871094), -49.184913635253906)
    

    數據結構解析

    ((cx, cy), (width, height), theta)
    
    • cx 矩形中心點x坐標 center x

    • cy 矩形中心點y坐標 center y

    • width 矩形寬度

    • height 矩形高度

    • theta 旋轉角度,角度(不是弧度

    注意: 上述值均為小數, 不可以直接用于圖片索引,或者矩形繪制.

    詳情見圖

    20170803134202667.png

    圖片來源 python opencv minAreaRect 生成最小外接矩形

    注意:旋轉角度θ是水平軸(x軸)逆時針旋轉,與碰到的矩形的第一條邊的夾角。并且這個邊的邊長是width,另一條邊邊長是height。也就是說,在這里,width與height不是按照長短來定義的。

    在opencv中,坐標系原點在左上角,相對于x軸,逆時針旋轉角度為負,順時針旋轉角度為正。

    為了直觀起見, 我們可以直接這樣賦值

    ((cx, cy), (width, height), theta) = cv2.minAreaRect(cnt)
    

    完整一些的演示樣例:

    for cidx,cnt in enumerate(contours):
        ((cx, cy), (width, height), theta) = cv2.minAreaRect(cnt)
        print('center: cx=%.3f, cy=%.3f, width=%.3f, height=%.3f, roate_angle=%.3f'%(cx, cy, width, height, theta))
    

    OUTPUT

    center: cx=133.105, cy=404.773, width=100.107, height=57.519, roate_angle=-49.185 
    center: cx=415.190, cy=378.853, width=66.508, height=100.537, roate_angle=-1.710  
    center: cx=278.323, cy=296.089, width=71.608, height=78.065, roate_angle=-78.440  
    center: cx=83.000, cy=307.000, width=60.000, height=94.000, roate_angle=0.000     
    center: cx=448.346, cy=213.731, width=47.068, height=64.718, roate_angle=-11.310  
    center: cx=89.642, cy=164.695, width=17.204, height=88.566, roate_angle=-25.427   
    center: cx=330.578, cy=123.387, width=92.325, height=72.089, roate_angle=-66.666 
    

    *如何獲取四個頂點? *

    20170803134202667.png

    利用cv2.boxPoints 函數, 我們可以獲取矩形區域的四個頂點的坐標。序號如上圖所示。

    minAreaRect = cv2.minAreaRect(cnt)
    print(cv2.boxPoints(minAreaRect))
    

    樣例輸出

    [[ 122.15498352  461.4520874 ]
     [  78.62363434  423.85681152]
     [ 144.05558777  348.09350586]
     [ 187.58694458  385.68878174]]
    

    你看這個數據結構是不是跟contour的數據結構是類似的。

    阿凱突然想到, 其實可以使用drawContours函數繪制。

    前提我們還需要將浮點數坐標轉換成整數。

    # 聲明畫布 拷貝自img
    canvas = np.copy(img)
    
    for cidx,cnt in enumerate(contours):
        minAreaRect = cv2.minAreaRect(cnt)
        # 將浮點數坐標轉換成整數
        rectCnt = np.int64(cv2.boxPoints(minAreaRect))
        cv2.drawContours(canvas, [rectCnt], 0, (0,255,0), 3)
    
    cv2.imwrite("number_minarearect_canvas.png", canvas)
    

    number_minarearect_canvas.png

    我們也可以使用多邊形繪制的函數進行繪制, 可能你需要復習一下 OpenCV繪圖-章節導引

    這里阿凱換了一種顏色繪制。

    # 繪制多邊形
    cv2.polylines(img=canvas, pts=[rectCnt], isClosed=True, color=(0,0,255), thickness=3)
    

    number_minarearect_canvas2.png

    完整一些的代碼

    import numpy as np
    import cv2
    
    # 讀入黑背景下的彩色手寫數字
    img = cv2.imread("color_number_handwriting.png")
    # 轉換為gray灰度圖
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 尋找輪廓
    bimg, contours, hier = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # 聲明畫布 拷貝自img
    canvas = np.copy(img)
    
    for cidx,cnt in enumerate(contours):
        minAreaRect = cv2.minAreaRect(cnt)
        # 轉換為整數點集坐標
        rectCnt = np.int64(cv2.boxPoints(minAreaRect))
        # 繪制多邊形
        cv2.polylines(img=canvas, pts=[rectCnt], isClosed=True, color=(0,0,255), thickness=3)
    
    cv2.imwrite("number_minarearect_canvas.png", canvas)
    

    ## 4. 作業 Homework

    Task01 - 獲取棋子底部的坐標并繪制

    給大家準備了一下測試樣例.

    你需要提取圖片中的棋子的位置,找到棋子所在的矩形區域,并且標注棋子底部中心點.

    Screenshot_20180212_115550.png

    請自行學習opencv輪廓contours的其他屬性opencv文檔-py_contour_features

    • 質心 moment

    • 面積 Area

    • 周長 perimeter

    • 邊緣近似

    • 凸包 與凸包性

    • 矩形區域 bounding rectangle

    • 最小矩形區域

    • 最小閉合圓形區域 minimum encolosing circle

    • 橢圓區域 fitting an ellipse

    • 線 fitting a line

    并用于輪廓的濾波,排除不相干色塊區域的干擾.

    除此之外你還可以利用橫寬比,寬度,高度作為濾波條件.

    Task02 - 提取旋轉的矩形

    我們目前可以繪制圖片中旋轉的矩形了, 那么你有辦法將他們提取出來么?

    請自行搜索圖像變換的資料,將數字提取出來。

    提示: 圖像旋轉 變換

    • cv2.getRotationMatrix2D 獲取旋轉矩陣

    • cv2.warpAffine 變換

    number_minarearect_canvas2.png

    拓展:將矩形區域放縮到統一尺寸, 例如20*10


    韩国精品无码一区二区三区,精品无码一区二区三区AV,欧洲丰满美熟女乱又伦AV,亚洲午夜久久久影院伊人