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
留言
張貼留言