2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

特定の色を検出して追従するロボット メモ

Last updated at Posted at 2020-09-16

以前 カメラの画像処理によるライントレースカーを作ったことがあり、その応用で「前方の特定の色を検出して追従する車」が作れるのではないかと思い、実際に作ってみました。

一旦ソースコードだけですが公開しておきます。 どういう考え方で制御しているかなど、また気が向いたら追記していきます。
import cv2
import numpy as np
import time
import RPi.GPIO as GPIO
import pigpio

# 正転・逆転制御用GPIO
R_ctrl = 17
L_ctrl = 27

# PWM制御用GPIO
R_PWM = 12
L_PWM = 13

# GPIO設定
GPIO.setwarnings(False) 
GPIO.setmode(GPIO.BCM)
GPIO.setup(R_ctrl, GPIO.OUT)
GPIO.setup(L_ctrl, GPIO.OUT)

# PWM設定
pi = pigpio.pi()
pi.set_mode(R_PWM, pigpio.OUTPUT)
pi.set_mode(L_PWM, pigpio.OUTPUT)

duty_S = 4 #直進PWM duty比
duty_T = 4 #旋回PWM duty比
freq = 700 #PWM周波数
sleep_time_S = 0.05 #モーター動作待ち 直進
sleep_time_T = 0.15 #モーター動作待ち 旋回

# ↓画像処理関係設定↓
camera = cv2.VideoCapture(0)   # カメラCh.(ここでは0)を指定

# カメラ画素数(実環境に合わせて修正)
camera_H = 480 #幅
camera_W = 640 #高さ

B_width = 150 #ブロックエリア幅

T_th = 1000  #曲がり判定しきい値
N_th = 60000 #近づき判定しきい値
F_th = 50000 #離れ判定しきい値

# 二値化設定
th = 50 #閾値
i_max = 255 #閾値超えたら置き換える値

# 青色検出関数
def detect_blue_color(img):
    # HSV色空間に変換
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # 青色のHSVの値域1
    hsv_min = np.array([90, 64, 0])
    hsv_max = np.array([150,255,255])

    # 青色領域のマスク
    mask = cv2.inRange(hsv, hsv_min, hsv_max)

    # マスキング処理
    masked_img = cv2.bitwise_and(img, img, mask=mask)

    return masked_img

# HSV画像のグレースケール化関数
def hsv2gray(img):
    
    (h,s,v) = cv2.split(img) #h,s,v に分割
    s[:] = 0 #彩度を0に
    merge = cv2.merge((h, s, v))
    rgb = cv2.cvtColor(merge, cv2.COLOR_HSV2RGB) #hsv→rgb変換
    gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY) #rgb→グレースケール化
    
    return gray

# モーター制御関数
def motorctrl(R, L, frequency ,duty ,sleep_time):

    #正転・逆転指示
    GPIO.output(R_ctrl, R)
    GPIO.output(L_ctrl, L)

    #指定時間だけモーター回転
    pi.hardware_PWM(R_PWM, frequency, duty*100000)
    pi.hardware_PWM(L_PWM, frequency, duty*100000)
    time.sleep(sleep_time)

    #停止
    pi.hardware_PWM(R_PWM, freq, 000000)
    pi.hardware_PWM(L_PWM, freq, 000000)


while True:
    ret, frame = camera.read()    #フレームを取得
    blue_frame = detect_blue_color(frame) #青色検出
    gray_frame = hsv2gray(blue_frame) #青色をグレースケール化
    ret, bi_frame = cv2.threshold(gray_frame, th, i_max, cv2.THRESH_BINARY) #グレースケールを二値化

    #↓ブロックエリア描画設定(描画させないならコメントアウトでOK)
    #線は青色で描画している(二値化画像では白で表示される)
    cv2.rectangle(bi_frame,(0,camera_H),(B_width,camera_H),(255,0,0),1) #左ブロックエリア
    cv2.rectangle(bi_frame,(camera_W - B_width,0),(camera_W,camera_H),(255,0,0),1) #右ブロックエリア

    #↓エリア設定(領域計算用)[縦,横]
    LB = bi_frame[0:camera_H, 0:B_width] #左ブロックエリア
    RB = bi_frame[0:camera_H, camera_W - B_width:camera_W] #右ブロックエリア
    CA = bi_frame[0:camera_H, 0:camera_W] #画面全体

    #↓各領域の面積計算
    Det_LB = cv2.countNonZero(LB) #左ブロックエリアの白ピクセルカウント
    Det_RB = cv2.countNonZero(RB) #右ブロックエリアの白ピクセルカウント
    Det_CA = cv2.countNonZero(CA) #画面全体の白ピクセルカウント
    
    print("Det_LB: " +str(Det_LB) + "  Det_CA: " +str(Det_CA) +"  Det_RB: " +str(Det_RB))
    
    #↓画像を表示(表示不要であればコメントアウト。表示しないほうが処理早い)
    cv2.imshow('original', frame) #元画像を表示
    #cv2.imshow('detect_blue', blue_frame) #青色検出画像を表示
    cv2.imshow('blue_white', bi_frame) #青色→グレースケール→二値化画像を表示

    #↓制御部分
    #ちょうどいい距離の時は止まっておく
    if (N_th -5000) > Det_CA > (F_th + 5000):
        motorctrl(1,1,freq,0,sleep_time_S)

    #離れすぎたら近づく
    elif Det_CA < F_th:
        print("離れすぎを検出しました")
        motorctrl(1,1,freq,duty_S,sleep_time_S)

    #近すぎたら離れる
    elif Det_CA > N_th:
        print("近すぎを検出しました")
        motorctrl(0, 0, freq, duty_S, sleep_time_S)

    #左にずれたら右旋回
    elif Det_LB > T_th:
        print("左ブロックエリア侵入を検出しました")
        motorctrl(1, 0, freq, duty_T, sleep_time_T)

    #右にずれたら左旋回
    elif Det_RB > T_th:
        print("右ブロックエリア侵入を検出しました")
        motorctrl(0, 1, freq, duty_T, sleep_time_T)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        print("エスケープが押されました")
        break

# 撮影用オブジェクトとウィンドウの解放
camera.release()
cv2.destroyAllWindows()

やってみて思ったのは、とりあえず原理的にできることはわかりましたが、あまり実用的ではないのかなと思いました。
理由
・検出対象と同系色の物体も検出してしまう
・光の当たり方で色の見え方が変わる
等、ノイズに弱いから

フィルタかけたりで工夫はできるのかもしれませんが、どこまでできるのかな、という感じです。
やっぱりもっと形とか、対象の特徴を捉えて追従させるのがいいんだと思います。
単純なロジックなので、処理的には軽いのかもしれません(他の手法をやったことないので比較できていません)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?