Python 深入了解opencv圖像分割算法
本文主要是基于Python Opencv 實現(xiàn)的圖像分割,其中使用到的opencv的函數(shù)有:
- 使用 OpenCV 函數(shù) cv::filter2D 執(zhí)行一些拉普拉斯濾波以進行圖像銳化
- 使用 OpenCV 函數(shù) cv::distanceTransform 以獲得二值圖像的派生(derived)表示,其中每個像素的值被替換為其到最近背景像素的距離
- 使用 OpenCV 函數(shù) cv::watershed 將圖像中的對象與背景隔離
加載源圖像并檢查它是否加載沒有任何問題,然后顯示它:
# Load the image parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\ Sample code showing how to segment overlapping objects using Laplacian filtering, \ in addition to Watershed and Distance Transformation') parser.add_argument('--input', help='Path to input image.', default='cards.png') args = parser.parse_args() src = cv.imread(cv.samples.findFile(args.input)) if src is None: print('Could not open or find the image:', args.input) exit(0) # Show source image cv.imshow('Source Image', src)
原圖
將背景從白色更改為黑色,因為這將有助于稍后在使用距離變換(Distance Transform)期間提取更好的結果
src[np.all(src == 255, axis=2)] = 0
如果不太理解numpy.all的的用法,可以參考這里
之后,我們將銳化(sharpen)我們的圖像,以銳化前景對象(the foreground objects)的邊緣。 我們將應用具有相當強過濾器的拉普拉斯(laplacian)過濾器(二階導數(shù)的近似值):
# 創(chuàng)建一個內核,我們將用它來銳化我們的圖像 # 一個二階導數(shù)的近似值,一個非常強大的內核 kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32) # do the laplacian filtering as it is # well, we need to convert everything in something more deeper then CV_8U # because the kernel has some negative values, # and we can expect in general to have a Laplacian image with negative values # BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255 # so the possible negative number will be truncated imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel) sharp = np.float32(src) imgResult = sharp - imgLaplacian # convert back to 8bits gray scale imgResult = np.clip(imgResult, 0, 255) imgResult = imgResult.astype('uint8') imgLaplacian = np.clip(imgLaplacian, 0, 255) imgLaplacian = np.uint8(imgLaplacian) #cv.imshow('Laplace Filtered Image', imgLaplacian) cv.imshow('New Sharped Image', imgResult)
銳化處理的主要目的是突出灰度的過度部分。由于拉普拉斯是一種微分算子,如果所使用的定義具有負的中心系數(shù),那么必須將原圖像減去經拉普拉斯變換后的圖像,而不是加上它,從而得到銳化結果。----摘自《數(shù)字圖像處理(第三版)》
現(xiàn)在我們將新的銳化源圖像分別轉換為灰度和二值圖像(binary):
# Create binary image from source image bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY) _, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) cv.imshow('Binary Image', bw)
我們現(xiàn)在準備在二值圖像(binary image)上應用距離變換。 此外,我們對輸出圖像進行歸一化,以便能夠對結果進行可視化和閾值處理:
# Perform the distance transform algorithm dist = cv.distanceTransform(bw, cv.DIST_L2, 3) # 對范圍 = {0.0, 1.0} 的距離圖像(the distance image)進行歸一化(Normalize), # 以便我們可以對其進行可視化和閾值處理 cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX) cv.imshow('Distance Transform Image', dist)
distanceTransform用法
cv.distanceTransform( src, distanceType, maskSize[, dst[, dstType]] )
src:輸入圖像,數(shù)據(jù)類型為CV_8U的單通道圖像
dst: 輸出圖像,與輸入圖像具有相同的尺寸,數(shù)據(jù)類型為CV_8U或者CV_32F的單通道圖像。
distanceType:選擇計算兩個像素之間距離方法的標志,其常用的距離度量方法, DIST_L1(distance = |x1-x2| + |y1-y2| 街區(qū)距離), DIST_L2 (Euclidean distance 歐幾里得距離,歐式距離) 。
maskSize:距離變換掩碼矩陣的大小,參數(shù)可以選擇的尺寸為DIST_MASK_3(3×3)和DIST_MASK_5(5×5).
我們對 dist 圖像進行閾值處理,然后執(zhí)行一些形態(tài)學操作(即膨脹)以從上述圖像中提取峰值:
# Threshold to obtain the peaks # This will be the markers for the foreground objects _, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY) # Dilate a bit the dist image kernel1 = np.ones((3,3), dtype=np.uint8) dist = cv.dilate(dist, kernel1) cv.imshow('Peaks', dist)
從每個 blob 中,我們在 cv::findContours 函數(shù)的幫助下為分水嶺算法創(chuàng)建一個種子/標記:
# Create the CV_8U version of the distance image # It is needed for findContours() dist_8u = dist.astype('uint8') # Find total markers contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # Create the marker image for the watershed algorithm markers = np.zeros(dist.shape, dtype=np.int32) # Draw the foreground markers for i in range(len(contours)): cv.drawContours(markers, contours, i, (i+1), -1) # Draw the background marker cv.circle(markers, (5,5), 3, (255,255,255), -1) markers_8u = (markers * 10).astype('uint8') cv.imshow('Markers', markers_8u)
最后,我們可以應用分水嶺算法,并將結果可視化:
# Perform the watershed algorithm cv.watershed(imgResult, markers) #mark = np.zeros(markers.shape, dtype=np.uint8) mark = markers.astype('uint8') mark = cv.bitwise_not(mark) # uncomment this if you want to see how the mark # image looks like at that point #cv.imshow('Markers_v2', mark) # Generate random colors colors = [] for contour in contours: colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256))) # Create the result image dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8) # Fill labeled objects with random colors for i in range(markers.shape[0]): for j in range(markers.shape[1]): index = markers[i,j] if index > 0 and index <= len(contours): dst[i,j,:] = colors[index-1] # Visualize the final image cv.imshow('Final Result', dst)
基于機器學習的圖像分割
Pixellib是一個用于對圖像和視頻中的對象進行分割的庫。 它支持兩種主要類型的圖像分割:
1.語義分割
2.實例分割
PixelLib 支持兩個用于圖像分割的深度學習庫,分別是 Pytorch 和 Tensorflow
以上就是Python 深入了解opencv圖像分割算法的詳細內容,更多關于Python的資料請關注腳本之家其它相關文章!
相關文章
Python中用append()連接后多出一列Unnamed的解決
Python中用append()連接后多出一列Unnamed的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01PyCharm MySQL可視化Database配置過程圖解
這篇文章主要介紹了PyCharm MySQL可視化Database配置過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06詳解python ThreadPoolExecutor異常捕獲
本文主要介紹了詳解python ThreadPoolExecutor異常捕獲,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-01-01python中pandas.DataFrame對行與列求和及添加新行與列示例
pandas是python環(huán)境下最有名的數(shù)據(jù)統(tǒng)計包,而DataFrame翻譯為數(shù)據(jù)框,是一種數(shù)據(jù)組織方式,這篇文章主要給大家介紹了python中pandas.DataFrame對行與列求和及添加新行與列的方法,文中給出了詳細的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03Python模塊對Redis數(shù)據(jù)庫的連接與使用講解
這篇文章主要介紹了Python模塊對Redis數(shù)據(jù)庫的連接與使用,通過實例代碼給大家介紹了Python連接Redis數(shù)據(jù)庫方法,Python使用連接池連接Redis數(shù)據(jù)庫方法,感興趣的朋友跟隨小編一起看看吧2021-07-07詳解appium自動化測試工具(monitor、uiautomatorviewer)
這篇文章主要介紹了詳解appium自動化測試工具(monitor、uiautomatorviewer),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01Pandas技巧分享之創(chuàng)建測試數(shù)據(jù)
學習pandas的過程中,為了嘗試pandas提供的各類功能強大的函數(shù),常常需要花費很多時間去創(chuàng)造測試數(shù)據(jù),本篇介紹了一些快速創(chuàng)建測試數(shù)據(jù)的方法,需要的可以參考一下2023-07-07