无人驾驶中如何识别颜色并跟踪的具体应用

摄像头对于颜色的识别,我们在上一篇文章中有具体的介绍,并介绍了OpenCV中的一些常见知识点,这里我们来对颜色识别在无人驾驶中,做一个具体应用。

有兴趣的可以先看下本人拍摄的一个视频:无人车识别颜色并跟踪  

通过视频我们可以看到无人车,会跟着自己设定的颜色而行驶,包括转弯的实现。那么无人车是如何识别颜色并跟踪的呢?其中的转弯又是怎么做到的呢?我们先来看下代码,代码就是很好的解释:

1、无人驾驶代码

from jetbotmini import Camera
from jetbotmini import bgr8_to_jpeg
import cv2
import numpy as np
import torch
import torchvision
import traitlets
import ipywidgets.widgets as widgets
from IPython.display import display
from jetbotmini import Robot

# 实例化摄像头
camera = Camera.instance(width=300, height=300)

# 蓝色上下限数组
color_lower = np.array([100,43,46])
color_upper = np.array([124, 255, 255])

# 初始化无人车驱动电机实例
robot = Robot()

# 图片、速度进度条、转弯进度条组件的显示
image_widget = widgets.Image(format='jpeg', width=300, height=300)
speed_widget = widgets.FloatSlider(value=0.4, min=0.0, max=1.0, description='speed')
turn_gain_widget = widgets.FloatSlider(value=0.5, min=0.0, max=2.0, description='turn gain')
display(widgets.VBox([widgets.HBox([image_widget]),speed_widget,turn_gain_widget]))

width = int(image_widget.width)
height = int(image_widget.height)

center_x = 0
def execute(change):
    # -----这块属于对图像的处理与颜色检测,上篇文章有详细介绍------
    frame = camera.value
    frame = cv2.resize(frame, (300, 300))
    frame_=cv2.GaussianBlur(frame,(5,5),0)
    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    mask=cv2.inRange(hsv,color_lower,color_upper)
    mask=cv2.erode(mask,None,iterations=2)
    mask=cv2.dilate(mask,None,iterations=2)
    mask=cv2.GaussianBlur(mask,(3,3),0)
    cnts=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
    # ------------------------------------------------------------------------

    # 检测到了目标
    if len(cnts)>0:
        cnt = max(cnts,key=cv2.contourArea)
        (color_x,color_y),color_radius=cv2.minEnclosingCircle(cnt)
        if color_radius > 10:
            # 将检测到的颜色标记出来
            cv2.circle(frame,(int(color_x),int(color_y)),int(color_radius),(255,0,255),2)
            # 偏离中心位置来判断是否转弯
            # [-1,1]
            center_x = (150 - color_x)/150
            robot.set_motors(
                float(speed_widget.value + turn_gain_widget.value * center_x),
                float(speed_widget.value - turn_gain_widget.value * center_x)
            )
    # 没有检测到就停止
    else:
        pass
        robot.stop()
    # 更新图像显示到Image组件
    image_widget.value = bgr8_to_jpeg(frame)

将摄像头初始化,并且定义了一个能够检测到颜色的方法,除了识别颜色之外,我们还做了一个颜色目标位置在摄像头左右的偏移量,这个是用来给左右马达更新不同的速度值的。这个就是为什么无人车可以进行转弯的原因了,目标的中心位置在图像中心位置的偏离值,我们将其添加到马达的速度中去,左右马达一个是加另一个是减,这样就形成了差速!
接下来我们调用这个方法:execute({'new': camera.value})
当然这种调用只能检测到一帧,我们需要的是实时更新摄像头的图像,实时的去跟踪变化的场景。
我们使用observe方法来实时处理:

camera.unobserve_all()
camera.observe(execute, names='value')

这样就可以实时检测蓝颜色目标,如果检测到目标,就会跟随目标行驶,如果没有检测到,无人车将会停止。

2、无人车停止

虽然上面代码可以在没有检测到目标的时候,无人车会自动停止,但有时候我们也想要强制停止无人车,如下:

import time
camera.unobserve_all()
time.sleep(1.0)
robot.stop()

我们可以看到上面的代码整体跟颜色识别章节差不多,区别在于多了一个无人车的加入,更准确来讲是多了左右两个轮子(马达),这两个轮子是差速轮,意思就是各自拥有一个马达驱动,速度可以不同(速度一样就是直行),这样才能够转弯和漂移等操作,根据识别到的颜色的中心位置来更新左右马达的速度,这样就有了跟踪的效果。

其中如何驱动无人车的更多详细介绍可以查阅:Jetson Nano驱动机器人的左右两路电机

3、camera.observe

observe(handler, names=traitlets.All, type='change')

设置一个在trait改变时调用的处理程序
其中handler是回调函数,调用的就是上面定义的execute函数,handler(change),其中change是一个字典,所以这也是调用execute时,参数是字典的原因{'new': camera.value}
在type为change的情况下,有以下几个键:

owner:HasTraits实例
old:修改后的trait属性的旧值
new:修改后的trait属性的新值
name:修改后的trait属性的名称

所以这里就做到了一个类似死循环的效果,可以对摄像头的每一帧进行更新。

4、camera.unobserve_all

camera.unobserve_all(name=traitlets.All)

删除指定名称的任何类型的trait更改处理程序。如果未指定名称,删除所有trait通知器。或者通俗来讲就是关闭视频流,释放资源的意思。
所以我们看到在camera.observe和robot.stop()之前都先做一步释放资源的处理以及停止无人车。

5、CSI摄像头

这里对摄像头做一个附加解释,随着人工智能的发展,自动驾驶,智能家居等应用都离不开摄像头,而一款低功耗低成本高清晰的摄像头就显得尤为重要了。一般大家见到的摄像头是USB接口,而这里是使用CSI接口协议的摄像头,如图:

可以看到这里是15针的排线,不是常见的USB接口,CSI接口是主机处理器与摄像头模块之间的高速串行接口,最关键点是能耗低,这也导致了现在手机高清摄像头的普及。

猜你喜欢

转载自blog.csdn.net/weixin_41896770/article/details/131778946