如何让cv2.HoughLinesP仅检测垂直线,避免识别电车线架横线?
只检测电车架空线(垂直线)的优化方案
针对线架水平线误检测的问题,无需依赖效果不佳的腐蚀操作,以下两种方法可以直接解决:
方法一:过滤检测到的线条斜率
计算每条线段的斜率,只保留接近垂直的线条(斜率绝对值极大,或x坐标几乎无变化),彻底过滤水平线。
修改代码中处理lines的部分:
if lines is not None: # 垂直阈值:可根据实际场景调整,值越大要求线条越接近垂直 vertical_threshold = 10 for line in lines: x1, y1, x2, y2 = line[0] dx = x2 - x1 if dx == 0: # 完全垂直的线段 cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0), 5) else: slope = abs((y2 - y1) / dx) if slope > vertical_threshold: # 接近垂直的线段 cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0), 5)
方法二:用垂直结构元素强化垂直线
如果想在边缘检测阶段就弱化水平线,可以替换你之前的正方形腐蚀核,改用垂直结构元素:
# 创建高瘦的垂直核,保留垂直线条,消除短水平线 kernel = np.ones((10,1), np.uint8) edges = cv2.erode(edges, kernel, iterations=1)
完整优化后的代码
整合以上两种优化点的完整代码:
import cv2 import numpy as np import window_names import track_bars vid = 'blackpool_tram_result.mp4' cap = cv2.VideoCapture(vid) frame_counter = 0 while (True): ret, frame = cap.read() frame_counter += 1 if frame_counter == cap.get(cv2.CAP_PROP_FRAME_COUNT): frame_counter = 0 cap.set(cv2.CAP_PROP_POS_FRAMES, 0) blank = np.zeros(frame.shape[:2], dtype='uint8') grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) output = np.empty(grey.shape, dtype=np.uint8) cv2.normalize( grey, output, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX) hist = cv2.equalizeHist(output) track_bars.lower_threshold = cv2.getTrackbarPos("lower", window_names.window_canny) track_bars.upper_threshold = cv2.getTrackbarPos("upper", window_names.window_canny) track_bars.smoothing_neighbourhood = cv2.getTrackbarPos("smoothing", window_names.window_canny) track_bars.sobel_size = cv2.getTrackbarPos("sobel size", window_names.window_canny) track_bars.smoothing_neighbourhood = max(3, track_bars.smoothing_neighbourhood) if not (track_bars.smoothing_neighbourhood % 2): track_bars.smoothing_neighbourhood = track_bars.smoothing_neighbourhood + 1 track_bars.sobel_size = max(3, track_bars.sobel_size) if not (track_bars.sobel_size % 2): track_bars.sobel_size = track_bars.sobel_size + 1 smoothed = cv2.GaussianBlur( hist, (track_bars.smoothing_neighbourhood, track_bars.smoothing_neighbourhood), 0) edges = cv2.Canny( smoothed, track_bars.lower_threshold, track_bars.upper_threshold, apertureSize=track_bars.sobel_size) # 可选:用垂直结构元素腐蚀,强化垂直线,过滤短水平线 kernel = np.ones((10,1), np.uint8) edges = cv2.erode(edges, kernel, iterations=1) rho = 1 # 霍夫网格的距离分辨率(像素) theta = np.pi / 180 # 霍夫网格的角度分辨率(弧度) threshold = 15 # 最小投票数 minLineLength = 50 # 线段最小长度 maxLineGap = 20 # 线段最大间隙 line_image = np.copy(frame) * 0 mask = cv2.rectangle(blank, (edges.shape[1]//2 + 150, edges.shape[0]//2 - 150), (edges.shape[1]//2 - 150, edges.shape[0]//2 - 300), 255, -1) masked = cv2.bitwise_and(edges,edges,mask=mask) lines = cv2.HoughLinesP(masked, rho, theta, threshold, np.array([]), minLineLength, maxLineGap) if lines is not None: # 过滤只保留垂直线段 vertical_threshold = 10 for line in lines: x1, y1, x2, y2 = line[0] dx = x2 - x1 if dx == 0: cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0), 5) else: slope = abs((y2 - y1) / dx) if slope > vertical_threshold: cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0), 5) lines_edges = cv2.addWeighted(frame, 0.8, line_image, 1, 0) cv2.imshow(window_names.window_hough, frame) cv2.imshow(window_names.window_canny, edges) cv2.imshow(window_names.window_mask, mask) cv2.imshow(window_names.window_masked_image, masked) key = cv2.waitKey(27) if (key == ord('x')) & 0xFF: break cv2.destroyAllWindows()
调整建议
- 可以根据实际视频场景修改
vertical_threshold的值:值越大,对线条垂直程度的要求越高;值越小,允许的倾斜范围越大。 - 若架空线存在轻微倾斜,可适当降低
vertical_threshold,或调整腐蚀核的高度。
内容的提问来源于stack exchange,提问作者Isaac_E
相关产品推荐
相关产品推荐

