SSブログ

自動運転士による自動運転計画(続くのか?) [自動運転]

 先週は「さよならの朝に約束の花をかざろう」を公開初日に見に行って、Yahooの映画評はかなりよいですが、映画に単純な楽しさを求める私としては、この映画どうかなあと思いました。で、今週も公開初日に「映画ドラえもん のび太の宝島」を子どもと見に行って、こっちは面白かったです。個人的には去年の南極モノよりも面白かったです。
 そして、ブレードランナー2049のブルーレイが出たので、買って見ました。映画館は3Dかつ字幕でかなり辛かったのですが、2Dで吹き替えだと目に負担がかからなくてよいです。

 さて、本題です。「自動運転士による自動運転計画(続くのか?)」です。
 RasPiにカメラが付き、もしかしたら画像処理も出来そうということで、将来的に画像処理も載せようと思い、今回は信号機の色を確認する処理をしてみます。もちろん、車載などという難しいことはまた今度考えるとして、WindowsPCとこのごろ流行りのPython+OpenCVでやろうと思います。
 まずは交通信号の画像処理について下調べです。ネットを探すと、
以下のものが上のほうに出てきました。
形状及び色特徴を用いた安全運転支援システムのための信号機検出処理
夜間動画像からの道路交通信号認識技術の研究
家庭用ビデオカメラ動画像からの道路交通信号認識


 で、調べるまでは、赤、黄、青の光っている信号機の画像を登録して、パターンマッチングして信号機を検出して、というのが一般的かなと考えていたのですが、どうも、こっちの業界はRGBをHSV変換してやるのが一般的らしいです。
・H:色相 赤から青
・S:彩度 色が淡い~濃い
・V:明度 明るさが暗い~明るい
 まあ、現在はもう一歩進んで機械学習なんでしょうが、私は今までグレースケールの画像処理しか扱っていなかったため、かなりお勉強になりました。
 そして、Python+OpenCVです。バージョン違いやC++の情報がごっちゃになっているなど、どうもネットで情報を探しにくかったですが、まあ、数日にらめっこしたらどうにか実験できるレベルにはなってきました。
 処理の流れは、(1)画像所得、(2)HSV変換、(3)赤信号、黄信号、青信号で二値化する(4)領域面積の一番大きい所の信号の色とする。です。LEDが明るすぎて、信号機の中心部分の色が白く飛ぶなど、どうも、カメラというのは人間の目に比べてダイナミックレンジの低さが気になります。
 実験環境は以下。DS BlueBoxNuckyさんの日本型信号機を使っています。
re_DSC02232.jpg

 画面はこんな感じです。
無題.png

 左上がUSBカメラ像。上真ん中が(使っていないが)Gray変換した二値化画像、左下が青信号二値化、下真ん中が黄色信号二値化、右下が赤信号二値化で、Pythonの環境はアナコンダとスパイダーとかいう環境でやっていますが、よくわかっていません。追加でOpenCVとNumpyとかいうライブラリ?を入れています。デバッグ中はエラーが出て途中で止まると、USBカメラのドライバごと落ちていきます。
 で、動画です。


 まあ、このままだととても外乱光に弱いので、LEDの強力な光を利用して、カメラにND
フィルターを付けてしまって、信号以外の風景や光は見えないようにしてしまおうかと思っていますが、そうすると、点灯する信号以外は全部無視の自動運転士が出来上がる・・・。なにかかなりショボく終わりそうな気がする・・・。

pythonのソースですが、以下です。(書きなぐりです。)
-----
#-*- coding:utf-8 -*-
import cv2
# import numpy as np
import numpy as np


def disp_text(frame,text = "",width = 0,height = 0,size = 1):
    cv2.putText(frame, text, (width, height), cv2.FONT_HERSHEY_PLAIN, size, (255, 255, 255), size, cv2.LINE_AA)

def disp_blue(hsv_frame,rgb_frame):
    # 色相、彩度、明度
    #lower_blue = np.array([70,50,100])
    #upper_blue = np.array([90,100,255])
    lower = np.array([70,50,200])
    upper = np.array([90,255,255])
    # HSV イメージから青い物体だけを取り出すための閾値
    mask = cv2.inRange(hsv_frame, lower, upper)
    # ビットごとのAND演算で元画像をマスク
    res = cv2.bitwise_and(rgb_frame,rgb_frame, mask= mask)
    cv2.imshow('blue',res)
    return np.sum(res)

def disp_yellow(hsv_frame,rgb_frame):
    # 色相、彩度、明度
    lower = np.array([15,50,200])
    upper = np.array([35,255,255])
    # HSV イメージから黄色い物体だけを取り出すための閾値
    mask = cv2.inRange(hsv_frame, lower, upper)
    # ビットごとのAND演算で元画像をマスク
    res = cv2.bitwise_and(rgb_frame,rgb_frame, mask= mask)
    cv2.imshow('yellow',res)
    return np.sum(res)

def disp_red(hsv_frame,rgb_frame):
    # 色相、彩度、明度
    #lower_blue = np.array([170,100,100])
    #upper_blue = np.array([190,255,255])
    lower = np.array([00,50,200])
    upper = np.array([10,255,255])
    # HSV イメージから赤い物体だけを取り出すための閾値
    mask1 = cv2.inRange(hsv_frame, lower, upper)

    lower = np.array([170,50,200])
    upper = np.array([180,255,255])
    mask2 = cv2.inRange(hsv_frame, lower, upper)
    
    mask = mask1 | mask2
    # ビットごとのAND演算で元画像をマスク
    res = cv2.bitwise_and(rgb_frame,rgb_frame, mask= mask)
    cv2.imshow('red',res)
    return np.sum(res)

def disp_gray(rgb_frame):
    gray = cv2.cvtColor(rgb_frame, cv2.COLOR_BGR2GRAY)
    # 二値変換
    thresh = 200
    max_pixel = 255
    ret, img_dst = cv2.threshold(gray,
                                 thresh,
                                 max_pixel,
                                 cv2.THRESH_BINARY)
    cv2.imshow('gray',img_dst)
    return np.sum(img_dst)

#def main():

# 動画の読み込み
cap = cv2.VideoCapture(1)

# 動画終了まで繰り返し
#while(cap.isOpened()):
while(1):
    # フレームを取得
    ret, img = cap.read()
    org_height, org_width = img.shape[:2]
    
    #画面表示を考えて大きさを小さくする
    size = (org_width//3*2, org_height//3*2)
    frame = cv2.resize(img, size)

    #HSV変換
        # BGR空間から HSV空間に変換
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    gray_s = disp_gray(frame)
    blue_s = disp_blue(hsv,frame)
    yellow_s = disp_yellow(hsv,frame)
    red_s = disp_red(hsv,frame)
    temp_str = "b,y,r"+str(blue_s)+","+str(yellow_s)+","+str(red_s)
    #どの色が強いか
    sig = np.array([blue_s, yellow_s,red_s])
    sig_name = np.array(["blue", "yellow","red"])
    sig_max = np.argmax(sig)

    _h, _s, _v = cv2.split(hsv)
    max_h = np.amax(_v)
  
    # フレームを表示
    # 左上から中央まで、太さ50の赤い四角形を描く
    # 画像の高さ、幅を取得
    height, width = frame.shape[:2]
    #cv2.rectangle(frame, (0, 0), (width/2, height/2), (0, 0, 255), 50)

    cv2.rectangle(frame, (0, 0), (width//2,height//3), (64, 64, 64), -1)
    temp_height = 20
    disp_text(frame,"v:"+str(max_h),0,temp_height)
    temp_height += 20
    disp_text(frame,temp_str,0,temp_height)
    temp_height += 40
    disp_text(frame,sig_name[sig_max],0,temp_height,2)
    cv2.imshow("raw", frame)
    
    #esc key
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()


コメント(0) 

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。