python-opencv視覺巡線


簡要概述:

通過攝像頭采集圖像,
將圖像灰度化、二值化、膨脹、腐蝕操作后,
提取第400行像素值v,接近於圖像底線位置,
提取中間值(這里為白色)的數量和位置,
根據數量和位置,利用簡單的數學公式,(首項+尾項)/2,計算出白色的中間位置,
然后對比實際的中間位置320(不需要改),計算出偏移量,
最后根據偏移量計算出電機應有的轉角。

一、邊緣檢測實驗

#!/usr/bin/env python3

# 識別的是中線為白色

import cv2
import numpy as np

# center定義
center = 320
# 打開攝像頭,圖像尺寸640*480(長*高),opencv存儲值為480*640(行*列)
cap = cv2.VideoCapture(0)
while (1):
    ret, frame = cap.read()
    cv2.imshow("recognize_face", frame)
    # 轉化為灰度圖
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    cv2.imshow("gray", gray)
    # 大津法二值化
    retval, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
    cv2.imshow("dst", dst)
    # 膨脹,白區域變大
    dst = cv2.dilate(dst, None, iterations=2)
    cv2.imshow("dst2", dst)
    # # 腐蝕,白區域變小 #
    dst = cv2.erode(dst, None, iterations=6)
    cv2.imshow("dst3", dst)
    # 單看第400行的像素值v
    color = dst[400]
    try:
        # 找到白色的像素點個數,如尋黑色,則改為0
        white_count = np.sum(color == 255)
        # 找到白色的像素點索引,如尋黑色,則改為0
        white_index = np.where(color == 255)
        # 防止white_count=0的報錯
        if white_count == 0:
            white_count = 1
        # 找到黑色像素的中心點位置
        # 計算方法應該是邊緣檢測,計算白色邊緣的位置和/2,即是白色的中央位置。
        center = (white_index[0][white_count - 1] + white_index[0][0]) / 2
        # 計算出center與標准中心點的偏移量,因為圖像大小是640,因此標准中心是320,因此320不能改。
        direction = center - 320
        print(direction)
    except:
        continue
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release() #釋放cap
cv2.destroyAllWindows()#銷毀所有窗口

二、樹莓派GPIO應用

# coding:utf-8 
# 實現樹莓派小車的變速控制 
import RPi.GPIO as gpio 
# 定義引腳 
in1 = 12 
in2 = 16 
in3 = 18 
in4 = 22 
# 設置GPIO口為BOARD編號規范,從左到右,從上到下。 
gpio.setmode(gpio.BOARD) 
# 設置GPIO口為輸出 
gpio.setup(in1, gpio.OUT) 
gpio.setup(in2, gpio.OUT) 
gpio.setup(in3, gpio.OUT) 
gpio.setup(in4, gpio.OUT) 
# 設置PWM波,頻率為500Hz 
pwm1 = gpio.PWM(in1, 500) 
pwm2 = gpio.PWM(in2, 500) 
pwm3 = gpio.PWM(in3, 500) 
pwm4 = gpio.PWM(in4, 500) 
# 初始化 
pwm1.start(0) 
pwm2.start(0) 
pwm3.start(0) 
pwm4.start(0) 
# 定義向前 
def go(): 
    pwm1.ChangeDutyCycle(50) 
    pwm2.ChangeDutyCycle(0) 
    pwm3.ChangeDutyCycle(50) 
    pwm4.ChangeDutyCycle(0) 
# 定義向右 
def right(): 
    pwm1.ChangeDutyCycle(50) 
    pwm2.ChangeDutyCycle(0) 
    pwm3.ChangeDutyCycle(30) 
    pwm4.ChangeDutyCycle(0) 
# 定義向左 
def left(): 
    pwm1.ChangeDutyCycle(30) 
    pwm2.ChangeDutyCycle(0) 
    pwm3.ChangeDutyCycle(50) 
    pwm4.ChangeDutyCycle(0) 
# 定義向后 
def back(): 
    pwm1.ChangeDutyCycle(0) 
    pwm2.ChangeDutyCycle(50) 
    pwm3.ChangeDutyCycle(0) 
    pwm4.ChangeDutyCycle(50) 
# 定義停止 
def stop(): 
    pwm1.ChangeDutyCycle(0) 
    pwm2.ChangeDutyCycle(0) 
    pwm3.ChangeDutyCycle(0) 
    pwm4.ChangeDutyCycle(0) 
pwm1.stop() 
pwm2.stop() 
pwm3.stop() 
pwm4.stop() 
gpio.cleanup()

三、視覺巡線

# coding:utf-8 
# 加入攝像頭模塊,讓小車實現自動循跡行駛 
# 思路為:攝像頭讀取圖像,進行二值化,將白色的賽道凸顯出來 
# 選擇下方的一行像素,黑色為0,白色為255 # 找到白色值的中點 
# 目標中點與標准中點(320)進行比較得出偏移量 
# 根據偏移量來控制小車左右輪的轉速 
# 考慮了偏移過多失控->停止;偏移量在一定范圍內->高速直行(這樣會速度不穩定,已刪) 
import RPi.GPIO as gpio 
import time 
import cv2 
import numpy as np 
import serial

ser=serial.Serial('/dev/ttyAMA0',115200,timeout=1)
# 定義引腳 
pin1 = 12 
pin2 = 16 
pin3 = 18 
pin4 = 22 
# 設置GPIO口為BOARD編號規范 
gpio.setmode(gpio.BOARD) 
# 設置GPIO口為輸出 
gpio.setup(pin1, gpio.OUT) 
gpio.setup(pin2, gpio.OUT) 
gpio.setup(pin3, gpio.OUT) 
gpio.setup(pin4, gpio.OUT) 
# 設置PWM波,頻率為500Hz 
pwm1 = gpio.PWM(pin1, 500) 
pwm2 = gpio.PWM(pin2, 500) 
pwm3 = gpio.PWM(pin3, 500) 
pwm4 = gpio.PWM(pin4, 500) 
# pwm波控制初始化 
pwm1.start(0) 
pwm2.start(0) 
pwm3.start(0) 
pwm4.start(0) 
# center定義 
center = 320 
# 打開攝像頭,圖像尺寸640*480(長*高),opencv存儲值為480*640(行*列) 
cap = cv2.VideoCapture(0) 
while (1): 
    ret, frame = cap.read()
    cv2.imshow("recognize_face", frame) 
    # 轉化為灰度圖 
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 
    # 大津法二值化 
    retval, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU) 
    # 膨脹,白區域變大 
    dst = cv2.dilate(dst, None, iterations=2) 
    cv2.imshow("dst", dst)
    # # 腐蝕,白區域變小 # 
    #dst = cv2.erode(dst, None, iterations=6) 
    # 單看第400行的像素值s 
    color = dst[400] 
    try:
        # 找到白色的像素點個數,如尋黑色,則改為0
        white_count = np.sum(color == 255)
        # 找到白色的像素點索引,如尋黑色,則改為0
        white_index = np.where(color == 255)
        # 防止white_count=0的報錯
        if white_count == 0:
            white_count = 1
        # 找到黑色像素的中心點位置
        # 計算方法應該是邊緣檢測,計算白色邊緣的位置和/2,即是白色的中央位置。
        center = (white_index[0][white_count - 1] + white_index[0][0]) / 2
        # 計算出center與標准中心點的偏移量,因為圖像大小是640,因此標准中心是320,因此320不能改。
        direction = center - 320
        print(direction)
        ser.write(direction)
    except:
        continue

    # 停止 
    if abs(direction) > 250: 
        pwm1.ChangeDutyCycle(0) 
        pwm2.ChangeDutyCycle(0) 
        pwm3.ChangeDutyCycle(0) 
        pwm4.ChangeDutyCycle(0) 
    # 右轉 
    elif direction >= 0: 
        # 限制在70以內 
        if direction > 70: 
            direction = 70 
        pwm1.ChangeDutyCycle(30 + direction) 
        pwm2.ChangeDutyCycle(0) 
        pwm3.ChangeDutyCycle(30) 
        pwm4.ChangeDutyCycle(0) 
    # 左轉 
    elif direction < -0: 
        if direction < -70: 
            direction = -70 
        pwm1.ChangeDutyCycle(30) 
        pwm2.ChangeDutyCycle(0) 
        pwm3.ChangeDutyCycle(30 - direction) 
        pwm4.ChangeDutyCycle(0) 
    if cv2.waitKey(1) & 0xFF == ord('q'): 
        break 
# 釋放清理 
cap.release() 
cv2.destroyAllWindows() 
pwm1.stop() 
pwm2.stop() 
pwm3.stop() 
pwm4.stop() 
gpio.cleanup() 

參考文獻:
樹莓派小車自動循跡(攝像頭)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM