第一次接触无人机和计算机视觉的结合时,我被这个交叉领域的可能性震撼了。想象一下,一台能自主识别物体、跟踪目标甚至避开障碍物的飞行器——这不再是科幻电影的场景,而是每个开发者现在都能动手实现的项目。本文将带你从零开始,用Python和OpenCV构建你的第一个智能无人机应用。
对于初学者,我强烈推荐DJI Tello系列无人机。这款不足100克的迷你无人机不仅价格亲民(约100美元),还提供了完善的Python SDK。它的最大优势是内置了视觉定位系统,即使在室内也能稳定悬停,这对计算机视觉实验至关重要。
注意:购买前确认你的型号是"Tello EDU"版本,普通版Tello的SDK功能有限
开发环境我选择Anaconda+VS Code的组合,以下是具体配置步骤:
bash复制conda create -n dronecv python=3.8
conda activate dronecv
bash复制pip install opencv-python numpy djitellopy
python复制import cv2
print(cv2.__version__) # 应显示4.x版本
通过DJITelloPy库控制无人机的典型代码如下:
python复制from djitellopy import Tello
drone = Tello()
drone.connect()
# 基础控制指令
drone.takeoff()
drone.move_left(50) # 单位:厘米
drone.rotate_clockwise(90) # 单位:度
drone.land()
实时获取视频流是计算机视觉的基础,这段代码展示了如何将无人机摄像头画面显示在本地:
python复制drone.streamon()
while True:
frame = drone.get_frame_read().frame
cv2.imshow("Drone View", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
drone.streamoff()
cv2.destroyAllWindows()
这个经典项目能让你理解视觉反馈控制的基本原理。我们使用OpenCV的Haar级联分类器:
python复制face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
while True:
frame = drone.get_frame_read().frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
# 计算人脸中心与画面中心的偏移量
center_x = x + w//2
offset = center_x - frame.shape[1]//2
# 根据偏移控制无人机旋转
if abs(offset) > 50:
drone.rotate_clockwise(offset//10)
cv2.imshow("Face Tracking", frame)
更进阶的挑战是让无人机跟随特定颜色的物体。我们使用HSV色彩空间提高鲁棒性:
python复制# 定义红色范围(根据实际目标调整)
lower_red = np.array([0, 120, 70])
upper_red = np.array([10, 255, 255])
while True:
frame = drone.get_frame_read().frame
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_red, upper_red)
# 寻找最大轮廓
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if contours:
largest = max(contours, key=cv2.contourArea)
x,y,w,h = cv2.boundingRect(largest)
# 控制逻辑
if w > 50: # 目标足够大时才移动
center_x = x + w//2
if center_x < frame.shape[1]//3:
drone.move_left(20)
elif center_x > 2*frame.shape[1]//3:
drone.move_right(20)
实测中发现无人机在视觉处理延迟时容易产生振荡。我的解决方案是:
python复制# PID控制器示例
class SimplePID:
def __init__(self, Kp, Ki, Kd):
self.Kp, self.Ki, self.Kd = Kp, Ki, Kd
self.prev_error = 0
self.integral = 0
def update(self, error, dt):
self.integral += error * dt
derivative = (error - self.prev_error) / dt
output = self.Kp*error + self.Ki*self.integral + self.Kd*derivative
self.prev_error = error
return output
# 使用时
pid = SimplePID(0.8, 0.001, 0.05)
offset = ... # 计算得到的偏移量
control = pid.update(offset, 1/30) # 假设30fps
drone.rotate_clockwise(int(control))
在树莓派等资源受限设备上运行时,这些技巧能显著提升帧率:
python复制# 设置低分辨率
drone.set_video_resolution(Tello.RESOLUTION_480P)
# ROI示例
roi_width = 200
roi_height = 200
while True:
frame = drone.get_frame_read().frame
height, width = frame.shape[:2]
roi = frame[height//2-roi_height//2:height//2+roi_height//2,
width//2-roi_width//2:width//2+roi_width//2]
# 只在ROI区域处理...
飞行前检查:
紧急情况处理:
python复制def emergency_stop():
drone.emergency() # 立即停止电机
drone.streamoff()
cv2.destroyAllWindows()
# 绑定快捷键
keyboard.on_press_key('space', lambda _: emergency_stop())
法律合规:
完成基础功能后,可以尝试这些进阶方向:
python复制# AprilTag检测示例
import apriltag
detector = apriltag.Detector()
while True:
gray = cv2.cvtColor(drone.get_frame_read().frame, cv2.COLOR_BGR2GRAY)
results = detector.detect(gray)
for r in results:
# 提取三维姿态信息
pose, _, _ = detector.detection_pose(r, [500,500,width//2,height//2])
print(f"Tag {r.tag_id} position: {pose[:3,3]}")
开发过程中最深的体会是:计算机视觉算法在实际物理系统中的应用,需要比纯软件开发更多的妥协和调优。光照变化、运动模糊、处理延迟等因素都会显著影响最终效果。我的建议是从最简单的案例开始,逐步增加复杂度,每次只改变一个变量进行测试。