markdown
#說明
前一篇以影像處理的方法,去做去除文字,主要是偵測RGB的值,寫 rule的方法去去除,那這一篇是用找尋邊緣的方式去除文字。
#操作流程
##Code
```
import cv2
import numpy as np
def draw_contours(img, cnts):  # conts = contours
    img = np.copy(img)
    img = cv2.drawContours(img, cnts, -1, (0, 255, 0), 2)
    return img
def draw_min_rect_circle(img, cnts):  # conts = contours
    img = np.copy(img)
    for cnt in cnts:  # 這邊的 cnts 是一整組的輪廓,裡面有很多個點,所以是對每一個點去做 for 迴圈
        x, y, w, h = cv2.boundingRect(cnt)
        # cv2.boundingRect這個函數為替輪廓加入邊框,用來標示圖片中特定物體的法
        # 輸入值是輪廓,輸出值為,一組四個值,分別表示左上角的x與y,和寬和長
        # 參考: https://chtseng.wordpress.com/2016/12/05/opencv-contour%E8%BC%AA%E5%BB%93/
        #cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)  # blue
        # cv2.rectangle 這個函數是繪製方框,輸入值為 影像,和頂點座標,和對項座標,框線的顏色,框線的寬度 =這裡是藍色框
        rectangle = ([[x, y], [x + w, y], [x, y + h], [x + w, y + h]])
        area1 = np.array([[x, y], [(x + w), y], [x, (y + h)], [(x + w), (y + h)]])
        img2=cv2.fillPoly(img, [area1], (0, 0, 0))
        cv2.namedWindow('3', cv2.WINDOW_NORMAL)
        cv2.resizeWindow("3", 640, 480)
        cv2.imshow("3", img)
        # cv2.waitKey(1943)
        cv2.waitKey(0)
        cv2.imwrite("result3.jpg", img)
        min_rect = cv2.minAreaRect(cnt)  # 最小矩陣,會返回 ( (最小外接矩形的中心座標),(寬和高),旋轉角度 )
        # 參考:https://www.itread01.com/content/1548357888.html
        min_rect = np.int0(cv2.boxPoints(min_rect))  # 輪廓點原本是浮點數(有小數點的),轉換成整數
        #area1 = np.array([[x, y], [(x + w), y], [x, (y + h)], [(x + w), (y + h)]])
        img2 = cv2.fillPoly(img, [min_rect], (0, 0, 0))
        cv2.namedWindow('3', cv2.WINDOW_NORMAL)
        cv2.resizeWindow("3", 640, 480)
        cv2.imshow("3", img)
        # cv2.waitKey(1943)
        cv2.waitKey(0)
        cv2.imwrite("result5.jpg", img)
        #cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2)  # green #畫輪廓#綠色
        (x, y), radius = cv2.minEnclosingCircle(cnt)  # 這個和剛剛的很相似,剛剛是畫矩形,這裡是畫圓形
        # 這邊畫圓形,所以返回值是圓心的座標(x,y) 和半徑
        center, radius = (int(x), int(y)), int(radius)  # center and radius of minimum enclosing circle
        #img = cv2.circle(img, center, radius, (0, 0, 255), 2)  # red #畫成紅色的圓形
    return img  # 返回影像所以這個影像包含了藍色框線和綠色的矩形和紅色的圓形
def draw_approx_hull_polygon(img, cnts):
    # img = np.copy(img)
    img = np.copy(img)
    img = np.zeros(img.shape, dtype=np.uint8)
    # img2=np.zeros(img2.shape, dtype=np.uint8)
    #cv2.drawContours(img, cnts, -1, (255, 0, 0), 2)  # blue
    # cv2.drawContours 這個函式是用來繪製輪廓的,根據邊界點繪製任何形狀
    # 輸入的參數,第一個是原始影像,第二個是輪廓這是一個列表的資料型態,
    # 第三個是輪廓的索引(index),如果設置-1,就是畫全部的輪廓,最後一個參數是輪廓的顏色=(255,0,0)藍色和厚度=2
    # 參考 https://www.kancloud.cn/aollo/aolloopencv/272892
    print(cnts)
    cv2.fillPoly(img, cnts, (0, 0, 0))
    cv2.imwrite("result4.jpg", img)
    min_side_len = img.shape[0] / 32  # 多邊形邊長的最小值
    min_poly_len = img.shape[0] / 16  # 多邊形周長的最小值
    min_side_num = 3  # 多邊形邊數的最小值
    approxs = [cv2.approxPolyDP(cnt, min_side_len, True) for cnt in cnts]  # 以最小邊長為限制繪製多邊形
    # cv2.approxPolyDP 函數,這個是做對多邊形進行逼近,可以為多邊形加上限制
    # 導致原本的多邊形的點數很多,經由這個函數後會減少邊的點數,代表邊也減少了
    # 舉例來說可能有一個80邊的多邊形,經由 cv2.approxPolyDP 函數 加上限制後,就會可能變成8邊的多邊形
    # 參考: https://gogoprivateryan.blogspot.com/2015/08/opencv-2-opencv-python.html
    approxs = [approx for approx in approxs if cv2.arcLength(approx, True) > min_poly_len]  # 篩選出周長大於 min_poly_len 的多邊形
    approxs = [approx for approx in approxs if len(approx) > min_side_num]  # 篩選出邊長大於 min_side_num 的多邊形
    #cv2.polylines(img, approxs, True, (0, 255, 0), 2)  # green  #繪製多邊形輪廓綠色的
    cv2.fillPoly(img, approxs, 1)
    hulls = [cv2.convexHull(cnt) for cnt in cnts]  # cv2.convexHull這函數可以找出圖的凸多邊形框,類似找到中心點然後包含所有的輪廓點的最小框
    # 參考:https://gogoprivateryan.blogspot.com/2015/08/opencv-2-opencv-python.html
    # 網址裡面有一個手長的那個多邊形就是那個概念
    print(hulls)
    #cv2.polylines(img, hulls, True, (0, 0, 255), 2)  # red #繪製多邊形輪廓紅色
    cv2.fillPoly(img, hulls, 1)
    cv2.imwrite("result.jpg", img)
    return img  # 最後傳回一張有三個顏色的影像,藍色綠色紅色 ,這裡都是多邊形
def run():
    image = cv2.imread('./1.jpg')  # 1.讀取影像
    thresh = cv2.Canny(image, 600, 700)  # 這個canny 後面接三個參數,第一個參數是影像,第二個是最小值,第三個是最大值
    # cv2.Canny 參考:https://www.jianshu.com/p/e8e1f2f1c605
    # 返回值是偵測到邊緣的影像
    # cv2.findContours 輸入的參數有三個,第一個是影像,第二個是輪廓檢索模式,第三個是輪廓近似方法)
    # 返回值,以前的版本返回值有三個,現在新版返回值是兩個,所以常常直接套用網路上的 code 會有 bug,需要修正
    # 這邊的兩個返回值,第一個是影像,第二個是輪廓,每一個輪廓都是一個 Numpy 的數組 => [110 123] 類似這樣的,包含邊界座標
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # cv2.findContours 輸入的參數有三個,第一個是影像,第二個是輪廓檢索模式,第三個是輪廓近似方法)
    # 返回值,以前的版本返回值有三個,現在新版返回值是兩個,所以常常直接套用網路上的 code 會有 bug,需要修正
    # 返回值如果是三個的話,第一個是影像,第二個是輪廓,第三個是輪廓的結構
    # 這邊的兩個返回值,第一個是輪廓,第二個是輪廓的結構,每一個輪廓都是一個 Numpy 的數組 => [110 123] 類似這樣的,包含邊界座標
    # 參考: https://www.kancloud.cn/aollo/aolloopencv/272892
    imgs = [
        image, thresh,
        draw_min_rect_circle(image, contours),  # 這裡呼叫函數draw_min_rect_circle,投入兩個參數:影像和輪廓
        draw_approx_hull_polygon(image, contours),  # 這也是呼叫函數 draw_approx_hull_polygon,投入兩個參數:影像和輪廓
    ]
    for img in imgs:
        # cv2.imwrite("%s.jpg" % id(img), img)
        cv2.namedWindow('contours', cv2.WINDOW_NORMAL)
        cv2.resizeWindow("contours", 640, 480)
        cv2.imshow("contours", img)
        # cv2.waitKey(1943)
        cv2.waitKey(0)
if __name__ == '__main__':
    run()
pass
```
##DEMO
留言
張貼留言