zoukankan      html  css  js  c++  java
  • 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() 
    

    参考文献:
    树莓派小车自动循迹(摄像头)

  • 相关阅读:
    系统综合实践第三次作业
    系统综合实践第二次作业
    系统综合实践第一次作业
    第03组 Beta版本演示
    第03组 Beta冲刺(4/4)
    第04组 Beta版本演示
    第04组 Beta冲刺(4/4)
    第04组 Beta冲刺(3/4)
    第04组 Beta冲刺(2/4)
    第04组 Beta冲刺(1/4)
  • 原文地址:https://www.cnblogs.com/chendeqiang/p/12861661.html
Copyright © 2011-2022 走看看