You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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()

补充图像说明:

  • 原始图像:包含清晰圆形轮廓的黑白图像
  • 处理结果:白色原始轮廓与绿色不连续的平滑轮廓叠加显示
  • 点分布图:展示轮廓坐标点的分布状态

问题分析与解决方法

核心问题

  1. 坐标解构错误:cv2.findContours返回的轮廓数组格式是(N,1,2),每个点的坐标是(x,y),代码里把originalX取成cnt[:,0,1](对应y轴)、originalY取成cnt[:,0,0](对应x轴),导致坐标轴颠倒,后续平滑后绘制错位。
  2. 绘制方式错误:直接通过whiteBoard[xscipy, yscipy, 1] = 255逐个标记像素,没有将平滑后的点按顺序连接成线,这是轮廓不连续的主要原因。
  3. 滤波参数不合理: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 23:52:55