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

求助:cv2.findContours将numpy平铺图像识别为独立数组的问题

如何让cv2提取平铺后整个数组的轮廓

我将一幅图像平铺3次后,使用cv2.findContours提取轮廓,但结果提取出了原图像的三次独立轮廓,而非整个数组的轮廓。相关代码如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

rr,thetar,phir,br520=hdf.rdhdf_3d('/blahblah/testing/br000520.hdf') # 加载数据
br520_r1p05=br520[:,:,61]
trp_br520=np.tile(br520_r1p05,3) # 平铺数据

ret, th = cv.threshold(trp_br520, 0, 255, cv.THRESH_BINARY_INV)
th=th.astype(np.uint8)
contours, hierarchy = cv.findContours(th, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
conts=sorted(contours, key=len)

# 绘图:
fig,ax=plt.subplots(figsize=(10,4))
ax.imshow(trp_br520,cmap='seismic',vmin=-10,vmax=10)
ax.set_title('Tripling array')

colors = plt.cm.plasma(np.linspace(0,1,len(conts)))

for i in range(len(list(conts))):
    ax.scatter(np.asarray(conts[i])[:,0,1],np.asarray(conts[i])[:,0,0],color=colors[i],s=5)
plt.tight_layout()

运行后,cv2.findContours提取出了三个独立的轮廓,对应三次平铺的图像区域,而非覆盖整个(180,1080)数组的单一轮廓。


问题根源

cv2.findContours基于连通像素区域提取轮廓,平铺后的三个图像副本之间没有连通的目标像素,因此被识别为三个独立的连通域,对应三个轮廓。


解决方案

方案1:形态学操作连通区域(推荐)

通过膨胀操作填补三个平铺区域之间的间隙,让目标像素连通成一个整体,再提取最外层轮廓:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 加载和平铺数据
rr,thetar,phir,br520=hdf.rdhdf_3d('/blahblah/testing/br000520.hdf')
br520_r1p05=br520[:,:,61]
trp_br520=np.tile(br520_r1p05,3)

# 阈值处理
ret, th = cv.threshold(trp_br520, 0, 255, cv.THRESH_BINARY_INV)
th=th.astype(np.uint8)

# 用膨胀操作连通三个区域(可根据实际情况调整核大小和迭代次数)
kernel = np.ones((3, 3), np.uint8)
th = cv.dilate(th, kernel, iterations=2)

# 提取最外层轮廓
contours, hierarchy = cv.findContours(th, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# 取面积最大的轮廓(即整个连通区域的轮廓)
conts = [max(contours, key=cv.contourArea)] if contours else []

# 绘图
fig,ax=plt.subplots(figsize=(10,4))
ax.imshow(trp_br520,cmap='seismic',vmin=-10,vmax=10)
ax.set_title('Tripling array with merged contour')

colors = plt.cm.plasma(np.linspace(0,1,len(conts)))
for i in range(len(conts)):
    ax.scatter(np.asarray(conts[i])[:,0,1],np.asarray(conts[i])[:,0,0],color=colors[i],s=5)
plt.tight_layout()
plt.show()

方案2:手动合并轮廓

如果不想修改阈值图像,可以直接将提取到的三个轮廓的点合并成一个整体轮廓:

# 原代码到提取轮廓部分不变
contours, hierarchy = cv.findContours(th, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)

# 合并所有轮廓的坐标点
merged_contour = np.vstack(contours)
# 转为轮廓格式(单个轮廓的数组)
conts = [merged_contour]

# 后续绘图代码不变

注意:这种方法会保留所有轮廓的细节点,如果只需要整个数组的外轮廓,方案1更合适。


内容的提问来源于stack exchange,提问作者weaselskinghenry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 23:47:16