<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
影象中將前景物件作為目標影象分割或者提取出來。對背景本身並無興趣分水嶺演演算法及GrabCut演演算法對影象進行分割及提取。
分水嶺演演算法將影象形象地比喻為地理學上的地形表面,實現影象分割,該演演算法非常有效。
任何一幅灰度影象,都可以被看作是地理學上的地形表面,灰度值高的區域可以被看成是山峰,灰度值低的區域可以被看成是山谷。
左圖是原始影象,右圖是其對應的“地形表面”。
該過程將影象分成兩個不同的集合:集水盆地和分水嶺線。我們構建的堤壩就是分水嶺線,也即對原始影象的分割。這就是分水嶺演演算法。
由於噪聲等因素的影響,採用上述基礎分水嶺演演算法經常會得到過度分割的結果。過度分割會將影象劃分為一個個稠密的獨立小塊,讓分割失去了意義。為了改善影象分割效果,人們提出了基於掩模的改進的分水嶺演演算法。改進的分水嶺演演算法允許使用者將他認為是同一個分割區域的部分標註出來(被標註的部分就稱為掩模)。分水嶺演演算法在處理時,就會將標註的部分處理為同一個分割區域。
例如:
原始影象,對其做標註處理,其中被標註為深色的三個小色塊表示,在使用掩模分水嶺演演算法時,這些部分所包含的顏色都會被分割在同一個區域內。
在OpenCV中,可以使用函數cv2.watershed()實現分水嶺演演算法。
在具體的實現過程中,還需要藉助於形態學函數、距離變換函數cv2.distanceTransform()、cv2.connectedComponents()來完成影象分割。
import cv2 import numpy as np import matplotlib.pyplot as plt o=cv2.imread("my.bmp", cv2.IMREAD_UNCHANGED) k=np.ones((5,5), np.uint8) e=cv2.erode(o, k) b=cv2.subtract(o, e) plt.subplot(131) plt.imshow(o) plt.axis('off') plt.subplot(132) plt.imshow(e) plt.axis('off') plt.subplot(133) plt.imshow(b) plt.axis('off') plt.show()
使用形態學操作和減法運算能夠獲取影象的邊界資訊。但是,形態學操作僅適用於比較簡單的影象。如果影象內的前景物件存在連線的情況,使用形態學操作就無法準確獲取各個子影象的邊界了。
如果畫素點本身的值為0,則這個距離也為0。
通常情況下:
如果對上述計算結果進行閾值化,就可以得到影象內子圖的中心、骨架等資訊。距離變換函數cv2.distanceTransform()可以用於計算物件的中心,還能細化輪廓、獲取影象前景等
函數cv2.distanceTransform()的語法格式為:
dst=cv2.distanceTransform(src, distanceType, maskSize[, dstType]])
使用距離變換函數cv2.distanceTransform(),計算一幅影象的確定前景
import numpy as np import cv2 import matplotlib.pyplot as plt img = cv2.imread('water_coins.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ishow=img.copy() ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) kernel = np.ones((3,3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) # 進行開運算 dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2,5) ret, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) plt.subplot(131) plt.imshow(ishow) plt.axis('off') plt.subplot(132) plt.imshow(dist_transform) plt.axis('off') plt.subplot(133) plt.imshow(fore) plt.axis('off') plt.show()
fore影象中: 比較準確地顯示出左圖內的“確定前景”。確定前景,通常是指前景物件的中心。之所以認為這些點是確定前景,是因為它們距離背景點的距離足夠遠,都是距離大於足夠大的固定閾值(0.7*dist_transform.max())的點。
為了方便說明將確定背景稱為B。
“影象O-確定背景B”,可以通過對影象進行形態學的膨脹操作得到。
標註一幅影象的確定前景、確定背景及未知區域。
import numpy as np import cv2 import matplotlib.pyplot as plt img = cv2.imread('water_coins.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ishow=img.copy() ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) kernel = np.ones((3,3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) bg = cv2.dilate(opening, kernel, iterations=3) dist = cv2.distanceTransform(opening, cv2.DIST_L2,5) ret, fore = cv2.threshold(dist,0.7*dist.max(),255,0) fore = np.uint8(fore) un = cv2.subtract(bg, fore) plt.subplot(221) plt.imshow(ishow) plt.axis('off') plt.subplot(222) plt.imshow(bg) plt.axis('off') plt.subplot(223) plt.imshow(fore) plt.axis('off') plt.subplot(224) plt.imshow(un) plt.axis('off') plt.show()
retval, labels = cv2.connectedComponents( image )
使用函數cv2.connectedComponents()標註一幅影象
import numpy as np import cv2 import matplotlib.pyplot as plt img = cv2.imread('water_coins.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ishow=img.copy() ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) kernel = np.ones((3,3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) sure_bg = cv2.dilate(opening, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2,5) ret, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) fore = np.uint8(fore) ret, markers = cv2.connectedComponents(fore) print(ret) plt.subplot(131) plt.imshow(ishow) plt.axis('off') plt.subplot(132) plt.imshow(fore) plt.axis('off') plt.subplot(133) plt.imshow(markers) plt.axis('off') plt.show()
前景影象的中心點被做了不同的標註(用不同顏色區分)
函數cv2.connectedComponents()在標註影象時,會將背景標註為0,將其他的物件用從1開始的正整數標註。具體的對應關係為:
在分水嶺演演算法中,標註值0代表未知區域。所以,我們要對函數cv2.connectedComponents()標註的結果進行調整:將標註的結果都加上數值1。經過上述處理後,在標註結果中:
為了能夠使用分水嶺演演算法,還需要對原始影象內的未知區域進行標註,將已經計算出來的未知區域標註為0即可。
關鍵程式碼:
ret, markers = cv2.connectedComponents(fore) markers = markers+1 markers[未知區域] = 0
使用函數cv2.connectedComponents()標註一幅影象,並對其進行修正,使未知區域被標註為0
import numpy as np import cv2 import matplotlib.pyplot as plt img = cv2.imread('water_coins.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ishow=img.copy() ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) kernel = np.ones((3,3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) sure_bg = cv2.dilate(opening, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2,5) ret, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) fore = np.uint8(fore) ret, markers1 = cv2.connectedComponents(fore) foreAdv=fore.copy() unknown = cv2.subtract(sure_bg, foreAdv) ret, markers2 = cv2.connectedComponents(foreAdv) markers2 = markers2+1 markers2[unknown==255] = 0 plt.subplot(121) plt.imshow(markers1) plt.axis('off') plt.subplot(122) plt.imshow(markers2) plt.axis('off') plt.show()
前景都有一個黑色的邊緣,這個邊緣是被標註的未知區域。
markers = cv2.watershed( image, markers )
cv2.watershed()函數處理之前,必須先用正數大致勾畫出影象中的期望分割區域。每一個分割的區域會被標註為1、2、3等。對於尚未確定的區域,需要將它們標註為0。我們可以將標註區域理解為進行分水嶺演演算法分割的“種子”區域。
使用分水嶺演演算法進行影象分割時,基本的步驟為:
使用分水嶺演演算法對一幅影象進行分割:
import numpy as np import cv2 import matplotlib.pyplot as plt img = cv2.imread('water_coins.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ishow=img.copy() ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) kernel = np.ones((3,3), np.uint8) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) sure_bg = cv2.dilate(opening, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) ret, markers = cv2.connectedComponents(sure_fg) markers = markers+1 markers[unknown==255] = 0 markers = cv2.watershed(img, markers) img[markers == -1] = [0,255,0] # 邊界 plt.subplot(121) plt.imshow(ishow) plt.axis('off') plt.subplot(122) plt.imshow(img) plt.axis('off') plt.show()
經典的前景提取技術主要使用紋理(顏色)資訊,如魔術棒工具,或根據邊緣(對比度)資訊,如智慧剪刀等。在開始提取前景時,先用一個矩形框指定前景區域所在的大致位置範圍,然後不斷迭代地分割,直到達到最好的效果。經過上述處理後,提取前景的效果可能並不理想,存在前景沒有提取出來,或者將背景提取為前景的情況,此時需要使用者干預提取過程。
使用者在原始影象的副本中(也可以是與原始影象大小相等的任意一幅影象),用白色標註要提取為前景的區域,用黑色標註要作為背景的區域。然後,將標註後的影象作為掩模,讓演演算法繼續迭代提取前景從而得到最終結果。
PowerPoint 2016提供了“刪除背景”功能。
GrabCut演演算法的具體實施過程。
在OpenCV中,實現互動式前景提取的函數是cv2.grabCut(),其語法格式為:
mask, bgdModel, fgdModel =cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode] )
在最後使用模板提取前景時,會將引數值0和2合併為背景(均當作0處理),將引數值1和3合併為前景(均當作1處理)。
在通常情況下,我們可以使用白色筆刷和黑色筆刷在掩模影象上做標記,再通過轉換將其中的白色畫素設定為0,黑色畫素設定為1。
只有當引數mode的值被設定為矩形模式cv2.GC_INIT_WITH_RECT時,引數rect才有意義。
其格式為(x, y, w, h),分別表示區域左上角畫素的x軸和y軸座標以及區域的寬度和高度。
如果前景位於右下方,又不想判斷原始影象的大小,對於w 和h可以直接用一個很大的值。
使用掩模模式時,將該值設定為none即可。
mode表示迭代模式。其可能的值與含義如下:
RECT 和MASK可以組合使用( 並的關係 )
使用GrabCut演演算法提取影象的前景
import numpy as np import cv2 import matplotlib.pyplot as plt o = cv2.imread('lenacolor.png') orgb=cv2.cvtColor(o, cv2.COLOR_BGR2RGB) mask = np.zeros(o.shape[:2], np.uint8) bgdModel = np.zeros((1,65), np.float64) fgdModel = np.zeros((1,65), np.float64) rect = (50,50,400,500) cv2.grabCut(o, mask, rect, bgdModel, fgdModel,5, cv2.GC_INIT_WITH_RECT) mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8') ogc = o*mask2[:, :, np.newaxis] ogc=cv2.cvtColor(ogc, cv2.COLOR_BGR2RGB) plt.subplot(121) plt.imshow(orgb) plt.axis('off') plt.subplot(122) plt.imshow(ogc) plt.axis('off') plt.show()
為了得到完整的前景物件,需要做一些改進。
這裡對原始影象進行標註,將需要保留的部分設定為白色,將需要刪除的背景設定為黑色。以標記好的影象作為模板,使用函數cv2.grabCut()完成前景的提取。
這個過程主要包含以下步驟:
在GrabCut演演算法中使用模板提取影象的前景:
import numpy as np import cv2 import matplotlib.pyplot as plt o= cv2.imread('lenacolor.png') orgb=cv2.cvtColor(o, cv2.COLOR_BGR2RGB) mask = np.zeros(o.shape[:2], np.uint8) bgd = np.zeros((1,65), np.float64) fgd = np.zeros((1,65), np.float64) rect = (50,50,400,500) cv2.grabCut(o, mask, rect, bgd, fgd,5, cv2.GC_INIT_WITH_RECT) mask2 = cv2.imread('mask.png',0) mask2Show = cv2.imread('mask.png', -1) m2rgb=cv2.cvtColor(mask2Show, cv2.COLOR_BGR2RGB) mask[mask2 == 0] = 0 mask[mask2 == 255] = 1 mask, bgd, fgd = cv2.grabCut(o, mask, None, bgd, fgd,5, cv2.GC_INIT_WITH_MASK) mask = np.where((mask==2)|(mask==0),0,1).astype('uint8') ogc = o*mask[:, :, np.newaxis] ogc=cv2.cvtColor(ogc, cv2.COLOR_BGR2RGB) plt.subplot(121) plt.imshow(m2rgb) plt.axis('off') plt.subplot(122) plt.imshow(ogc) plt.axis('off') plt.show()
在函數cv2.grabCut()的實際使用中,也可以不使用矩形初始化,直接使用模板模式。構造一個模板影象,其中:
構造完模板後,直接將該模板用於函數cv2.grabCut()處理原始影象,即可完成前景的提取。
一般情況下,自定義模板的步驟為:
在GrabCut演演算法中直接使用自定義模板提取影象的前景
import numpy as np import cv2 import matplotlib.pyplot as plt o= cv2.imread('lenacolor.png') orgb=cv2.cvtColor(o, cv2.COLOR_BGR2RGB) bgd = np.zeros((1,65), np.float64) fgd = np.zeros((1,65), np.float64) mask2 = np.zeros(o.shape[:2], np.uint8) #先將掩模的值全部構造為0(確定背景),在後續步驟中,再根據需要修改其中的部分值 mask2[30:512,50:400]=3 #lena頭像的可能區域 mask2[50:300,150:200]=1 #lena頭像的確定區域,如果不設定這個區域,頭像的提取不完整 cv2.grabCut(o, mask2, None, bgd, fgd,5, cv2.GC_INIT_WITH_MASK) mask2 = np.where((mask2==2)|(mask2==0),0,1).astype('uint8') ogc = o*mask2[:, :, np.newaxis] ogc=cv2.cvtColor(ogc, cv2.COLOR_BGR2RGB) plt.subplot(121) plt.imshow(orgb) plt.axis('off') plt.subplot(122) plt.imshow(ogc) plt.axis('off') plt.show()
對於不同的影象,要構造不同的模板來劃分它們的確定前景、確定背景、可能的前景與可能的背景。
到此這篇關於python中的opencv 影象分割與提取 的文章就介紹到這了,更多相關opencv影象分割 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45