python-opencv-视觉巡线


title: Python-opencv-视觉巡线
tags:


一、概述

通过摄像头采集图像,
将图像灰度化、二值化、膨胀、腐蚀操作后,
提取第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()

文章参考德强师兄博客https://purethought.cn/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容