OpenCV气泡轮廓极值点处理:多同X轴点时实现Y轴对齐选取
解决方案:OpenCV气泡轮廓极值点Y轴对齐问题
问题说明
用OpenCV提取充气气泡(白色区域)轮廓的极值点时,先对图像二值化、阈值处理后提取轮廓,再通过numpy的argmin()/argmax()获取最左、最右点。但当最右点所在竖直线上存在多个像素时,argmax()仅返回第一个实例,导致最左、最右点Y轴坐标不对齐,弦长计算出现误差。
需求:
- 若某X轴上存在多个点,最左和最右点需Y轴对齐
- 若无多点,仍按原逻辑选取第一个实例
修改后的代码实现
核心思路是先筛选出最左/最右X值对应的所有点,再通过匹配Y坐标(优先取中位数或最接近值)实现两点对齐:
# 导入必要库(若未导入) import numpy as np from scipy.spatial import distance as dist import cv2 import imutils from imutils import contours # (原阈值处理代码省略) cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cnts = imutils.grab_contours(cnts) (cnts, _) = contours.sort_contours(cnts) # 选择气泡轮廓(索引根据实际情况调整) c = cnts[1] # 将轮廓坐标转换为二维数组(原形状为(N,1,2)) points = c.reshape(-1, 2) x_coords = points[:, 0] y_coords = points[:, 1] # 获取最小、最大X值 min_x = x_coords.min() max_x = x_coords.max() # 筛选最左X、最右X对应的所有点 left_points = points[x_coords == min_x] right_points = points[x_coords == max_x] # 计算目标Y值(优先用左点的中位数,保证对齐) if len(left_points) == 1: target_y = left_points[0][1] else: target_y = np.median(left_points[:, 1]) # 确定最左点:若左点有多个,选最接近目标Y的点 if len(left_points) > 1: left_idx = np.argmin(np.abs(left_points[:, 1] - target_y)) extLeft = tuple(left_points[left_idx]) else: extLeft = tuple(left_points[0]) # 确定最右点:在右点中选最接近目标Y的点 if len(right_points) > 1: right_idx = np.argmin(np.abs(right_points[:, 1] - target_y)) extRight = tuple(right_points[right_idx]) else: extRight = tuple(right_points[0]) # 原有的顶部、底部极值点计算逻辑不变 extTop = tuple(c[c[:, :, 1].argmin()][0]) extBot = tuple(c[c[:, :, 1].argmax()][0]) # 后续绘图、计算、保存代码不变 cv2.drawContours(image, [c], -1, (0, 255, 255), 2) cv2.circle(image, extLeft, 4, (0, 0, 255), -1) cv2.circle(image, extRight, 4, (0, 255, 0), -1) cv2.circle(image, extTop, 1, (255, 0, 0), -1) cv2.circle(image, extBot, 1, (255, 100, 0), -1) chord = (dist.euclidean(extLeft, extRight))/pixelsPerMetric height = int(extTop[1]-extBot[1])/pixelsPerMetric print(chord) print(height) cv2.putText(image, "{:.1f}mm".format(chord), extLeft, cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2) cv2.imshow("Image", image) fname="extreme.jpg" print(extLeft) print(extBot) print(extRight) cv2.imwrite(fname, image) cv2.waitKey(0) cv2.destroyAllWindows()
代码说明
- 轮廓坐标转换:将OpenCV返回的三维轮廓数组
c转换为二维数组,方便后续筛选操作 - 筛选极值X对应的点:提取所有X等于最小/最大值的点,覆盖同竖直线上的所有像素
- Y坐标对齐逻辑:
- 若最左X只有一个点,直接以其Y为目标值;若有多个点,取Y坐标的中位数作为基准
- 在最右X的点集中,选取Y坐标最接近目标值的点,确保两点Y轴对齐
- 若最左X有多个点,同样选取最接近目标Y的点,保证逻辑一致性
内容的提问来源于stack exchange,提问作者chipmunk008
相关产品推荐
相关产品推荐

