求助: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
相关产品推荐
相关产品推荐

