20、树莓派机器人的计算机视觉与编程实践

树莓派机器人的计算机视觉与编程实践

1. OpenCV 简单斑点检测

在使用 OpenCV 进行简单斑点检测时,我们可以通过以下步骤实现:
1. 编写代码打印关键点的坐标和大小到终端:

# print the coordinates and size of keypoints to terminal
for k in keypnts:
    print k.pt[0]
    print k.pt[1]
    print k.size
cv2.waitKey(0)
  1. 保存文件。
  2. 打开终端窗口。
  3. 导航到保存文件的文件夹。
  4. 输入 python simple_blob_detect.py 并按回车键。

运行上述步骤后,会打开图像的三个版本,并且原始图像中蓝色球周围会绘制一个红色圆圈,同时在终端窗口中会打印出球的中心坐标和大小。

2. SimpleBlobDetector 参数

SimpleBlobDetector 类需要一些参数才能正常工作。强烈建议通过将相应参数设置为 true false 来明确启用或禁用所有过滤选项。如果启用了某个过滤器,则还需要为其设置参数。默认参数配置为提取深色圆形斑点。

图像首先通过应用阈值转换为多个二值图像, minThreshold maxThreshold 确定整体范围, thresholdStep 确定阈值之间的距离。然后使用 findContours() 处理每个二值图像的轮廓,计算每个斑点的中心。使用 minDistanceBetweenBlobs 参数将多个斑点组合成一个组,组的中心作为关键点返回,同时返回组的整体直径。最后计算每个过滤器的参数并应用过滤器。

3. 过滤器及参数
过滤器 参数 说明
filterByColor blobColor 过滤每个二值图像的相对强度,测量斑点中心的强度值并与 blobColor 参数进行比较,强度范围为 0 - 255,0 为暗,255 为亮。
filterByArea minArea, maxArea 当单个斑点分组时,计算其总面积,此过滤器查找面积在 minArea maxArea 之间的斑点。
filterByCircularity minCircularity, maxCircularity 圆度通过公式 4 * Area / (perimeter * perimeter) 计算,返回 0 到 1 之间的比率,与 minCircularity maxCircularity 比较,若值在参数之间,则该斑点包含在结果中。
filterByInertia minInertiaRatio, maxInertiaRatio 惯性是对斑点伸长程度的估计,是 0 到 1 之间的比率,若值在 minInertiaRatio maxInertiaRatio 之间,则该斑点在关键点结果中返回。
filterByConvexity minConvexity, maxConvexity 凸度是 0 到 1 之间的比率,测量斑点中凸曲线和凹曲线的比率,参数为 minConvexity maxConvexity
4. 斑点跟踪

要跟踪斑点,需要使用机器人相机的实时视频流,并定义跟踪的含义。最简单的跟踪形式是让生成的圆圈随斑点移动。具体步骤如下:
1. 打开 Thonny IDE 并创建一个新文件。
2. 将文件保存为 blob_tracker.py
3. 输入以下代码:

import cv2
import numpy as np
cap = cv2.VideoCapture(0)
# setup detector and parameters
params = cv2.SimpleBlobDetector_Params()
params.filterByColor = False
params.filterByArea = True
params.minArea = 20000
params.maxArea = 30000
params.filterByInertia = False
params.filterByConvexity = False
params.filterByCircularity = True
params.minCircularity = 0.5
params.maxCircularity = 1
det = cv2.SimpleBlobDetector_create(params)
# define blue
lower_blue = np.array([80,60,20])
upper_blue = np.array([130,255,255])
while True:
    ret, frame = cap.read()
    imgHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    blueMask = cv2.inRange(imgHSV,lower_blue, upper_blue)
    blur = cv2.blur(blueMask, (10,10))
    res = cv2.bitwise_and(frame, frame, mask=blueMask)
    # get and draw keypoint
    keypnts = det.detect(blur)
    cv2.drawKeypoints(frame, keypnts, frame, (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    cv2.imshow('frame', frame)
    cv2.imshow('mask', blur)
    for k in keypnts:
        print k.size
    if cv2.waitKey(1) & 0xff == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
  1. 保存文件。
  2. 打开终端窗口。
  3. 导航到保存文件的文件夹。
  4. 输入 sudo python blob_tracker.py 并按回车键。

运行后会打开两个窗口,一个显示用于颜色过滤的掩码,另一个显示视频流,斑点周围会绘制一个圆圈。

5. 追球机器人

结合 PID 控制器和斑点跟踪程序,我们可以编写一个追球机器人的程序。目标是让机器人跟踪蓝色球并保持球在画面中心。具体步骤如下:
1. 打开 Thonny IDE 并创建一个新文件。
2. 将文件保存为 ball_chaser.py
3. 输入以下代码:

import cv2
import numpy as np
import time
from adafruit_motorkit import MotorKit
# create motor objects
kit = MotorKit()
# create motor list
motors = [kit.motor1, kit.motor2, kit.motor3, kit.motor4]
# motor multipliers
motorMultiplier = [1.0, 1.0, 1.0, 1.0, 1.0]
# motor speeds
motorSpeed = [0,0,0,0]
# speeds
speedDef = 1.0
leftSpeed = speedDef
rightSpeed = speedDef
diff = 0
maxDiff = 0.5
turnTime = 0.5
# create camera object
cap = cv2.VideoCapture(0)
time.sleep(1)
# PID
kp = 1.0
ki = 1.0
kd = 1.0
ballX = 0.0
ballY = 0.0
x = {'axis':'X',
     'lastTime':int(round(time.time()*1000)),
     'lastError':0.0,
     'error':0.0,
     'duration':0.0,
     'sumError':0.0,
     'dError':0.0,
     'PID':0.0}
y = {'axis':'Y',
     'lastTime':int(round(time.time()*1000)),
     'lastError':0.0,
     'error':0.0,
     'duration':0.0,
     'sumError':0.0,
     'dError':0.0,
     'PID':0.0}
# setup detector
params = cv2.SimpleBlobDetector_Params()
# define detector parameters
params.filterByColor = False
params.filterByArea = True
params.minArea = 15000
params.maxArea = 40000
params.filterByInertia = False
params.filterByConvexity = False
params.filterByCircularity = True
params.minCircularity = 0.5
params.maxCircularity = 1
# create blob detector object
det = cv2.SimpleBlobDetector_create(params)
# define blue
lower_blue = np.array([80,60,20])
upper_blue = np.array([130,255,255])
def driveMotors(leftChnl = speedDef, rightChnl = speedDef, duration = defTime):
    # determine the speed of each motor by multiplying
    # the channel by the motors multiplier
    motorSpeed[0] = leftChnl * motorMultiplier[0]
    motorSpeed[1] = leftChnl * motorMultiplier[1]
    motorSpeed[2] = rightChnl * motorMultiplier[2]
    motorSpeed[3] = rightChnl * motorMultiplier[3]
    # run the motors. if the channel is negative, run
    # reverse. else run forward
    if(leftChnl < 0):
        motors[0].throttle(-motorSpeed[0])
        motors[1].throttle(-motorSpeed[1])
    else:
        motors[0].throttle(motorSpeed[0])
        motors[1].throttle(motorSpeed[1])
    if (rightChnl < 0):
        motors[2].throttle(motorSpeed[2])
        motors[3].throttle(motorSpeed[3])
    else:
        motors[2].throttle(-motorSpeed[2])
        motors[3].throttle(-motorSpeed[3])
def PID(axis):
    lastTime = axis['lastTime']
    lastError = axis['lastError']
    # get the current time
    now = int(round(time.time()*1000))
    duration = now-lastTime
    # calculate the error
    axis['sumError'] += axis['error'] * duration
    axis['dError'] = (axis['error'] - lastError)/duration
    # prevent runaway values
    if axis['sumError'] > 1: axis['sumError'] = 1
    if axis['sumError'] < -1: axis['sumError'] = -1
    # calculate PID
    axis['PID'] = kp * axis['error'] + ki * axis['sumError'] + kd * axis['dError']
    # update variables
    axis['lastError'] = axis['error']
    axis['lastTime'] = now
    # return the output value
    return axis
def killMotors():
    motors[0].throttle(0)
    motors[1].throttle(0)
    motors[2].throttle(0)
    motors[3].throttle(0)
# main program
try:
    while True:
        # capture video frame
        ret, frame = cap.read()
        # calculate center of frame
        height, width, chan = np.shape(frame)
        xMid = width/2 * 1.0
        yMid = height/2 * 1.0
        # filter image for blue ball
        imgHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        blueMask = cv2.inRange(imgHSV, lower_blue, upper_blue)
        blur = cv2.blur(blueMask, (10,10))
        res = cv2.bitwise_and(frame,frame, mask=blur)
        # get keypoints
        keypoints = det.detect(blur)
        try:
            ballX = int(keypoints[0].pt[0])
            ballY = int(keypoints[0].pt[1])
        except:
            pass
        # draw keypoints
        cv2.drawKeypoints(frame, keypoints, frame, (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
        # calculate error and get PID ratio
        xVariance = (ballX - xMid) / xMid
        yVariance = (yMid - ballY) / yMid
        x['error'] = xVariance/xMid
        y['error'] = yVariance/yMid
        x = PID(x)
        y = PID(y)
        # calculate left and right speeds
        leftSpeed = (speedDef * y['PID']) + (maxDiff * x['PID'])
        rightSpeed = (speedDef * y['PID']) - (maxDiff * x['PID'])
        # another safety check for runaway values
        if leftSpeed > (speedDef + maxDiff): leftSpeed = (speedDef + maxDiff)
        if leftSpeed < -(speedDef + maxDiff): leftSpeed = -(speedDef + maxDiff)
        if rightSpeed > (speedDef + maxDiff): rightSpeed = (speedDef + maxDiff)
        if rightSpeed < -(speedDef + maxDiff): rightSpeed = -(speedDef + maxDiff)
        # drive motors
        driveMotors(leftSpeed, rightSpeed, driveTime)
        # show frame
        # cv2.imshow('frame', frame)
        # cv2.waitKey(1)
except KeyboardInterrupt:
    killMotors()
    cap.release()
    cv2.destroyAllWindows()
  1. 保存文件。
  2. 打开终端窗口。
  3. 导航到保存文件的文件夹。
  4. 输入 sudo python ball_chaser.py 并按回车键。

运行几秒钟后,机器人应该开始向前移动,如果画面中有蓝色球,它会转向球,尝试将球保持在画面中心。

6. 机器人类型与工具选择

机器人技术涵盖了很多不同的领域,其定义取决于个人的兴趣。例如,有人对小型桌面机器人感兴趣,有人则对大型机器人、飞行机器人、水下机器人、自动驾驶汽车或家庭自动化和物联网等领域感兴趣。

不同的机器人领域需要不同的工具。在软件方面,有很多选择,如 PyCharm、Spyder 和 Microsoft 的 Visual Studio 等。PyCharm 的社区版提供了几乎所有项目所需的功能,适用于 Windows 和 Linux 系统;Spyder 包含在 Anaconda 发行版中,为科学和学术社区提供了许多工具;Visual Studio 的社区版也越来越易于使用,可满足大多数开发需求。

graph LR
    A[开始] --> B[安装摄像头]
    B --> C[安装OpenCV]
    C --> D[简单斑点检测]
    D --> E[斑点跟踪]
    E --> F[追球机器人编程]
    F --> G[选择合适工具]
    G --> H[结束]

通过以上内容,我们可以看到如何利用树莓派和 OpenCV 实现计算机视觉相关的功能,从简单的斑点检测到复杂的追球机器人编程,同时了解了不同机器人领域所需的工具选择。

树莓派机器人的计算机视觉与编程实践

7. 机器人领域的多样性及工具考量

机器人技术的范畴极为广泛,不同人对其的关注点差异很大。比如,有些人热衷于小型桌面机器人的开发,这类机器人通常结构相对简单,设计时甚至可以凭借临时构思或纸笔记录来完成。而对于大型机器人、飞行机器人或是水下机器人等更为复杂的项目,可能就需要借助 CAD 软件进行精确设计。

在工具使用上,可分为硬件和软件两类。这里着重探讨软件工具,因为它在机器人技术的各个领域都有广泛应用,并且选择工具主要取决于个人的习惯和实际需求。

软件工具 特点 适用场景
PyCharm 专业级 Python 集成开发环境,社区版功能丰富,支持 Windows 和 Linux 系统 大多数 Python 项目开发
Spyder 包含在 Anaconda 发行版中,为科学和学术社区提供众多工具 科研和学术相关的 Python 编程
Visual Studio 功能强大,社区版对初学者和爱好者越来越友好,可满足多种开发需求 多领域的综合开发
8. 不同 IDE 的优势与选择

在选择集成开发环境(IDE)时,有多种选择可供考虑。

  • PyCharm :这是一款专业的 Python 开发工具,其社区版具备了几乎所有项目所需的功能。对于经常在 Windows 和 Linux 系统间切换工作的开发者来说非常方便,在 Windows 机器上完成代码编写和调试后,可无缝转移到树莓派上继续使用相同的工具进行代码更新。
  • Spyder :它是 Anaconda 发行版中的一部分,安装较为便捷。该 IDE 提供了许多针对科学和学术领域的工具,深受数据科学家的喜爱。如果你从事科研或学术相关的 Python 编程工作,Spyder 会是一个不错的选择。
  • Visual Studio :曾经主要面向专业开发者,如今其社区版对初学者和爱好者也越来越友好。它功能强大,可以满足大多数开发需求,无论是 Python 编程还是其他类型的项目开发都能胜任。
graph LR
    A[选择 IDE] --> B{需求和习惯}
    B --> |专业 Python 开发| C[PyCharm]
    B --> |科研学术编程| D[Spyder]
    B --> |综合开发需求| E[Visual Studio]
9. 总结与展望

通过一系列的实践,我们充分利用了树莓派的强大功能,借助计算机视觉技术实现了比单纯使用微控制器更为复杂的任务。从安装摄像头到安装 OpenCV,再到进行简单斑点检测、斑点跟踪以及编程实现追球机器人,每一个步骤都让我们对机器人的视觉处理和控制有了更深入的理解。

在这个过程中,我们不仅学习了 OpenCV 的基本操作和应用,还结合了 PID 控制器等算法,将理论知识应用到实际项目中。同时,我们也了解到机器人技术领域的多样性,以及不同领域所需的工具选择。

未来,随着技术的不断发展,树莓派和 OpenCV 在机器人领域的应用将会更加广泛。我们可以进一步探索更多的计算机视觉算法,优化机器人的视觉处理能力;也可以结合其他传感器,如激光雷达、超声波传感器等,让机器人具备更强大的感知能力。此外,在软件工具方面,我们也可以不断尝试新的 IDE 和开发框架,提高开发效率和代码质量。

总之,机器人技术充满了无限的可能性,通过不断学习和实践,我们可以创造出更多有趣和实用的机器人项目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值