分水岭算法需要很多方面知识,我这里仅仅是简单实现基本功能而已,希望大家多多指教。
#原理:
#灰度图像可以被看成拓扑平面,灰度值高的区域可以看出山峰,灰度值低的区域可以看成是山谷。
向每一个山谷当中灌不同颜色的水。水位升高,不同山谷的水会汇#合,为防止不同山谷的水汇合
,小在汇合处建立起堤坝。然后继续灌水,然后再建立堤坝,直到山峰都掩模。构建好的堤坝就是图像的分割。
#此方法通常会得到过渡分割的结果,因为图像中的噪声以及其他因素。为了减少此影响,opencv使用基于标记的分水岭算法,
此算法要设置哪些山谷中的汇合点,哪些不是。这是一种交互式的图像分割算法那。我们要给已知对象打上不同表情。
如果某个区域肯定是前景或对象,就使用某个颜色或灰度值标签标记它。如果是背景那么使用其他颜色进行标记,
其余不能确定的部分用0标记。然后使用分水岭算法,每次灌水,标签会被更新,当两个不同颜色的标签相遇就会构建堤坝,知道所有山峰掩模,
最后得到的边界对象值是-1。
先一步一步开始做吧,我们先开始对图像进行处理:
import cv2 as cv
import numpy as np
def main():
pitcurepath = "C:/Users/POG/Desktop/49d2d78cd115011da7c9b4aa54f5460b.jpg"
global src
src = cv.imread(pitcurepath)
cv.imshow("image",src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()
def watershed_demo():
print(src.shape)
#cv.pyrMeanShiftFiltering() 边缘保留滤波
blurred = cv.pyrMeanShiftFiltering(src,10,100)
#灰度处理
gray = cv.cvtColor(src,cv.COLOR_BGR2GRAY)
#函数 cvThreshold 对单通道数组应用固定阈值操作。该函数的典型应用是对灰度图像进行阈值操作得到二值图像
ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("binaryimage",binary)
if __name__ =="__main__":
main()
这里仅仅是先对图像进行灰度处理和二值处理(把灰度图像变成非黑即白),结果:
(这里献上我的霉霉)
那我们要是再来对图像进行边缘保留滤波处理呢?
(仅仅改下cv.cvtColor参数)
iimport cv2 as cv
import numpy as np
def main():
pitcurepath = "C:/Users/POG/Desktop/49d2d78cd115011da7c9b4aa54f5460b.jpg"
global src
src = cv.imread(pitcurepath)
cv.imshow("image",src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()
def watershed_demo():
print(src.shape)
#cv.pyrMeanShiftFiltering() 边缘保留滤波
blurred = cv.pyrMeanShiftFiltering(src,10,100)
#灰度处理
gray = cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)
#函数 cvThreshold 对单通道数组应用固定阈值操作。该函数的典型应用是对灰度图像进行阈值操作得到二值图像
ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("binaryimage",binary)
if __name__ =="__main__":
main()
肉眼可见边缘变模糊了,变得好处理了。
下面我们进行形态学操作函数morphologyEx和距离变换来看看结果:
import cv2 as cv
import numpy as np
def main():
pitcurepath = "C:/Users/POG/Desktop/u=1730442960,1387670636&fm=26&fmt=auto&gp=0.jpg"
global src
src = cv.imread(pitcurepath)
cv.imshow("image",src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()
def watershed_demo():
print(src.shape)
#cv.pyrMeanShiftFiltering() 边缘保留滤波
blurred = cv.pyrMeanShiftFiltering(src,10,100)
#灰度处理
gray = cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)
#函数 cvThreshold 对单通道数组应用固定阈值操作。该函数的典型应用是对灰度图像进行阈值操作得到二值图像
ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("binaryimage",binary)
#getStructuringElement函数会返回指定形状和尺寸的结构元素
kenrnel = cv.getStructuringElement(cv.MORPH_RECT,(3,3))
#形态学操作函数morphologyEx
mb = cv.morphologyEx(binary,cv.MORPH_OPEN,kenrnel,iterations=2)
sure_bg = cv.dilate(mb,kenrnel,iterations=3)
cv.imshow("mor-pot",sure_bg)
#距离变换
dist = cv.distanceTransform(mb,cv.DIST_L2,3)
dest_output = cv.normalize(dist,0,1.0,cv.NORM_MINMAX)
cv.imshow("distince",dest_output*100)
if __name__ =="__main__":
main()
(突然到这发现霉霉的照片用不成了,没法进行区分区域。。)
完整代码:
(这里用到很多形态学知识和操作,我也只是跟着视频和书做的,很多都不熟练,这个分水岭算法我会经常更新的)
import cv2 as cv
import numpy as np
def main():
pitcurepath = "C:/Users/POG/Desktop/u=1730442960,1387670636&fm=26&fmt=auto&gp=0.jpg"
global src
src = cv.imread(pitcurepath)
cv.imshow("image",src)
watershed_demo()
cv.waitKey(0)
cv.destroyAllWindows()
def watershed_demo():
print(src.shape)
#cv.pyrMeanShiftFiltering() 边缘保留滤波
blurred = cv.pyrMeanShiftFiltering(src,10,100)
#灰度处理
gray = cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)
#函数 cvThreshold 对单通道数组应用固定阈值操作。该函数的典型应用是对灰度图像进行阈值操作得到二值图像
ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("binaryimage",binary)
#getStructuringElement函数会返回指定形状和尺寸的结构元素
kenrnel = cv.getStructuringElement(cv.MORPH_RECT,(3,3))
#形态学操作函数morphologyEx
mb = cv.morphologyEx(binary,cv.MORPH_OPEN,kenrnel,iterations=2)
sure_bg = cv.dilate(mb,kenrnel,iterations=3)
cv.imshow("mor-pot",sure_bg)
#距离变换
dist = cv.distanceTransform(mb,cv.DIST_L2,3)
dest_output = cv.normalize(dist,0,1.0,cv.NORM_MINMAX)
cv.imshow("distince",dest_output*50)
ret,surface = cv.threshold(dist,dist.max()*0.6,255,cv.THRESH_BINARY)
cv.imshow("surface",surface)
surface_fg = np.uint8(surface)
unknown = cv.subtract(sure_bg,surface_fg)
ret,markers = cv.connectedComponents(surface_fg)
print(ret)
#watershed transform
markers = markers+1
markers[unknown==255]=0
markers = cv.watershed(src,markers=markers)
src[markers==-1]=[0,0,255]
cv.imshow("result",src)
if __name__ =="__main__":
main()