如何在OpenCV中获取连续平滑轮廓?高斯滤波后仍存断裂问题
轮廓平滑后出现不连续的解决方法
问题描述
我的目标是提取平滑轮廓,目前用scipy的gaussian_filter分别对轮廓的x、y像素坐标做平滑处理后绘制,但结果出现不连续情况。试过多种滤波器(中值、均匀、savgol),哪怕只单独平滑x或y坐标后绘制基线(绿色),问题依然存在。怀疑是不是对cv2.findContours()返回的数据解构错误,但没找到相关文档依据。
附上代码:
import numpy as np from scipy.ndimage import gaussian_filter import cv2 img = cv2.imread("<Path>") imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, imgBin = cv2.threshold(imgGray, 70, 255, 0) print(img.shape) # 反转二值图像 imgBin = cv2.bitwise_not(imgBin) # 提取轮廓 cont, hier = cv2.findContours(imgBin, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 筛选面积大于5000的轮廓 large_contours = [] for k in cont: if(cv2.contourArea(k) > 5000): large_contours.append(k) # 在白板上绘制原始轮廓 whiteBoard = np.full(shape=img.shape, fill_value=0, dtype=np.uint8) cv2.drawContours(whiteBoard, large_contours, -1,255, 1) # 设置高斯滤波参数 sig = 70 # 绘制平滑后的轮廓 for cnt in large_contours: originalX = np.array(cnt[:, 0,1]) originalY = np.array(cnt[:, 0,0]) # 平滑坐标点 xscipy = gaussian_filter(originalX, sig) yscipy = gaussian_filter(originalY, sig) # 绘制平滑后的点 whiteBoard[xscipy, yscipy, 1] = 255 cv2.imshow('ag', whiteBoard) cv2.waitKey(0) cv2.destroyAllWindows()
补充图像说明:
- 原始图像:包含清晰圆形轮廓的黑白图像
- 处理结果:白色原始轮廓与绿色不连续的平滑轮廓叠加显示
- 点分布图:展示轮廓坐标点的分布状态
问题分析与解决方法
核心问题
- 坐标解构错误:
cv2.findContours返回的轮廓数组格式是(N,1,2),每个点的坐标是(x,y),代码里把originalX取成cnt[:,0,1](对应y轴)、originalY取成cnt[:,0,0](对应x轴),导致坐标轴颠倒,后续平滑后绘制错位。 - 绘制方式错误:直接通过
whiteBoard[xscipy, yscipy, 1] = 255逐个标记像素,没有将平滑后的点按顺序连接成线,这是轮廓不连续的主要原因。 - 滤波参数不合理:
sig=70的高斯滤波核过大,过度模糊坐标点,丢失轮廓连续性。
修正后的代码
import numpy as np from scipy.ndimage import gaussian_filter import cv2 img = cv2.imread("<Path>") imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, imgBin = cv2.threshold(imgGray, 70, 255, 0) # 反转二值图像 imgBin = cv2.bitwise_not(imgBin) # 提取轮廓 cont, hier = cv2.findContours(imgBin, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 筛选面积大于5000的轮廓 large_contours = [k for k in cont if cv2.contourArea(k) > 5000] # 在白板上绘制原始轮廓 whiteBoard = np.full(shape=img.shape, fill_value=0, dtype=np.uint8) cv2.drawContours(whiteBoard, large_contours, -1, (255,255,255), 1) # 设置合理的高斯滤波参数(可根据需求微调) sig = 10 # 处理每个大轮廓 for cnt in large_contours: # 正确提取x、y坐标:cnt[:,0,0]是x,cnt[:,0,1]是y original_x = cnt[:, 0, 0].astype(np.float64) original_y = cnt[:, 0, 1].astype(np.float64) # 平滑坐标点 smoothed_x = gaussian_filter(original_x, sig) smoothed_y = gaussian_filter(original_y, sig) # 将平滑后的坐标组合成轮廓格式,并转换为整数 smoothed_contour = np.stack((smoothed_x, smoothed_y), axis=1).reshape(-1,1,2).astype(np.int32) # 用cv2.drawContours绘制连续的平滑轮廓(绿色) cv2.drawContours(whiteBoard, [smoothed_contour], -1, (0,255,0), 1) cv2.imshow('Smooth Contour', whiteBoard) cv2.waitKey(0) cv2.destroyAllWindows()
关键修正点
- 修正坐标提取:调换
originalX和originalY的索引,确保x、y坐标对应正确的轴。 - 改用
cv2.drawContours绘制:将平滑后的坐标重新组织成轮廓数组格式,用OpenCV的绘制函数连接成线,保证连续性。 - 调整滤波参数:将
sig从70改为10(可按需微调),避免过度模糊导致轮廓变形。
内容的提问来源于stack exchange,提问作者user22034139
相关产品推荐
相关产品推荐

