邊緣是零零散散的,而輪廓是一個整體
cv2.findContours(img,mode,method)
img:輸入圖像對象名稱
mode:輪廓檢索模式
RETR_EXTERNAL:只檢索最外面的輪廓
RETR_LIST:檢索所有的輪廓,并將其保存到一條鏈表當中
RETR_CCOMP:檢索所有的輪廓,并將他們組織為兩層;頂層是各部分的外部邊界,第二層為空洞的邊界
RETR_TREE:檢索所有的輪廓,并重構嵌套輪廓的整個層次(最常用)
method:輪廓逼近方法
CHAIN_APPROX_NONE:以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)
CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分
為了更高的精確率,盡量最好使用二值圖像
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()#做之前需要對照片進行二值處理
img = cv2.imread('E:\Jupyter_workspace\study\data/cfx.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#轉換為灰度圖
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#對圖像進行二值處理,小于127為0,大于127為255
show_photo('thresh',thresh)binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)show_photo('binary',binary)#就是作完二值操作的結果np.array(contours).shape#是一群list結構的輪廓點,保存一些輪廓的信息
#結果為:(2,)#hierarchy是一個層級,把結果全部保存到層級里面
二值處理后的圖像
binary參數實則就是二值處理后的圖像
繪制輪廓
cv2.drawContours(draw_img,contours,-1,(0,0,255),2)
參數1:一個照片對象名稱
參數2:輪廓是什么
參數3:畫第幾個輪廓,-1表示把所有的輪廓都畫出來
參數4:(B,G,R)畫輪廓的線是什么顏色的
參數5:線條的寬度
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()#做之前需要對照片進行二值處理
img = cv2.imread('E:\Jupyter_workspace\study\data/cfx.png')
show_photo('img ',img )gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#轉換為灰度圖
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#對圖像進行二值處理,小于127為0,大于127為255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)draw_img = img.copy()#注意一定要copy要不然會對原圖進行改變!!!
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),2)#-1表示顯示所有輪廓,(0,0,225)BGR表示紅色,2為輪廓粗細
show_photo('-1 is All',res)draw_img = img.copy()#注意一定要copy要不然會對原圖進行改變!!!
res = cv2.drawContours(draw_img,contours,0,(0,0,255),2)#0表示顯示第0個輪廓,(0,0,225)BGR表示紅色,2為輪廓粗
show_photo('zero',res)draw_img = img.copy()#注意一定要copy要不然會對原圖進行改變!!!
res = cv2.drawContours(draw_img,contours,1,(0,0,255),2)#1表示顯示第1個輪廓,(0,0,225)BGR表示紅色,2為輪廓粗
show_photo('one',res)
原圖:
顯示所有輪廓(里外)
顯示第0個輪廓(外)
顯示第1個輪廓(內)
輪廓特征
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/cfx.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#轉換為灰度圖
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#對圖像進行二值處理,小于127為0,大于127為255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)cnt = contours[0]#contours存放所有輪廓的信息,這里取第一個輪廓cv2.contourArea(cnt)#第一個輪廓所對應的面積
#結果為:20909.0cv2.arcLength(cnt,True)#第一個輪廓所對應的周長,True表示閉合的
#結果為:612.0
輪廓近似
輪廓近似:舉例子拿曲線AB進行近似計算
1,首先直線連接AB,再曲線AB上找到離AB直線最遠的一點C,點C到直線AB的距離為d1
2,用戶需要自定義一個值epsilon作為閾值
3,將d1與閾值epsilon進行比較;若d1 < epsilon可直接將直線AB代替曲線AB,近似結束若d1 > epsilon則,連接直線AC和直接BC在曲線AC上找離直線AC最短的一點D,點D到直線AC的距離為d2若d2 < epsilon可直接將直線AC代替曲線AC若d2 > epsilon則做同樣的操作在曲線BC上找離直線BC最短的一點E,點E到直線BC的距離為d3同樣的操作
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo.png')
show_photo('img ',img )gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)cnt = contours[0]draw_img = img.copy()
res =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
show_photo('res',res)
原圖:
輪廓近似后效果
近似函數:
cv2.approxPolyDP(cnt,epsilon,True)
參數1:傳入要近似的輪廓
參數2:自定義一個值來進行輪廓比較,一般是按周長的百分比進行設置的
參數3:輪廓是否封閉
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo.png')
show_photo('img ',img )gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)epsilon = 0.1*cv2.arcLength(cnt,True)#倍數越小越接近本身輪廓
approx = cv2.approxPolyDP(cnt,epsilon,True)draw_img = img.copy()
res =cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
show_photo('res',res)
原圖:
近似函數處理過后的圖像:
邊界矩形
獲得輪廓的邊緣矩形:cv2.boundingRect(cnt)
參數:指定操作的對象是哪個輪廓
返回值:輪廓對應的邊緣矩形的x,y坐標和w,h寬高值
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo1.png')
show_photo('img',img)#原圖gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
res, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]#這里的輪廓取得是第0個,當然也可以取其他的輪廓x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
show_photo('img',img)area = cv2.contourArea(cnt)#輪廓面積
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h #輪廓對應的邊緣矩形的面積,寬×高為對應邊緣矩形的面積
extent = float(area) / rect_area
print('輪廓面積與邊界矩形之比',extent)
#結果為:輪廓面積與邊界矩形之比 0.5113636363636364
原圖:
獲取第0個輪廓邊界矩形:
外接圓
import cv2
import numpy as np
from matplotlib import pyplot as pltdef show_photo(name,picture):#圖像顯示函數cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/lunkuo1.png')
show_photo('img',img)gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
res, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]#對輪廓0操作,當然也可以換成其他的輪廓x, y, w, h = cv2.boundingRect(cnt)
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)#(B,G,R),2為輪廓粗細程度
show_photo('img',img)
原圖:
對第0輪廓進行外接圓操作: