基于边缘检测的图像分割流程
1、灰度图转变
2、使用边缘检测算子进行边缘提取,如canny、sobel、拉普拉斯算子
3、对边缘进行闭合处理
4、显示闭合后的轮廓
试了下canny、sobel、拉普拉斯,其中拉普拉斯算子可以事先对灰度图平滑处理一下(拉普拉斯对噪声敏感)。
python
import cv2
import numpy as np
def edge_detection_canny(img_path, thres=(50,150), ksize=5):
'''
:param img_path:
:param thres: canny算子的限制阈值,[0]为低阈值,[1]为高阈值
:param ksize: canny的核大小
:return:
'''
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, thres[0], thres[1])
# 形态学闭运算:连接断裂的边缘, cv2.MORPH_RECT结果元素矩形, cv2.MORPH_ELLIPSE椭圆形, CROSS十字形
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (ksize, ksize))
# kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (ksize, ksize))
# kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (ksize, ksize))
# 闭运算:先膨胀后腐蚀,用于填充边缘间的细小间隙,连接相邻的边缘片段
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
# 查找轮廓
# 在闭运算后的边缘图像中查找物体的轮廓
# RETR_EXTERNAL: 只检索最外层轮廓(忽略内部孔洞的轮廓),RETR_LIST检索所有轮廓不建立层级,RETR_CCOMP检索所有轮廓组织为两级层级;检索所有轮廓,重建完整的嵌套层级
# CHAIN_APPROX_SIMPLE: 压缩水平、垂直和对角线段,只保留端点;CHAIN_APPROX_NONE:存储所有轮廓
contours, _ = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上绘制轮廓
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
cv2.imshow('edge', edges)
cv2.imshow('closed', closed)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def edge_detection_sobel(img_path, ksize=3):
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=ksize)
sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=ksize)
sobel_magnitude = np.sqrt(sobel_x ** 2 + sobel_y ** 2)
# 转换为8位无符号整数并归一化到0-255
sobel_edges = np.uint8(np.clip(sobel_magnitude, 0, 255))
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
closed = cv2.morphologyEx(sobel_edges, cv2.MORPH_CLOSE, kernel)
contours, _ = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
cv2.imshow('edge', sobel_edges)
cv2.imshow('closed', closed)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def edge_detection_lap(img_path, ksize=3):
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Laplacian(blurred, cv2.CV_64F, ksize=ksize)
laplacian_abs = np.absolute(edges)
laplacian_edges = np.uint8(np.clip(laplacian_abs, 0, 255))
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
closed = cv2.morphologyEx(laplacian_edges, cv2.MORPH_CLOSE, kernel)
contours, _ = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
cv2.imshow('edge', laplacian_edges)
cv2.imshow('closed', closed)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
img_path = './test/test_img.jpg'
edge_detection_canny(img_path)
# edge_detection_sobel(img_path)
# edge_detection_lap(img_path)