Try   HackMD
tags: OpenCV,輪廓檢測

OpenCV 輪廓檢測- contour detection(籃網偵測,字母模板偵測)

  • 輪廓通常是從邊緣獲得的,但它們的目標是成為對象輪廓,因此,它們需要是閉合曲線。

contour偵測處理流程
![](https://i.imgur.com/eIMevYA.jpg

把輪廓找出來-
findContours語法
contours, hierarchy = cv2.findContours(source_image, retrieval_mode, approx_method)

output的部分有兩塊

  1. contours-找出來的輪廓
  2. hierarchy-找出來的輪廓,彼此間有沒有關係? 有沒有小輪廓是在大輪廓裡面的?

input的部分
1.source_image-目標照片
2.retrieval_mode-擷取模式

  • cv2.RETR_EXTERNAL-只擷取最外圍的輪廓
  • cv2.RETR_LIST-擷取大大小小所有輪廓,擷取結果沒有父子關係,大家都平等
  • cv2.RETR_CCOMP-會列出內、外兩層關係
  • cv2.RETR_TREE-會列出完整所有關係

3.approx_method-輪廓紀錄方式

  • cv2.CHAIN_APPROX_NONE-最精細紀錄模式
  • cv2.CHAIN_APPROX_SIMPLE-只記錄畫出輪廓的關鍵點

把輪廓畫出來-
drawContours語法
marked_img = cv2.drawContours(img, contours, contourIdx,color,thickness, lineType = cv.LINE_8, hierarchy = cv.Mat(), maxLevel = INT_MAX, offset = cv.Point(0, 0)))
input的部分
1.img-BGR目標照片,要標註輪廓的照片
2.contours-我們偵測到的輪廓
3.contourIdx-你要畫的輪廓,如果你要畫全部的輪廓,就用-1
4.color-BGR,畫輪廓的顏色
5.lineType
6.offset-偏離程度

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
進行contour偵測前,有一個關鍵,圖最好是黑底白圖(目標是白色的)

實作

import cv2

image = cv2.imread('basketball.jpg')
#我們等一下需要一張乾淨的底圖來標示
imageCopy= image.copy()
cv2.imshow('BGR image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#轉灰階
gray_image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', gray_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#轉二元圖
ret,binary_im = cv2.threshold(gray_image,100, 255,cv2.THRESH_BINARY)
cv2.imshow('binary', binary_im)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

contours,hierarchy = cv2.findContours(binary_im,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#設定一下drawContours的參數
contours_to_plot= -1 #畫全部
plotting_color= (0,255,0)#畫綠色框
thickness= -1
#開始畫contours
with_contours = cv2.drawContours(image,contours, contours_to_plot, plotting_color,thickness)
cv2.imshow('contours', with_contours)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#標示矩形邊框
for cnt in contours:
    x,y,w,h = cv2.boundingRect(cnt)
    image = cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,255),2)
cv2.imshow('contours', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#根據面積,挑出籃網的部分
required_contour = max(contours, key = cv2.contourArea)
x,y,w,h = cv2.boundingRect(required_contour)
img_copy2 = cv2.rectangle(imageCopy, (x,y),(x+w, y+h),(0,255,255),2)
cv2.imshow('largest contour', img_copy2)
cv2.waitKey(0)
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

cv2.boundingRect
矩形邊框(Bounding Rectangle)是說,用一個最小的矩形,把找到的形狀包起來。
cv2.boundingRect(img)
img是一個二值圖,也就是它的參數;
返回四個值,分別是x,y,w,h( x,y是矩型左上點的坐標,w,h是矩型的寬和高)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

cv2.contourArea
計算輪廓的面積
cv2.contourArea(contour, oriented=True)
contour:表示某輸入單個輪廓,為array
oriented:表示某個方向上輪廓的面積值,這裡指順時針或者逆時針。若為True,該函數返回一個帶符號的面積值,正負值取決於輪廓的方向(順時針還是逆時針),若為False,表示以絕對值返回

cv2.arcLength
計算輪廓的周長
cv2.arcLength(contour, closed=True)
contour:表示某輸入單個輪廓,為array
closed:用於指示曲線是否封閉

cv2.approxPolyDP
cv2.approxPolyDP()函數是輪廓近似函數,是opencv中對指定的點集進行多邊形逼近的函數,其逼近的精度可通過參數設置
approxPolyDP(curve, epsilon, closed, approxCurve=None)
curve:表示輸入的點集
epslion:指定的精度,也即原始曲線與近似曲線之間的最大距離,不過這個值我們一般按照周長的大小進行比較
close:若為True,則說明近似曲線為閉合的;反之,若為False,則斷開

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
找模板實作比對

import cv2 
#讀取照片
image = cv2.imread('phrase_handwritten.png') 
cv2.imshow( 'Original image' ,image )
cv2.waitKey(0) 
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#轉灰階
gray_image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 
#轉二元
ret,binary_im = cv2.threshold(gray_image,0,255,cv2.THRESH_OTSU) 
cv2.imshow( 'binary image' , binary_im )
cv2.waitKey(0) 
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#找輪廓
contours_list,hierarchy = cv2.findContours(binary_im,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 
for cnt in contours_list:
    x,y,w,h = cv2.boundingRect(cnt)
    cv2.rectangle(image,(x,y),(x+w,y+h),(0, 255, 255),2) 
cv2.imshow( 'Contours marked on RGB image' , image )
cv2.waitKey(0) 
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#做模板
ref_gray = cv2.imread('b3.png', cv2.IMREAD_GRAYSCALE) 
ret, ref_binary = cv2.threshold(ref_gray,0,255,cv2.THRESH_OTSU) 
cv2.imshow( 'Reference image' , ref_binary )
cv2.waitKey(0) 
cv2.destroyAllWindows()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

#開始比較
ref_contour_list,hierarchy = cv2.findContours(ref_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 
if len(ref_contour_list)==1:
    ref_contour= ref_contour_list[0]
else:
    print('找到的模板輪廓超過1個,需要確認一下用哪一個?')

ctr= 0
dist_list= []
for cnt in contours_list:
    retval=cv2.matchShapes(cnt, ref_contour,cv2.CONTOURS_MATCH_I1,0)
    dist_list.append(retval)
    ctr= ctr+1

min_dist= min(dist_list)   #找出距離最近的     
ind_min_dist= dist_list.index(min_dist)   #挑出那張圖
required_cnt= contours_list[ind_min_dist]
x,y,w,h = cv2.boundingRect(required_cnt)
imagecopy= cv2.imread('phrase_handwritten.png')

cv2.rectangle(imagecopy,(x,y),(x+w,y+h),(255, 0, 0),2) 
cv2.imshow( 'Detected B' , imagecopy )
cv2.waitKey(0) 
cv2.destroyAllWindows()