分水岭算法在opencv中算是比较重要的算法,主要是对图像的分割和提取,能够对认为是同一区域的部分分割出来,特别是针对一些图像中所要提取的特征相互接触,用普通的阈值分割很难划分出来。(代码学习:贾志刚老师)
这次实验对象是堆积的管道,如图所示下图所示(从网上找的):
本次主要针对这些圆管的横截面中每个圆孔的识别与定位,在此过程中也遇到了问题,也请各位同仁帮忙指正。
import cv2
import numpy as np
def watershed_demo():
print(src.shape)
#这个函数严格来说并不是图像的分割,而是图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域
blurred = cv2.pyrMeanShiftFiltering(src,10,100)
#图像灰度
gray=cv2.cvtColor(blurred,cv2.COLOR_BGR2GRAY)
#二值化
ret,bindary = cv2.threshold(gray,23,255,cv2.THRESH_BINARY_INV)
cv2.imshow('bindary_image',bindary)
#3*3的矩形内核
kernel=cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
#6次开操作去除噪点小块
mb=cv2.morphologyEx(bindary,cv2.MORPH_OPEN,kernel,iterations=6)
#3次膨胀操作,是原始图像-确定背景
sure_bg=cv2.dilate(mb,kernel,iterations=3)
cv2.imshow('mor_opt',sure_bg)
#距离变换函数,用于计算前景对象的中心,获取前景图像(前景子图像相互连接)
dist=cv2.distanceTransform(mb,cv2.DIST_L2,3) #最后一个值掩膜尺寸,若前面的是DIST_L1或DIST_C时,强制为3
#归一化,将图像相同的归为一个类别
dist_output=cv2.normalize(dist,0,10,cv2.NORM_MINMAX)
#*30是为了增加亮度
cv2.imshow('distance_t',dist_output*30)
#cv2.imshow('distance_t',dist)
#确定前景,前景对象的中心
ret,surface = cv2.threshold(dist,dist.max()*0.6,255,cv2.THRESH_BINARY)
cv2.imshow('surface_bin',surface)
#存储图像类型
surface_fg=np.uint8(surface)
#cv2.imshow('surface_fg',surface_fg)
#背景图像减去前景图像(未知图像来自于:原图像-确定背景-确定前景)
unknown = cv2.subtract(sure_bg,surface_fg)
#确定前景图像后,使用函数对其进行标注,背景标注为0,其他对象从1开始标注
ret,markers=cv2.connectedComponents(surface_fg)
print(ret)
#分水岭算法的原因,标注为0时代表未知区域,所以我们要在原来标注的基础上每一个加1
markers=markers+1
#对原图像中的未知区域标注为0,代表未知区域
markers[unknown==255]=0
#分水岭算法进行图像分割
markers=cv2.watershed(src,markers=markers)
#原图中以绿色线条画出
src[markers==-1]=[0,255,0]
cv2.imshow('result',src)
src=cv2.imread(r'C:/Users/X/Desktop/guan.jpg')
cv2.imshow('origin',src)
watershed_demo()
cv2.waitKey()
cv2.destroyAllWindows()
问题如图所示,能识别的圆只能是黑色圆部分,边上有侧光的地方没能识别出来,至今没有解决方案!(代码标注如有错误,还望海涵!)