在前几天的文章中,对直线的铁轨可以实现检测,但是实际的过程中,火车的弯轨也是特别多,比如从北京-石家庄的铁路线路,弯路占到了70%以上的比例,所以对于铁轨的弯道检测,也是很重要的一块内容,在一段时间的研究下,终于实现了弯道铁轨的检测,同时也可以拟合S形的铁轨,并且检测速度可以实现实时性的要求,在接下来的工作中,我会把铁轨检测+YOLOv3移植到Jetson TX2+Intel NCS2(神经元计算棒2代)实现实时性检测的过程贴出来供大家参考。
另:本文是参考优达学城的公路车道线检测的项目来进行改进优化调参实现的。
需求环境:
Ubuntu16.04
python3.5
opencv3.2
首先的第一步,就是读入图片
import os
import cv2
import utils
import matplotlib.pyplot as plt
import numpy as np
from moviepy.editor import VideoFileClip
import line
test_imgs = utils.get_images_by_dir('pic')
读入图片之后,使用了sobelX,sobelY,算子边缘检测
将图像转换成HLS通道,然后判断图像像素值信息及三个通道信息
将图像转换成LUV通道,然后判断图像像素值信息及三个通道信息
将图像转换成LAB通道,然后判断图像像素值信息及三个通道信息
def thresholding(img):
#setting all sorts of thresholds
x_thresh = utils.abs_sobel_thresh(img, orient='x', thresh_min=90 ,thresh_max=280)
mag_thresh = utils.mag_thresh(img, sobel_kernel=3, mag_thresh=(30, 170))
dir_thresh = utils.dir_threshold(img, sobel_kernel=3, thresh=(0.7, 1.3))
hls_thresh = utils.hls_select(img, thresh=(160, 255))
lab_thresh = utils.lab_select(img, thresh=(155, 210))
luv_thresh = utils.luv_select(img, thresh=(225, 255))
#Thresholding combination
threshholded = np.zeros_like(x_thresh)
threshholded[((x_thresh == 1) & (mag_thresh == 1)) | ((dir_thresh == 1) & (hls_thresh == 1)) | (lab_thresh == 1) | (luv_thresh == 1)] = 1
return threshholded
处理完成之后的图片如下图所示:
很重要的一步就是选取RIO区域,就是摄像机的记录铁轨区域,选取梯形图,如下图所示:
梯形所示的部分就是我们的RIO区域,只要我们的摄像机安装在火车的固定位置,那么这个RIO区域就是固定的区域,只要在一张图片上校准之后,我们就可以适用于这一个火车所对应的所有的铁轨检测。
选取完RIO区域之后,我们需要将选取的RIO区域转换成鸟瞰图,然后从鸟瞰图里去进行边缘侧检测。转换鸟瞰图的过程其实就是透视变换的处理
thresholded_wraped = cv2.warpPerspective(thresholded, M, img.shape[1::-1], flags=cv2.INTER_LINEAR)
透视处理变换完就是下图的样子:
可以看出来,两条铁轨已经很明显了,接下来的工作就是把这两条曲线拟合出来,左边一条,右边一条,这边注意一下,如果是视频检测的话,和单张图片不一样,视频的话,会从上一条拟合的曲线来更新最新的一条曲线,这里使用的方法是,多次函数拟合,因为火车的铁轨和汽车的车道线不太一样,会有多次弯道,所以,优达学城的二次函数拟合不能完整的拟合出S形的弯道轨迹,所以在这里,我选取的是三次函数拟合,已经可以很好的拟合出来铁轨的走向了。
if left_line.detected and right_line.detected:
left_fit, right_fit, left_lane_inds, right_lane_inds = utils.find_line_by_previous(thresholded_wraped,left_line.current_fit,right_line.current_fit)
else:
left_fit, right_fit, left_lane_inds, right_lane_inds = utils.find_line(thresholded_wraped)
left_line.update(left_fit)
right_line.update(right_fit)
拟合完成之后,将曲线转回到普通的视图中,涂上颜色
def draw_area(undist,binary_warped,Minv,left_fit, right_fit):
# Generate x and y values for plotting
ploty = np.linspace(0, binary_warped.shape[0]-1, binary_warped.shape[0] )
# left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
# right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]
left_fitx = left_fit[0]*ploty**3 + left_fit[1]*ploty**2 + left_fit[2]*ploty+left_fit[3]
right_fitx = right_fit[0]*ploty**3 + right_fit[1]*ploty**2 + right_fit[2]*ploty+right_fit[3]
# Create an image to draw the lines on
warp_zero = np.zeros_like(binary_warped).astype(np.uint8)
color_warp = np.dstack((warp_zero, warp_zero, warp_zero))
# Recast the x and y points into usable format for cv2.fillPoly()
pts_left = np.array([np.transpose(np.vstack([left_fitx, ploty]))])
pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, ploty])))])
pts = np.hstack((pts_left, pts_right))
# Draw the lane onto the warped blank image
cv2.fillPoly(color_warp, np.int_([pts]), (0,255, 0))
# Warp the blank back to original image space using inverse perspective matrix (Minv)
undist = np.array(undist)
newwarp = cv2.warpPerspective(color_warp, Minv, (undist.shape[1], undist.shape[0]))
newwarp = expand(newwarp)
# Combine the result with the original image
result = cv2.addWeighted(undist, 1, newwarp, 0.3, 0)
return result,newwarp
最后,扩张一下铁路的安全距离1.5m
至此,铁轨检测(直轨+弯轨)成功检测75m+的铁轨。
“S”形状铁轨检测效果图
光照度条件不好的铁轨检测效果图
Github链接如下 代码链接
代码不易,欢迎Star~