數字影象處理筆記(三):使用OpenCV檢測影象特徵
阿新 • • 發佈:2018-12-15
1 - 引言
在數字影象處理中還提供了許多檢測影象簡單特徵的方法,例如邊緣檢測、輪廓檢測、直線檢測、圓檢測等。讓我們用OpenCV實現以下這些演算法吧
2 - Canny邊緣檢測
OpenCV提供了一個非常方便的Canny函式(以演算法的發明者命名)
import cv2 import numpy as np img = cv2.imread('images/12.jpg',0) cv2.imwrite("canny.jpg",cv2.Canny(img,200,300)) cv2.imshow("canny",cv2.imread("canny.jpg")) cv2.waitKey(0)
原始圖片:
輸出圖片:
Canny邊緣檢測演算法由5個步驟:
- 高斯濾波器對影象去噪
- 計算梯度
- 在邊緣上使用非最大抑制
- 在檢測到的邊緣上使用雙閾值去除假陽性
- 分析邊緣及其之間的連線,以保留真正的邊緣並消除不明顯的邊緣
3 - 輪廓檢測
在計算機視覺中,輪廓檢測是另一個比較重要的任務,不單是用來檢測影象或者視訊幀中物體的輪廓,而且還有其他操作與輪廓檢測有關。下面給出一個簡單的例子來檢測出正方形的輪廓
import cv2 import numpy as np img = np.zeros((200,200),dtype=np.uint8) img[50:150,50:150]=255 ret,thresh = cv2.threshold(img,127,255,0) image,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) color = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) img = cv2.drawContours(color,contours,-1,(0,255,0),2) cv2.waitKey(0)
找到一個正方形的輪廓很簡單,要找到不規則的就需要使用cv2.findContours與其他程式碼結合起來實現
import cv2 import numpy as np img = cv2.pyrDown(cv2.imread("images/test.jpg", cv2.IMREAD_UNCHANGED)) # threshold 函式對影象進行二化值處理,由於處理後圖像對原影象有所變化,因此img.copy()生成新的影象,cv2.THRESH_BINARY是二化值 ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY) # findContours函式查詢影象裡的圖形輪廓 # 函式引數thresh是影象物件 # 層次型別,引數cv2.RETR_EXTERNAL是獲取最外層輪廓,cv2.RETR_TREE是獲取輪廓的整體結構 # 輪廓逼近方法 # 輸出的返回值,image是原影象、contours是影象的輪廓、hier是層次型別 image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: # 輪廓繪製方法一 # boundingRect函式計算邊框值,x,y是座標值,w,h是矩形的寬和高 x, y, w, h = cv2.boundingRect(c) # 在img影象畫出矩形,(x, y), (x + w, y + h)是矩形座標,(0, 255, 0)設定通道顏色,2是設定線條粗度 cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # 輪廓繪製方法二 # 查詢最小區域 rect = cv2.minAreaRect(c) # 計算最小面積矩形的座標 box = cv2.boxPoints(rect) # 將座標規範化為整數 box = np.int0(box) # 繪製矩形 cv2.drawContours(img, [box], 0, (0, 0, 255), 3) # 輪廓繪製方法三 # 圓心座標和半徑的計算 (x, y), radius = cv2.minEnclosingCircle(c) # 規範化為整數 center = (int(x), int(y)) radius = int(radius) # 勾畫圓形區域 img = cv2.circle(img, center, radius, (0, 255, 0), 2) # # 輪廓繪製方法四 # 圍繞圖形勾畫藍色線條 cv2.drawContours(img, contours, -1, (255, 0, 0), 2) # 顯示影象 cv2.imshow("contours", img) cv2.waitKey() cv2.destroyAllWindows()
原始影象:
實驗影象:
** 凸輪廓與Douglas-Peucker演算法**
凸形狀內部的任意兩點的連線都在該形狀裡面,使用這個演算法後可以畫出一個凸包輪廓包圍著整個物體。
import cv2
import numpy as np
img = cv2.pyrDown(cv2.imread("images/15.jpg", cv2.IMREAD_UNCHANGED))
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) , 127, 255, cv2.THRESH_BINARY)
# findContours函式查詢影象裡的圖形輪廓
# 函式引數thresh是影象物件
# 層次型別,引數cv2.RETR_EXTERNAL是獲取最外層輪廓,cv2.RETR_TREE是獲取輪廓的整體結構
# 輪廓逼近方法
# 輸出的返回值,image是原影象、contours是影象的輪廓、hier是層次型別
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 建立新的影象black
black = cv2.cvtColor(np.zeros((img.shape[1], img.shape[0]), dtype=np.uint8), cv2.COLOR_GRAY2BGR)
for cnt in contours:
# 輪廓周長也被稱為弧長。可以使用函式 cv2.arcLength() 計算得到。這個函式的第二引數可以用來指定物件的形狀是閉合的(True) ,還是開啟的(一條曲線)
epsilon = 0.01 * cv2.arcLength(cnt, True)
# 函式approxPolyDP來對指定的點集進行逼近,cnt是影象輪廓,epsilon表示的是精度,越小精度越高,因為表示的意思是是原始曲線與近似曲線之間的最大距離。
# 第三個函式引數若為true,則說明近似曲線是閉合的,它的首位都是相連,反之,若為false,則斷開。
approx = cv2.approxPolyDP(cnt, epsilon, True)
# convexHull檢查一個曲線的凸性缺陷並進行修正,引數cnt是影象輪廓。
hull = cv2.convexHull(cnt)
# 勾畫影象原始的輪廓
cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2)
# 用多邊形勾畫輪廓區域
cv2.drawContours(black, [approx], -1, (255, 255, 0), 2)
# 修正凸性缺陷的輪廓區域
cv2.drawContours(black, [hull], -1, (0, 0, 255), 2)
# 顯示影象
cv2.imshow("hull", black)
cv2.waitKey()
cv2.destroyAllWindows()
4 - 直線檢測和圓檢測
直線檢測
import cv2
import numpy as np
img = cv2.imread('images/louvre_small.jpg')
# 灰度處理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# canny邊緣處理
edges = cv2.Canny(gray,50,120)
line = 100
minLineLength = 20
# HoughLinesP函式是概率直線檢測,注意區分HoughLines函式
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, lines=line, minLineLength=minLineLength)
# 降維處理
lines1 = lines[:,0,:]
# line 函式勾畫直線
# (x1,y1),(x2,y2)座標位置
# (0,255,0)設定BGR通道顏色
# 2 是設定顏色粗淺度
for x1,y1,x2,y2 in lines1:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
# 顯示影象
cv2.imshow("edges", edges)
cv2.imshow("lines", img)
cv2.waitKey()
cv2.destroyAllWindows()
實驗效果:
圓檢測
import cv2
import numpy as np
planets = cv2.imread('images/1.jpg')
# 灰度處理
gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY)
# medianBlur 平滑(模糊)處理
img = cv2.medianBlur(gray_img, 5)
# 灰度影象轉彩色影象
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
# 圓檢測
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=30, minRadius=50, maxRadius=100)
# 轉化整數
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# 勾畫圓形,planets影象、(i[0],i[1])圓心座標,i[2]是半徑
cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
# 勾畫圓心,圓心實質也是一個半徑為2的圓形
cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)
# 顯示影象
cv2.imwrite("planets_circles.jpg", planets)
cv2.imshow("mypic", cimg)
cv2.imshow("HoughCirlces", planets)
cv2.waitKey()
cv2.destroyAllWindows()