如何使用OpenCV-Python提取闭合灰色区域下方红线的坐标
解决OpenCV-Python提取灰色区域下方红线坐标的问题
看起来你已经搞定了红线轮廓的提取,现在就差把灰色区域上方的那部分红线坐标过滤掉对吧?核心思路就是先找到灰色闭合区域的底部边界,再筛选出红线中位于这个边界下方的点就行,我给你拆解具体步骤:
1. 先定位灰色区域的底部边界
首先得把灰色闭合区域的轮廓单独拎出来,这样才能确定它的“底部”在哪里(OpenCV里图像坐标是左上角为原点,y轴向下,所以底部对应最大的y值)。你可以通过颜色阈值或者轮廓面积来区分灰色区域:
方法一:通过颜色提取灰色区域
如果灰色区域的颜色比较固定,用HSV阈值分割最靠谱,代码示例:
# 转HSV空间,方便颜色筛选 hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV) # 这里的灰色范围你可以用取色工具调整,适配你的图像 lower_gray = np.array([0, 0, 50]) upper_gray = np.array([180, 50, 200]) gray_mask = cv2.inRange(hsv, lower_gray, upper_gray) # 提取灰色区域的轮廓,只取最外层的 gray_contours, _ = cv2.findContours(gray_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 假设面积最大的轮廓就是目标灰色区域 gray_contour = max(gray_contours, key=cv2.contourArea) # 计算灰色区域的最大y值(底部位置) gray_bottom_y = np.max(gray_contour[:, :, 1])
方法二:通过轮廓面积判断
如果灰色区域比红线大很多,也可以直接从已提取的contours里挑面积最大的那个当作灰色区域:
# 从所有轮廓中找到面积最大的(灰色区域) gray_contour = max(contours, key=cv2.contourArea) gray_bottom_y = np.max(gray_contour[:, :, 1])
2. 筛选红线的下方坐标
你已经把红线的坐标存在pix_array里了,现在只需要过滤出y值大于gray_bottom_y的点就行:
# 筛选出位于灰色区域下方的红线坐标 lower_red_points = pix_array[pix_array[:, 1] > gray_bottom_y] # 输出结果,比如你之前要的最小x坐标 print("下方红线的最小x坐标:", min(lower_red_points[..., 0]))
3. 优化你的完整代码
我把你的原有代码补全并整合了上述逻辑,你可以直接参考:
import cv2 import numpy as np def find_drawContours(path): src = cv2.imread(path) src = cv2.GaussianBlur(src, (3,3), 0) gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) # 用OTSU自动二值化,适配不同光照的图像 ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # OpenCV4+版本findContours返回两个值 contours, hierachy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 步骤1:获取灰色区域的底部y值 hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV) lower_gray = np.array([0, 0, 50]) upper_gray = np.array([180, 50, 200]) gray_mask = cv2.inRange(hsv, lower_gray, upper_gray) gray_contours, _ = cv2.findContours(gray_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not gray_contours: print("未检测到灰色区域") return gray_contour = max(gray_contours, key=cv2.contourArea) gray_bottom_y = np.max(gray_contour[:, :, 1]) # 步骤2:提取红线坐标并筛选下方部分 # 假设contours[0]是红线轮廓,如果不是可以换对应的索引 pix_list = [point[0] for point in contours[0]] pix_array = np.array(pix_list) lower_red_points = pix_array[pix_array[:, 1] > gray_bottom_y] print("下方红线坐标:", lower_red_points) print("下方红线的最小x坐标:", min(lower_red_points[..., 0])) # 可视化结果,用绿色标记下方红线 for point in lower_red_points: cv2.circle(src, tuple(point), 2, (0,255,0), -1) cv2.imwrite('img/res.lower_red.jpg', src)
额外提示
- 如果红线的轮廓是上下分开的两个独立轮廓,那你可以直接计算每个轮廓的y坐标中心,保留y中心更大的那个轮廓即可,不用逐个点筛选。
- 要是灰色区域的颜色阈值不好调,也可以尝试先提取红色线的mask,再用形态学操作去掉上方的部分,但不如先定位灰色区域精准。
内容的提问来源于stack exchange,提问作者Jiguang Lu




