3.五、Canny邊緣檢測算法
OpenCV提供了Canny邊緣檢測函數來識別邊緣。它有5個步驟:使用高斯濾波器對圖像進行去噪、計算梯度、在邊緣上使用最大抑制(NMS)、在檢測到的邊緣上使用雙閥值去除數組
假陽性(false positive),最後還會分析出全部的邊緣及其之間的鏈接,以保留真正的邊緣並消除不明顯的邊緣。app
import cv2 import numpy as np img = cv2.imread("flower.jpg") cv2.imwrite("canny.jpg", cv2.Canny(img, 200, 300)) cv2.imshow("image", img) cv2.imshow("canny", cv2.imread("canny.jpg")) cv2.waitKey() cv2.destroyAllWindows()
運行效果:函數
在計算機視覺中,輪廓檢測是另外一個比較重要的任務,不單是用來檢測圖像或視頻中物體的輪廓,並且還有其餘操做與輪廓檢測有關。這些操做有:計算多邊形邊界、優化
形狀逼近和計算感興趣區域。這是與圖像數據交互時的簡單操做,由於NumPy中的矩形區域可使用數組切片(slice)來定義。在介紹物體檢測(包括人臉)和物體跟蹤的概念時會大量使用這種技術。ui
import cv2 import numpy as np import os img = np.zeros((200, 200), dtype = np.uint8) # 建立一個200x200大小的黑色空白圖像, img[50:150, 50:150] = 255 # 在圖像的中央放置一個白色方塊 ret, thresh = cv2.threshold(img, 127, 255, 0) #對圖像進行二值化操做 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, 0, 255), 5) # 畫出輪廓,-1,表示全部輪廓,畫筆顏色爲(0, 255, 255),即Red,粗細爲5 cv2.imshow("contours",color) cv2.waitKey() cv2.destroyAllWindows()
findContours()函數有三個參數:輸入圖像、層次類型和輪廓逼近方法。spa
這個函數會修改輸入圖像,所以建議使用原始圖像的一份拷貝(如:經過img.copy()來做爲輸入圖像)。3d
由函數返回的層次樹至關重要:cv2.RETR_TREE參數會獲得圖像中輪廓的總體層次結構,以此來創建輪廓之間的「關係」。若是隻想獲得最外面的輪廓,可以使用cv2.RETR_EXTERNAL。code
這對消除包含在其餘輪廓中的輪廓頗有用(如在大多數情形下,不須要檢測一個目標包含在另外一個與之相同的目標裏面)orm
findContours()函數有三個返回值:修改後的圖像、圖像的輪廓以及它們的層次。使用輪廓來畫出圖像的彩色版本(即把輪廓畫成綠色),並顯示出來。
注意:返回三個值報錯,實際上只返回兩個值(圖像的輪廓以及它們的層次)
cv2.threshold()簡單閾值
這個函數有四個參數,第一個原圖像,第二個進行分類的閾值,第三個是高於(低於)閾值時賦予的新值,第四個是一個方法選擇參數,經常使用的有:
cv2.THRESH_BINARY(黑白二值)
cv2.THRESH_BINARY_INV(黑白二值反轉)
cv2.THRESH_TRUNC (獲得的圖像爲多像素值)
cv2.THRESH_TOZERO
cv2.THRESH_TOZERO_INV
該函數有兩個返回值,第一個retVal(獲得的閾值(在後面一個方法中會用到)),第二個就是閾值化後的圖像。
cvCvtColor(...)是Opencv裏的顏色空間轉換函數,能夠實現RGB顏色向HSV,HSI等顏色空間的轉換,也能夠轉換爲灰度圖像。參數CV_RGB2GRAY是RGB到gray。參數 CV_GRAY2RGB是gray到RGB.處理結果是彩色的,則轉灰色就是了
運行效果以下:
找到一個正方形輪廓很簡單,要找到不規則的、歪斜的以及旋轉的形狀可用 OpenCV的cv2.findContours函數,它能獲得最好的結果,下面來看一幅圖像:
現實的應用對目標的邊界框、最小矩形面積、最小閉圓特別感興趣。將cv2.findContours函數與少許的OpenCV的功能想結合就能很是容易地實現這些功能。
繪製矩形
函數:cv2.rectangle(img,(380,0),(511,111),(255,0,0),3),須要肯定的就是矩形的兩個點(左上角與右下角),顏色,線的類型(不設置就默認)
import cv2 import numpy as np import os from matplotlib import pyplot as plt img = np.zeros((512,512,3),np.uint8) #生成一個空彩色圖像 cv2.rectangle(img,(20,20),(411,411),(0,255,0),5) plt.imshow(img,'brg') plt.show()
import cv2 import numpy as np import os img = cv2.pyrDown(cv2.imread("hammer.png", cv2.IMREAD_UNCHANGED)) ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY) contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: # find bounding box coordinates # 現計算出一個簡單的邊界框 x, y, w, h = cv2.boundingRect(c) # 將輪廓信息轉換成(x, y)座標,並加上矩形的高度和寬度 cv2.rectangle(img, (x,y), (x+w, y+h), (0, 255, 0), 2) # 畫出矩形 # find minimum area # 計算包圍目標的最小矩形區域 rect = cv2.minAreaRect(c) # calculate coordinate of the minimum area rectangle box = cv2.boxPoints(rect) # normalize coordinates to integers box =np.int0(box) # 注:OpenCV沒有函數能直接從輪廓信息中計算出最小矩形頂點的座標。因此須要計算出最小矩形區域, # 而後計算這個矩形的頂點。因爲計算出來的頂點座標是浮點型,可是所得像素的座標值是整數(不能獲取像素的一部分), # 因此須要作一個轉換 # draw contours cv2.drawContours(img, [box], 0, (0, 0, 255), 3) # 畫出該矩形 # calculate center and radius of minimum enclosing circle (x, y), radius = cv2.minEnclosingCircle(c) # 會返回一個二元組,第一個元素爲圓心的座標組成的元組,第二個元素爲圓的半徑值。 # cast to integers center = (int(x), int(y)) radius = int(radius) # draw the circle img = cv2.circle(img, center, radius, (0, 255, 0), 2) cv2.drawContours(img, contours, -1, (255, 0, 0), 1) cv2.imshow("contours", img) cv2.waitKey() cv2.destroyAllWindows()
在導入模塊後,加載圖像,而後在源圖像的灰度圖像上執行一個二值化操做。這樣作以後,可在這個灰度圖像上執行全部計算輪廓的操做,但在源圖像上可利用色彩信息來畫這些輪廓。
cv2.drawContours(img, [box], 0, (0, 0, 255), 3):首先,該函數與全部繪圖函數同樣,它會修改源圖像。其次,該函數的第二個參數接收一個保存着輪廓的數組,
從而能夠在一次操做中繪製一系列的輪廓。所以若是隻有一組點來表示多邊形輪廓,就須要把這組點放到一個數組裏。該函數的第三個參數是要繪製的輪廓數組的索引:-1表示繪製全部的輪廓,
不然只會繪製輪廓數組裏指定的輪廓。大多數繪圖函數把繪圖的顏色和密度(thickness)放在最後兩個參數裏。
函數介紹:
cv2.imread():讀入圖片,共兩個參數,第一個參數爲要讀入的圖片文件名,第二個參數爲如何讀取圖片,包括cv2.IMREAD_COLOR:讀入一副彩色圖片;
cv2.IMREAD_GRAYSCALE:以灰度模式讀入圖片;cv2.IMREAD_UNCHANGED:讀入一幅圖片,幷包括其alpha通道。cv2.imread('flower.jpg',0)表示已灰度模式讀入
cv2.imshow():建立一個窗口顯示圖片,共兩個參數,第一個參數表示窗口名字,能夠建立多個窗口中,可是每一個窗口不能重名;第二個參數是讀入的圖片。
cv2.waitKey():鍵盤綁定函數,共一個參數,表示等待毫秒數,將等待特定的幾毫秒,看鍵盤是否有輸入,返回值爲ASCII值。若是其參數爲0,則表示無限期的等待鍵盤輸入。
cv2.destroyAllWindows():刪除創建的所有窗口
cv2.destroyWindows():刪除指定的窗口。
cv2.imwrite():保存圖片,共兩個參數,第一個爲保存文件名,第二個爲讀入圖片
Opencv中能夠經過函數cv2.pyrDown()和cv2.pyrUp()來構建金字塔。
函數cv2.pyrDown()是從一個高分辨率圖像變成低分辨率圖像的。cv2.pyrDown()函數接受3個參數:
tmp: 當前圖像,初始化爲原圖像 src 。
dst: 目的圖像( 顯示圖像,爲輸入圖像的一半)
Size( tmp.cols/2, tmp.rows/2 ) :目的圖像大小, 既然咱們是向下採樣
凸輪廓與Douglas-Peucker算法
大多數處理輪廓的時候,物體的形狀(包括凸形狀)都是變化多樣的。凸形狀內部的任意兩點之間的連線都在該形狀裏面。
cv2.approxPloyDP是一個OpenCV函數,它用來計算近似的多邊形框。該函數有三個參數:
第一個參數爲「輪廓」;
第二個參數爲「ε值」,它表示源輪廓與近似多邊形的最大差值(這個值越小,近似多邊形與源輪廓越接近);
第三個參數爲「布爾標記」,它表示這個多邊形是否閉合。
ε值對獲取有用的輪廓很是重要。是爲所獲得的近似多邊形周長與源輪廓周長之間的最大差值,這個差值越小,近似多邊形與源輪廓就越類似。
可經過OpenCV的cv2.arcLength函數來獲得輪廓的周長信息。
epsilon = 0.01 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
可經過OpenCV來有效地計算一個近似多邊形,多邊形周長與源輪廓周長之比就爲ε。
爲了計算凸形狀,須要用OpenCV的cv2.convexHull函數來獲取處理過的輪廓信息,代碼爲:
hull = cv2.convexHull(cnt)
3.八、直線和圓檢測
Hough變換是直線和形狀檢測背後的理論基礎。
繪製直線
函數爲:cv2.line(img,Point pt1,Point pt2,color,thickness=1,line_type=8 shift=0)
有值的表明有默認值,不用給也行。能夠看到這個函數主要接受參數爲兩個點的座標,線的顏色(彩色圖像的話顏色就是一個1*3的數組)
import cv2 import numpy as np import os from matplotlib import pyplot as plt img = np.zeros((512,512),np.uint8)#生成一個空灰度圖像 cv2.line(img,(0,200),(511,511),255,5) plt.imshow(img,'gray') plt.show()
import cv2 import numpy as np import os from matplotlib import pyplot as plt img = np.zeros((512,512,3),np.uint8)#生成一個空彩色圖像 cv2.line(img,(200,0),(511,511),(0,255,0),5) plt.imshow(img,'brg') plt.show()
3.九、直線檢測
直線檢測可經過HoughLines和HoughLinesP函數來完成,它們僅有的差異是:第一個函數使用標準的Hough變換,第二個函數使用機率Hough變換。HoughLinesP函數之因此成爲
機率版本的Hough變換是由於它只經過分析點的子集並估計這些點都屬於一條直線的機率,這是標準Hough變換的優化版本,該函數的計算代價會少一些,執行會變得更快。
import cv2 import numpy as np img = cv2.imread("lines.png") gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, 50, 120) minLineLength = 20 maxLineGap = 5 lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap) for x1, y1, x2, y2 in lines[0]: cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow("edges", edges) cv2.imshow("lines", img) cv2.waitKey() cv2.destroyAllWindows()
HoughLines函數會接收一個由Canny邊緣檢測濾波器處理過的單通道二值圖像,不必定須要Canny濾波器,可是一個通過去噪並只有邊緣的圖像看成Hough變換的輸入會很不錯。
HoughLinesP的參數:
須要處理的參數;
線段的幾何表示rho和theta,通常分別取1和np.pi/180;
閾值,低於該閾值的直線會被忽略,Hough變換能夠理解爲投票箱和投票數之間的關係,每個投票箱表明一個直線,投票數達到閾值的直線會被保留,其餘的會被刪除。
minLineLength和maxLineGap
3.十、繪製圓
繪製圓形只須要肯定圓心與半徑,函數: cv2.circle (img,(380,0),63,(255,0,0),3),
import cv2 import numpy as np from matplotlib import pyplot as plt img = np.zeros((512,512,3),np.uint8)#生成一個空彩色圖像 cv2.circle(img,(100,100),50,(55,255,155),5) plt.imshow(img,'brg') plt.show(
3.十一、圓檢測
OpenCV的HoughCircles函數可用來檢測圓,它與使用HoughLines函數相似。像用來決定刪除或保留直線的兩個參數minLineLength和maxLineGap同樣,
HoughCircles有一個圓心間的最小距離和圓的最小及最大半徑。
import cv2 import numpy as np planets = cv2.imread("planet_glow.png") gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY) img = cv2.medianBlur(gray_img, 5) cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 120, param1=100, param2 = 30, minRadius = 0, maxRadius = 0) circles = np.uint16(np.around(circles)) for i in circles[0,:]: # draw the outer circle cv2.circle(planets, (i[0], i[1]), i[2],(0, 255, 0),2) # draw the center of the circle cv2.circle(planets, (i[0], i[1]), 2, (0, 0,255), 3) cv2.imwrite("planets_circles.jpg",planets) cv2.imshow("HoughCircles", planets) cv2.waitKey() cv2.destroyAllWindows()
3.十二、繪製橢圓
橢圓涉及到長軸短軸,橢圓圓心,旋轉角度等。
import cv2 import numpy as np from matplotlib import pyplot as plt img = np.zeros((512,512,3),np.uint8)#生成一個空彩色圖像 cv2.ellipse(img,(256,256),(150,100),0,0,180,250,-1) #注意最後一個參數-1,表示對圖像進行填充,默認是不填充的,若是去掉,只有橢圓輪廓了 plt.imshow(img,'brg') plt.show()
3.1三、檢測其餘形狀
Hough變換能檢測的形狀僅限於圓,前面提到過檢測任何形狀的方法,特別是用approxPloyDP函數來檢測,該函數提供多邊形的近似,因此若是你的圖像有多邊形,再結合cv2.findContours函數和
cv2.approxPloyDP函數,就能至關準確地檢測出來。