OpenCV基于距离变换和分水岭实现图像分割
1. 距离变换
距离变换是将一副灰度图像中的每个非零像素点赋予一个基于其与最近零像素距离的新值的操作。距离变换常被用于形态学图像处理中的对象筛选,但也可以被用于图像分割中。
在OpenCV中,可以通过cv2.distanceTransform
函数实现距离变换。其中第一个参数是输入的二值化图像,第二个参数是距离类型(cv2.DIST_L1
、cv2.DIST_L2
、cv2.DIST_C
),第三个参数是掩膜大小,默认为3,即3x3的矩形掩膜。该函数会返回距离变换后的结果,数据类型为float32
。
2. 分水岭算法
分水岭算法是一种常用的图像分割算法,它源于地理学中的分水岭分析方法。该算法通过对灰度图像的分割,将图像看做是一个地理地形图,将梯度作为高程,将梯度作为集腋成裘的水流,从不同的源头流入,到达波峰或者波轮的漏斗,从而完成对图像的分割。
在OpenCV中,可以通过cv2.watershed
函数实现分水岭算法。其中第一个参数是输入的灰度图像,要求是三通道的,但是需要将其转换为三通道的灰度图像;第二个参数是标记图像(uint8
类型),其大小与输入图像相同;第三个参数指定分水岭算法中的连通性,通常使用cv2.getStructuringElement
函数制作结构元素(如矩形、椭圆等形状)来进行定义;第四个参数是输出的标记图像信息,数据类型为int32
;最后一个参数用来指定需要分割区域的数量。
3. 完整攻略
基于距离变换和分水岭的图像分割步骤如下:
- 读取待分割的彩色图像并转换为灰度图像。
- 对灰度图像进行二值化处理。
- 对二值化图像进行距离变换。
- 对距离变换后的图像进行阈值处理,得到分界线区域的标记图像。
- 对分界线区域的标记图像进行分水岭算法处理。
- 将结果可视化并输出。
以下是两条示例说明:
示例1
假设需要对一张车辆行驶场景下的图像进行分割,代码如下:
import cv2
import numpy as np
# 读取图像并转换为灰度图像
img = cv2.imread('driving.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化处理
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 距离变换
dist_transform = cv2.distanceTransform(thresh, cv2.DIST_L2, 5)
# 阈值处理
ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
# 获取背景区域
sure_bg = cv2.dilate(thresh, np.ones((3,3), np.uint8), iterations=3)
# 分界线区域
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,0,255]
# 显示输出
cv2.imshow('Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
该代码会实现对行驶场景下的车辆进行分割,更改cv2.imread
中的图片路径即可。
示例2
假设需要对一张带有多个目标的图像进行分割,代码如下:
import cv2
import numpy as np
# 读取图像并转换为灰度图像
img = cv2.imread('objects.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 高斯滤波
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# 二值化处理
ret, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 距离变换
dist_transform = cv2.distanceTransform(thresh, cv2.DIST_L2, 5)
# 阈值处理
ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
# 获取背景区域
sure_bg = cv2.dilate(thresh, np.ones((3,3), np.uint8), iterations=3)
# 分界线区域
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,0,255]
# 显示输出
cv2.imshow('Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
该代码会实现对多个目标进行分割,更改cv2.imread
中的图片路径即可。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:OpenCV基于距离变换和分水岭实现图像分割 - Python技术站