求助:如何从道路掩码二值图中提取左右边缘点集
解决方案
方法一:基于现有轮廓检测结果分割左右边缘
针对你当前轮廓包含道路底部边界、无法区分左右点集的问题,可通过两步处理解决:
- 过滤底部边界点:道路掩码的底部边缘通常靠近图像下边界,通过y坐标阈值过滤掉这部分无效点
- 按x坐标分割左右边缘:以图像中线为界,将剩余点分为左、右两个独立点集
修改后的代码如下:
import cv2 import numpy as np image = cv2.imread('/home/user/Desktop/seg_output/1.jpg') h, w = image.shape[:2] gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _, binary_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY) contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=cv2.contourArea, reverse=True) # 获取最大轮廓点集并去除冗余维度 contour_points = np.squeeze(contours[0]) # 过滤底部边界点:保留y坐标小于图像高度90%的点(可根据实际情况调整阈值) y_threshold = int(h * 0.9) filtered_points = contour_points[contour_points[:, 1] < y_threshold] # 按图像中线分割左右边缘 mid_x = w // 2 left_edge_points = filtered_points[filtered_points[:, 0] < mid_x] right_edge_points = filtered_points[filtered_points[:, 0] > mid_x] # 可视化结果 vis_image = image.copy() cv2.drawContours(vis_image, [left_edge_points], -1, (0, 0, 255), 2) cv2.drawContours(vis_image, [right_edge_points], -1, (255, 0, 0), 2) print("左边缘点数量:", len(left_edge_points)) print("右边缘点数量:", len(right_edge_points)) cv2.imshow('Left & Right Edges', vis_image) cv2.waitKey(0) cv2.destroyAllWindows()
方法二:Sobel边缘检测+轮廓提取
你提到的Sobel兼容性问题,只需将Sobel输出转换为8位无符号整数,即可正常进行轮廓检测:
import cv2 import numpy as np image = cv2.imread('/home/user/Desktop/seg_output/1.jpg') h, w = image.shape[:2] gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Sobel边缘检测并转换为8位图像 sobel_x = cv2.Sobel(gray_image, cv2.CV_64F, 1, 0, ksize=3) sobel_y = cv2.Sobel(gray_image, cv2.CV_64F, 0, 1, ksize=3) sobel_edges = cv2.convertScaleAbs(cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)) # 二值化后提取轮廓 _, binary_sobel = cv2.threshold(sobel_edges, 50, 255, cv2.THRESH_BINARY) contours, _ = cv2.findContours(binary_sobel, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 过滤小轮廓并分割左右边缘 contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 50] all_points = np.concatenate([np.squeeze(cnt) for cnt in contours]) y_threshold = int(h * 0.9) filtered_points = all_points[all_points[:, 1] < y_threshold] mid_x = w // 2 left_edge = filtered_points[filtered_points[:, 0] < mid_x] right_edge = filtered_points[filtered_points[:, 0] > mid_x] # 可视化结果 vis_image = image.copy() cv2.drawContours(vis_image, [left_edge], -1, (0,0,255), 2) cv2.drawContours(vis_image, [right_edge], -1, (255,0,0), 2) cv2.imshow('Sobel-based Edges', vis_image) cv2.waitKey(0) cv2.destroyAllWindows()
补充说明
- 若道路左右边缘有明显上下走向,也可通过轮廓点的排列顺序分割:OpenCV轮廓按顺时针/逆时针排列,左、右边缘通常连续分布,可通过x坐标变化趋势区分,但按中线分割更简单直接
- 所有阈值参数(y坐标阈值、Sobel二值化阈值)可根据实际图像调整,以获得最优效果
内容的提问来源于stack exchange,提问作者Pratham
相关产品推荐
相关产品推荐

