python-opencv视觉巡线

    技术2022-07-10  116

    简要概述:

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

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

    Processed: 0.018, SQL: 12