「PiCar-Xでlane detection(02) 自動運転のための車線検出」で下図のように車線を検出することが出来ました。今回はここから車の進むべき方向を決める、道路の真ん中=道路の向きの中心を求める方法について考えてみます。
一般的にはここから左側の複数の線分(赤い領域)の平均を取って左車線、同じく右側の複数の線分(青い領域)の平均を取って右車線を求めて、その両線の中央値を計算して道路の中央を求めます。
ただ、これが意外とややっこしい(-.-;)
真ん中から左の線分を左車線、同じく右側の線分を右車線としたいところですが、例えば下の写真のように必ずしも車は常に道路の中央からPiCameraで写真を撮っているわけではなく、カーブなどでは右に左にステアリングをとっているので、道路に対して斜めからの写真も多くなります。下の図のように片方の車線が画面からはみ出しそうになることも再々です。
とにかく左側車線と右側車線の区分をすることが出来ず、どのように左右を分けたら良いのか悩むところです。
1.PiCameraから画像の取り込み
「PiCar-Xでlane detection(04) PiCameraから画像の取り込み」で説明したように、imutilsのVideoStreamを使って動画撮影➡画像の切取りを行っています。
# 画像の高さ 幅を取得
Image_height, Image_width, c = image.shape
Image_height: 480
Image_width: 640
2.オリジナル画像から作業領域をクロップ
cropped_image = image[int(Image_height / 2):int(Image_height / 2 + 100), 0:int(Image_width)]
画像の高さは、中央から下へ幅100pix、横幅は画像の幅そのままでクロップ
3.画像をBGRからHSVへ変換
hsv_image = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2HSV)
4.OpenCV – inRangeで画像を2値化
lower = np.array([20, 0, 0])
upper = np.array([40, 255, 255])
masked_image = cv2.inRange(hsv_image, lower, upper)
5.OpenCV – cannyによるエッジ検出
canny_conversion = cv2.Canny(masked_image, 50, 155)
6.region of interest(注目する領域)を設定
ROI_image = reg_of_interest(canny_conversion)
見た目は変化ありませんが、「PiCar-Xでlane detection(05) PiCameraで撮影した画像の切り取りについて」で説明したように左右を台形状にカットしています。
7.OpenCV – HoughLinesPによる直線の検出
Hough_lines = cv2.HoughLinesP(ROI_image, 2, np.pi / 180, 50, np.array([]), minLineLength=20, maxLineGap=20)
# Hough_linesをcropped_imageと同じ大きさの黒色のキャンパスに描画
lanelines_image = show_lines(cropped_image, Hough_lines)
【それに続く処理】
黄色い線の左右両端を検出しているので、この例では左右2本の線分が検出されています。ただこの例でも左側がやや短く検出されています。また撮影条件によっては線分が途中で途切れたりして2本以上の線分として検出されるケースもあります。このブログページの最初の画像がそのよい例だと思います。
これらの複数の線分から左端・右端の線分を求めます。
left_right_lines = line_select(lanelines_image, Hough_lines)
# left-right_linesをcropped_imageと同じ大きさの黒色のキャンパスに描画
line_image = show_lines_result(cropped_image, left_right_lines)
# 上のline_imageとcropped_imageとを合成
combine_image = cv2.addWeighted(cropped_image, 0.8, line_image, 1, 1)
left_right_linesの中身は、
array([[313, 100, 307, 0],
[341, 100, 335, 0]])
2本の線分のデータとなっています。
# left_line_top left_line_top = left_right_lines[0, 2] # right_line_top right_line_top = left_right_lines[1, 2] center_line = (left_line_top + right_line_top) / 2 # image_center image_center = Image_width / 2 # ----------------------------------------------------------------------------- # steer steer = (center_line - image_center) / image_center * 80
上の式の「80」は、実際に動かしながら試行錯誤で求めた(ハイパー)パラメーターで、モデル条件が変われば改めて試行錯誤で最適解を求め直す必要があります。