发现你的身形——OpenCV图像轮廓
文章目錄
- 寫在最前
- 輪廓發現算法
- 邊緣檢測
- 寫在最后
寫在最前
我的意思不是說你長得很胖,emmmm,而是你的輪廓很大。
——五星上將詹姆斯下士如是說
果然有圖沒圖,理解是不一樣的,這就體現了計算機視覺的重要性,2333
上一節最后,我們說過這一次我們就將會講解真正的OpenCV圖像輪廓有關知識。輪廓發現的具體實現有多種方式,不過其實其使用在OpenCV中的使用并不困難,不過想用好還需要多點基礎知識。所以這里我們會首先講一講OpenCV中的輪廓發現算法,然后再講一講其他可以用于輪廓發現的特殊方法。這里我們主要使用了兩種來自于opencv官方的圖片(Note:上面那張不是),第一張是彩色快樂魚,第二張是水果分尸圖不對,應該是果繽紛才對。\(^o^)/~
輪廓發現算法
opencv中的輪廓發現算法來自于1985的一篇論文《TopologicalStructural Analysis of Digitized Binary Images by Border Following》,這篇論文主要講了兩種可有效利用于輪廓發現的邊界跟蹤算法,其中第一種是區分二值圖像邊界之間的保衛關系(surroundness relations)第二種是第一種算法的變形,只跟蹤最外層輪廓。對于具體內容這里不再過多描述,你可以自行查閱。至于具體的使用,我們直接使用OpenCV中的函數findContours即可。
由于opencv中的輪廓發現借鑒于論文《 Analysis of Digitized Binary Images by Border Following》,所以其只能接受二值化之后的圖像,也就是說我們需要先對原始圖像進行二值化處理,這里需要使用函數cvtColor將圖片進行類型轉化,具體代碼如下:
# 灰度圖像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化 ret, binary = cv2.threshold(gray, 175, 255, cv2.THRESH_BINARY)其中COLOR_BGR2GRAY的作用一如其名,就是將BGR圖像轉化為GRAY(灰度圖,又名遺照)
之后我們就可以使用 cv2.threshold方法進行二值化處理,就這樣一條彩色的快樂魚就變成了一張黑白的快樂魚遺照了。其中要注意的是,閾值是由我們自己選定的(這里是175),我們也可以通過修改閾值來獲取新的二值化參數。
最終,我們就可以將二值化之后的圖像傳進輪廓發現算法,進行輪廓發現并繪制。代碼與結果如下:
# 輪廓發現 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 輪廓繪制 cv2.drawContours(img, contours_new, -1, (0, 0, 255), 3)現在快樂魚就被慘遭“分尸”了,嘴巴上多了一條大口子。而說回正事,上面的代碼中drawContours函數就是繪制函數,第一個參數是需要繪制的原圖像,第二個參數是之前我們使用算法發現的輪廓,第三個參數則表示繪制的輪廓索引,這里使用-1表示繪制所有輪廓,第四個參數則是繪制輪廓時線條的顏色,這里我們選擇紅色0。第五個參數則表示線條粗細度,如果是負值則在輪廓內部繪制。除此之外還有一個隱身的六娃lineType表示線條類型,因為有默認數值LINE_8,所以這里沒有設置。
不過除了這些基本的操作外,我們還可以有很多其他的操作,比如借助之前我們學過的濾波函數對圖像進行處理,去除那些意義不大的小色塊,或者使用邊緣檢測算法如Canny先一步獲取圖形邊緣(代替直接二值化哪一步),然后再進行輪廓發現,這些操作避免發現錯誤輪廓,同時我們也可以使用判斷方法選擇一定周長或者面積的輪廓。前者直接使用cv.blur(src_gray, (3,3)),以及函數canny_output = cv.Canny(gray, threshold, threshold * 2)即可,后者則需要幾個opencv的函數進行配合,具體代碼如下:
# Detect edges using Canny threshold = 100 # Detect edges using Canny canny_output = cv2.Canny(gray, threshold, threshold * 2) for i in range(len(contours)):# 計算輪廓所包含的面積area = cv2.contourArea(contours[i])# 計算輪廓的周長perimeter = cv2.arcLength(contours[i], True)if perimeter >= 10 and area >= 20:print("第{0}個輪廓的面積為{1},周長為{2}".format(i+1,area,perimeter))contours_new.append(contours[i])第一段代碼的作用是使用Canny進行邊緣檢測(展示的圖片也經過了均值模糊),然后得到一張只有邊緣數據的圖,這樣就避免了之前直接二值化產生的像素閾值產生的本來不存在的誤差,而第二行代碼則是利用計算輪廓面積和計算輪廓周長的函數進行輪廓篩選。其實這里我們也可以選擇不進行篩選直接進行獲取,但是在一般情況下
均值模糊,邊緣檢測,周長,面積等都是十分有用的操作,至于怎么用則需要根據實際情況進行調整。
邊緣檢測
這里還提到了邊緣檢測,邊緣檢測顧名思義就是檢測圖片的邊緣。在一些特殊情況下其實邊緣檢測比直接輪廓獲取有用,不過也有些時候圖像分割的一些技術更有用一些。這幾項技術的特點都是作用于圖像中的區域對其進行處理。只不過在沒有深度學習的時代,沒有像目標檢測,或者現代的更直接的自動進行圖像分割的技術,只能使用各類算法進行手動操作,從不同的圖片中手動設置不同的方法獲取我們想要的信息。
Canny就是一種比較常見的邊緣檢測方法,下面就是一個例子。我們將會在下一屆仔細的講講的邊緣檢測等有關圖像處理技術。
寫在最后
大概寫到這個時候感覺確實可以出個專欄了,所以正式規劃了《漫談計算機視覺》,頻率大概會一周一更,大概會從OpenCV將其,然后一直串到這兩年各個計算機視覺領域比較經典深度神經網絡。同時代碼會開源,之后代碼和有關數據前往FontTian的Github下載即可,包括之前的內容都會穿上去,項目位置在這:https://github.com/FontTian/Gossipage_About_CV。
總結
以上是生活随笔為你收集整理的发现你的身形——OpenCV图像轮廓的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机视觉的基石-滤波
- 下一篇: 图像边缘检测,检测亦或简化