程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

python opencv邊緣檢測

編輯:Python

通過Opencv進行邊緣檢測可以說是十分常見了,接下來讓我們聊一聊如何通過python opencv一步一步實現邊緣檢測

重要函數講解

圖片讀取函數:

pic = cv2.imread(file_path, flag=None)

參數:

  • file_path:讀取的圖片的路徑。這裡要注意如果圖像不能讀取(由於文件丟失、權限不當、格式不支持或無效),函數返回一個NULL。文件的格式取決於具體的圖像的格式,而不是圖像的後綴名。
  • flag:圖像的格式。這裡使用的是 cv2.IMREAD_UNCHANGED代表的是讀取的是源圖像。也可以使用cv2.IMREAD_GRAYSCALE讀取的是灰度圖。

返回值:

  • pic:加載後返回的圖像。解碼後的圖像將按B G R 順序存儲通道。使用 IMREAD_GRAYSCALE 時,將使用編解碼器的內部灰度轉換。

注意:結果可能與 cvtColor() 的輸出不同。編解碼器附帶 OpenCV 圖像(libjpeg、默認使用 libpng、libtiff 和 libjasper)。因此,OpenCV 始終可以讀取 JPEG、PNG、TIFF。而Linux需要安裝隨操作系統映像提供的編解碼器libjpeg-dev


攝像頭讀取函數:

cap = cv2.VideoCapture(CAMERA_ID)

參數

  • CAMERA_ID:代表的是攝像頭的ID號,一般情況下0代表的是內置的攝像頭。若要讀取的是視頻則為視頻的具體的路徑,如./test.avi。

返回值

  • 初始化好的攝像頭設備

攝像頭讀取視頻幀函數:

ret, frame = cap.read()

  • cap.read()按幀讀取視頻

返回值

  • ret是布爾值,如果讀取幀是正確的則返回True,如果文件讀取到結尾,它的返回值就為False。
  • frame就是每一幀的圖像,是個RGB圖像的三維矩陣。如果未抓取任何幀,則圖像將為空。不允許修改或發布圖片,只是使用的是副本圖像進行相關的操作。

高斯濾波函數:

gs_frame=cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
說明:將源圖像與指定的高斯核進行卷積
參數

  • src:輸入圖像。圖像可以有任意數量的通道,這些通道被獨立處理,但深度應為 CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F。
  • ksize:ksize.width 和 ksize.height 可以不同,但​​它們都必須是正數和奇數。或者,它們可以是零,然後根據 sigma 計算它們。
  • sigmaX:X 方向的高斯核標准偏差
  • dst:輸出與 src 大小和類型相同的結果圖像
  • sigmaY:Y 方向的高斯核標准偏差;如果 sigmaY 為零,則設置為等於 sigmaX,如果兩個 sigma 都為零,則根據 ksize.width 和 ksize.height 計算它們.
  • borderType:像素外推方法。使用默認值即可。

inRange()函數實現二值化

OpenCV中的inRange()函數可實現二值化功能(這點類似threshold()函數
inRange_hsv=cv2.inRange((InputArray src, InputArray lowerb,InputArray upperb, OutputArray dst)

參數

  • src:輸入要處理的圖像,可以為單通道或多通道。
  • lowerb:包含下邊界的數組或標量。
  • upperb:包含上邊界數組或標量
  • dst:輸出圖像,與輸入圖像src 尺寸相同且為CV_8U 類型。也可以作為返回值處理

返回值

  • inRange_hsv:輸出圖像,與輸入圖像src 尺寸相同且為CV_8U 類型。也可以作為返回值處理

形態學腐蝕函數

img_erosion=cv2.erode(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
說明:通過使用特定的結構元素侵蝕圖像。該函數使用確定的指定結構元素侵蝕源圖像,取最小值的像素鄰域的形狀.侵蝕可以應用幾次(迭代),對於多通道圖像,每個通道都是獨立處理的。
參數

  • src:輸入圖像.通道的數量可以是任意的,但深度應該是CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F。
  • kernel:用於腐蝕的內核結構元素。一般為奇數(3,3)、(5,5)的卷積核等等
  • dst:輸出與 src 大小和類型相同的圖像
  • anchor:元素內錨點的錨點位置;默認值 (-1, -1) 表示錨點位於元素中心。
  • iterations:迭代應用侵蝕的次數
  • borderType:像素外推方法
  • borderValue:邊界的值為恆定的值

返回值

  • img_erosion:腐蝕後的圖像,與 src 大小和類型相同的圖像

形態膨脹學函數

說明:通過使用特定的結構元素來擴大圖像。該函數使用指定的結構元素來擴展源圖像,該結構元素確定取最大值的像素鄰域的形狀。
dilate_img=cv2.dilate(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)

參數

  • src:輸入圖像.通道的數量可以是任意的,但深度應該是CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F。
  • kernel:用於膨脹的內核結構元素。一般為奇數(3,3)、(5,5)的卷積核等等
  • dst:輸出與 src 大小和類型相同的圖像
  • anchor:元素內錨點的錨點位置;默認值 (-1, -1) 表示錨點位於元素中心。
  • iterations:迭代應用膨脹的次數
  • borderType:像素外推方法
  • borderValue:邊界的值為恆定的值

返回值

  • dilate_img:膨脹後的圖像,與 src 大小和類型相同的圖像

開、閉操作

morphologyEx_frame=cv2.morphologyEx(src, op, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
說明:使用腐蝕和膨脹來執行高級形態變換,開操作就是先腐蝕後膨脹
參數

  • src:輸入圖像.通道的數量可以是任意的,但深度應該是CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F。
  • op:形態學操作的類型. cv2.MORPH_OPEN、cv2.MORPH_CLOSE分別為開操作和閉操作
  • kernel:用於腐蝕或者膨脹的內核結構元素。一般為奇數(3,3)、(5,5)的卷積核等等
  • dst:輸出與 src 大小和類型相同的圖像
  • anchor:元素內錨點的錨點位置;默認值 (-1, -1) 表示錨點位於元素中心。
  • iterations:迭代應用侵蝕和膨脹的次數
  • borderType:像素外推方法
  • borderValue:邊界的值為恆定的值

返回值

  • morphology_frame:開或者閉操作的圖像,與 src 大小和類型相同的圖像

sobel算子

sobel算子簡介:sobel算子認為,鄰域的像素對當前像素產生的影響不是等價的,所以距離不同的像素具有不同的權值,對算子結果產生的影響也不同。一般來說,距離越遠,產生的影響越小。

sobel算子原理: 對傳進來的圖像像素做卷積,卷積的實質是在求梯度值,或者說給了一個加權平均,其中權值就是所謂的卷積核;然後對生成的新像素灰度值做阈值運算,以此來確定邊緣信息。x方向的梯度會加強圖像水平方向的特征,而y方向的梯度會加強圖像豎直方向的特征

sobel=cv2.Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)
說明:Sobel 算子結合了高斯平滑和微分,所以結果或多或少耐噪音。大多數情況下,函數被調用( xorder = 1, yorder = 0, ksize = 3)或 ( xorder = 0, yorder = 1, ksize = 3) 計算第一個 x 或 y 圖像導數。

參數

  • src:輸入圖像
  • ddepth:輸入圖像的深度。-1表示采用的是與原圖像相同的深度。目標圖像的深度必須大於等於原圖像的深度。如果是8 位輸入圖像它會導致截斷導數。
  • dx:導數x的順序
  • dy:導數y的順序
  • dst:輸出圖像。和輸入圖像具有相同的深度
  • ksize:擴展 Sobel 內核的大小;它必須是 1、3、5 或 7
  • scale:計算導數值的可選比例因子。默認情況下,沒有縮放
  • delta:可選的增量,將會加到最終的dst中,同樣,默認情況下沒有額外的值加到dst中
  • borderType:像素外推方法

權重取絕對值函數

dst=cv2.convertScaleAbs(src, dst=None, alpha=None, beta=None)
說明:由於sobel算子算出的值會產生負值,否則負數會一律當做0處理,所以要使用取絕對值函數。在輸入數組的每個元素上,函數 convertScaleAbs依次執行三個操作:縮放、取絕對值,轉換為無符號 8 位類型。在多通道數組的情況下,該函數處理每個通道獨立。當輸出不是 8 位時,操作可以是通過調用 Mat::convertTo 方法(或使用矩陣表達式),然後計算結果的絕對值。

參數

  • src:輸入數組
  • dst:輸出數組
  • alpha:可選比例因子
  • beta:可選增量添加到縮放值

加權函數

add_weight_img=cv2.addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None)

說明:計算兩個數組的加權和: dst = src1alpha + src2beta + gamma

參數

  • src1:第一個輸入數組
  • alpha:第一個數組元素的 alpha 權重
  • src2:具有相同大小和通道號的第二個輸入數組
  • beta:第二個數組元素的 beta 權重
  • gamma:標量添加到每個總和
  • dst:輸出數組,其大小和通道數與輸入數組相同
  • dtype:輸出數組的可選深度;當兩個輸入數組具有相同的深度時,dtype可以設置為 -1,相當於 src1.depth()

scharr算子

scharr_img=cv2.Scharr(src, ddepth, dx, dy, dst=None, scale=None, delta=None, borderType=None)

說明:雖然Sobel算子可以有效的提取圖像邊緣,但是對圖像中較弱的邊緣提取效果較差。因此為了能夠有效的提取出較弱的邊緣,需要將像素值間的差距增大。Scharr算子是對Sobel算子差異性的增強,因此兩者之間的在檢測圖像邊緣的原理和使用方式上相同。Scharr算子的邊緣檢測濾波的尺寸為3×3,因此也有稱其為Scharr濾波器。可以通過將濾波器中的權重系數放大來增大像素值間的差異.

參數

  • src:輸入圖像
  • ddepth:輸入圖像的深度。-1表示采用的是與原圖像相同的深度。目標圖像的深度必須大於等於原圖像的深度。如果是8 位輸入圖像它會導致截斷導數。
  • dx:導數x的順序
  • dy:導數y的順序
  • dst:輸出圖像。和輸入圖像具有相同的深度
  • ksize:擴展 Sobel 內核的大小;它必須是 1、3、5 或 7
  • scale:計算導數值的可選比例因子。默認情況下,沒有縮放
  • delta:可選的增量,將會加到最終的dst中,同樣,默認情況下沒有額外的值加到dst中
  • borderType:像素外推

Canny邊沿檢測算法

canny_img=cv2.Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None)
說明:在輸入圖像中找到邊緣,並使用精明算法。阈值 1 和阈值 2 之間的最小值用於邊緣鏈接。這最大值用於查找強邊緣的初始段。

參數

  • image:8 位輸入圖像
  • threshold1:第一個阈值
  • threshold2:第二個阈值
  • edges:輸出邊緣圖;單通道 8 位圖像,與 image 大小相同。
  • apertureSize:sobel算子的孔徑大小
  • L2gradient:計算圖像梯度幅度。可以使用默認的L2范數

尋找輪廓函數

contours, hierarchy=cv2.findContours(image, mode, method, contours=None, hierarchy=None, offset=None):
說明:從二進制圖像中檢索輪廓。

參數

  • image:一般為sobel算子或者scharr算子得到的二值化圖像。8 位單通道圖像。非零像素被視為 1。零像素保持為 0,因此圖像被視為 binary

  • mode:

    • cv2.RETR_EXTERNAL 只檢測外輪廓
    • cv2.RETR_LIST 檢測的輪廓不建立等級關系,都是同級,不存在父輪廓或內嵌輪廓,
    • cv2.RETR_CCOMP 建立兩個等級的輪廓,上面一層為外邊界,裡面一層為內孔的邊界信息
    • cv2.RETR_TREE 建立一個等級樹結構的輪廓
  • method

    • cv2.RETR_EXTERNAL 只檢測外輪廓
    • cv2.RETR_LIST 檢測的輪廓不建立等級關系,都是同級,不存在父輪廓或內嵌輪廓,
    • cv2.RETR_CCOMP 建立兩個等級的輪廓,上面一層為外邊界,裡面一層為內孔的邊界信息
    • cv2.RETR_TREE 建立一個等級樹結構的輪廓
  • contours:檢測的輪廓數組,每一個輪廓用一個point類型的vector表示

  • hierarchy:和輪廓個數相同,每個輪廓contours[ i ]對應4個hierarchy元素hierarchy[ i ][0 ] ~hierarchy[ i ][ 3],分別表示後一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號,如果沒有對應項,該值設置為負數。

  • offset:每個輪廓點移動的可選偏移量

返回值

  • contours:檢測的輪廓數組,每一個輪廓用一個point類型的vector表示
  • hierarchy:和輪廓個數相同,每個輪廓contours[ i ]對應4個hierarchy元素hierarchy[ i ][0 ] ~hierarchy[ i ][ 3],分別表示後一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號,如果沒有對應項,該值設置為負數。

畫輪廓函數

cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

說明:繪制輪廓輪廓或填充輪廓

參數

  • image:目標圖像
  • contours:是得到的一系列點的集合
  • contourIdx:指示要繪制的輪廓的參數。如果為負,則繪制所有輪廓。
  • color:輪廓的顏色
  • thickness:繪制輪廓線的粗細。如果它是負數,輪廓內部被繪制
  • lineType:線的連通性
  • hierarchy:可選層次信息結構,是findContours所的到的基於Contours的層級信息
  • maxLevel: 繪制輪廓的最大等級。如果等級為0,繪制單獨的輪廓。如果為1,繪制輪廓及在其後的相同的級別下輪廓。如果值為2,所有的輪廓。如果等級為2,繪制所有同級輪廓及所有低一級輪廓,諸此種種。如果值為負數,函數不繪制同級輪廓,但會升序繪制直到級別為abs(max_level)-1的子輪廓
  • offset:照給出的偏移量移動每一個輪廓點坐標.當輪廓是從某些感興趣區域(ROI)中提取的然後需要在運算中考慮ROI偏移量時,將會用到這個參數。

源代碼:

import cv2
import numpy as np
# 選擇圖片檢測或者選擇視頻檢測
is_picture = True
file_path = '../Picture/Badminton.jpeg'
# 識別OpencCV書的阈值:'red': {'Lower': np.array([0, 53, 66]), 'Upper': np.array([74, 76, 187])
# 這個是顏色的HSV的范圍值(分別代表的是H,S,V),可以根據需求進行刪改
color_dist = {
'red': {
'Lower': np.array([0, 53, 66]), 'Upper': np.array([74, 76, 187])},
'blue': {
'Lower': np.array([100, 80, 46]), 'Upper': np.array([124, 255, 255])},
'green': {
'Lower': np.array([77, 54, 47]), 'Upper': np.array([166, 255, 255])},
'yellow': {
'Lower': np.array([26, 43, 46]), 'Upper': np.array([34, 255, 255])},
}
class DetectProcess(object):
def __init__(self):
super(DetectProcess, self).__init__()
# 形態學腐蝕操作:cv2.erode
def erode(self, img):
# 創建腐蝕使用的內核:3x3和5x5
kernel = np.ones((3, 3), np.uint8)
# 執行腐蝕操作 iterations表示執行腐蝕的次數
img_erosion = cv2.erode(img, kernel, iterations=1)
return img_erosion
# 形態學膨脹:cv2.dilate
def dilate(self, img):
kernel = np.ones((5, 5), np.uint8)
dilation = cv2.dilate(img, kernel, iterations=1)
return dilation
# 開運算:cv2.morphologyEx() :先腐蝕再膨脹,有助於消除噪音.
def morphologyExOpening(self, img):
kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
return opening
# 閉運算:用於消除前景對象內的小孔或對象上的小黑點
def morphologyExClosing(self, img):
kernel = np.ones((5, 5), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
return closing
# sobel算子:返回的圖像通道和原圖相同,即彩色圖像處理後仍為3通道
# sobel得到的圖像是有許多小點的的
def sobel(self, img):
# 核函數的取值范圍:1,3,5,7,9,核函數過大效果不好
Ksize = 3
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=Ksize)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=Ksize)
# sobel-x方向
sobel_X = cv2.convertScaleAbs(sobelx)
# sobel-y方向
sobel_Y = cv2.convertScaleAbs(sobely)
# sobel-xy方向
sobel_XY = cv2.addWeighted(sobel_X, 0.5, sobel_Y, 0.5, 0)
return sobel_XY
# Scharr算子:返回的圖像通道和原圖相同,即彩色圖像處理後仍為3通道
def scharr(self, img):
scharr_x = cv2.Scharr(img, cv2.CV_8U, 1, 0)
scharr_y = cv2.Scharr(img, cv2.CV_8U, 0, 1)
scharrX = cv2.convertScaleAbs(scharr_x)
scharrY = cv2.convertScaleAbs(scharr_y)
scharr_XY = cv2.addWeighted(scharrX, 0.5, scharrY, 0.5, 0)
return scharr_XY
# Canny:返回的為單通道圖像
# 得到的是一條淡顏色的線
def canny(self, img):
# 核函數的取值為3,5,7
# 高低阈值maxVal和minVal的取值范圍1-255
# L2g為“精准”標識符,參數為True和False
Ksize = 3
minVal = 20
maxVal = 40
L2g = True
Canny = cv2.Canny(img, minVal, maxVal, apertureSize=Ksize, L2gradient=False)
return Canny
# 對輪廓的面積進行篩選
def areaFilter(contours):
""" 對面積進行篩選,若大於900的面積我們才認為是有效的邊緣,這個可以根據自己的需求進行調整 :param contours: 輪廓的集合 :return: 識別到的有效的輪廓集合 """
areas = []
for i in range(len(contours)):
if cv2.contourArea(contours[i]) <= 900:
continue
else:
areas.append(contours[i])
return areas
# areas.sort()
# print("area is:", areas)
if __name__ == '__main__':
detect = DetectProcess()
# 調用攝像頭
cap = cv2.VideoCapture(0)
while True:
if is_picture:
frame = cv2.imread(file_path)
else:
# 讀取視頻幀,ret標志讀取的結果,frame為讀取到的視頻幀圖像
ret, frame = cap.read()
# 高斯濾波
gs_frame = cv2.GaussianBlur(frame, (5, 5), 0)
# 轉化成HSV圖像
hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV)
# 規定紅色區域的HSV.
# OpenCV中的inRange()函數可實現二值化功能(這點類似threshold()函數
# cv2.inRange((InputArray src, InputArray lowerb,InputArray upperb, OutputArray dst);
# 參數1:輸入要處理的圖像,可以為單通道或多通道。
# 參數2:包含下邊界的數組或標量。
# 參數3:包含上邊界數組或標量。
# 參數4:輸出圖像,與輸入圖像src 尺寸相同且為CV_8U 類型。也可以作為返回值處理
inRange_hsv = cv2.inRange(hsv, color_dist['green']['Lower'], color_dist['green']['Upper'])
cv2.imshow('inRange_hsv', inRange_hsv)
# 形態學腐蝕操作
erode_frame = detect.erode(inRange_hsv)
cv2.imshow('erode', erode_frame)
# 形態學膨脹操作
dilate_frame = detect.dilate(erode_frame)
cv2.imshow('dilate', dilate_frame)
# 開運算
morphologyExOpening_frame = detect.morphologyExOpening(inRange_hsv)
cv2.imshow('morphologyExOpening', morphologyExOpening_frame)
# 閉運算
morphologyExClosing_frame = detect.morphologyExClosing(morphologyExOpening_frame)
cv2.imshow('morphologyExClosing', morphologyExClosing_frame)
# Sobel_frame
Sobel_frame = detect.sobel(morphologyExClosing_frame)
cv2.imshow('Sobel_frame', Sobel_frame)
# 尋找外部的點:建立RETR_EXTERNAL來統計最大外圍的點。
contours, hierarchy = cv2.findContours(Sobel_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# cnt = contours[1:50] 這個表示的是提取的圖像的范圍
cv2.drawContours(frame, areaFilter(contours), -1, (0, 0, 255), 2)
cv2.imshow('result', frame)
if cv2.waitKey(1) & 0xFF == 27:
break
cv2.destroyAllWindows()

效果:


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved