OpenCV 基础入门
引言
OpenCV(开源计算机视觉库)是一个强大的图像处理和计算机视觉库。对于 LeBot 来说,OpenCV 用于处理摄像头图像、检测障碍物、识别环境特征等视觉任务。本章将介绍 OpenCV 的基础知识和在 LeBot 中的应用。
OpenCV 安装
Python 环境
bash
# 使用 pip 安装
pip install opencv-python
# 安装完整版本(包括额外模块)
pip install opencv-contrib-python
# 验证安装
python -c "import cv2; print(cv2.__version__)"C++ 环境
bash
# Ubuntu/Debian
sudo apt-get install libopencv-dev
# macOS
brew install opencv
# 或从源代码编译
git clone https://github.com/opencv/opencv.git
cd opencv
mkdir build
cd build
cmake ..
make -j4
sudo make install基本图像操作
读取和显示图像
python
import cv2
import numpy as np
# 读取图像
image = cv2.imread('robot_camera.jpg')
# 检查是否成功读取
if image is None:
print("错误:无法读取图像")
else:
# 显示图像
cv2.imshow('Original Image', image)
# 获取图像信息
height, width, channels = image.shape
print(f"图像尺寸:{width}x{height}, 通道数:{channels}")
# 等待按键(0 表示无限等待)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存图像
cv2.imwrite('output.jpg', image)图像缩放
python
import cv2
image = cv2.imread('large_image.jpg')
# 方法 1:指定缩放比例
scaled = cv2.resize(image, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)
# 方法 2:指定输出尺寸
scaled = cv2.resize(image, (640, 480))
# 显示对比
cv2.imshow('Original', image)
cv2.imshow('Scaled', scaled)
cv2.waitKey(0)
cv2.destroyAllWindows()图像裁剪
python
import cv2
image = cv2.imread('image.jpg')
# 使用数组切片裁剪(ROI - Region of Interest)
x, y, w, h = 100, 50, 200, 150 # x, y, 宽度, 高度
cropped = image[y:y+h, x:x+w]
cv2.imshow('Cropped', cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()颜色空间转换
python
import cv2
image = cv2.imread('image.jpg')
# BGR 是 OpenCV 的默认格式
# 转换为 RGB(显示正确的颜色)
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 转换为灰度图
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 转换为 HSV(色调、饱和度、亮度)
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 转换为 LAB 颜色空间
lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
# 显示不同的颜色空间
cv2.imshow('Gray', gray_image)
cv2.imshow('HSV', hsv_image)
cv2.waitKey(0)
cv2.destroyAllWindows()图像处理基础
阈值处理
python
import cv2
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 二值阈值处理
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 自适应阈值(更好地处理光照不均匀)
adaptive_thresh = cv2.adaptiveThreshold(
gray, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
11, 2
)
# 显示结果
cv2.imshow('Binary', binary)
cv2.imshow('Adaptive', adaptive_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()模糊处理
python
import cv2
image = cv2.imread('image.jpg')
# 高斯模糊(最常用)
blurred = cv2.GaussianBlur(image, (5, 5), 0)
# 均值模糊
mean_blur = cv2.blur(image, (5, 5))
# 中值模糊(去噪)
median_blur = cv2.medianBlur(image, 5)
# 双边滤波(保持边界清晰)
bilateral = cv2.bilateralFilter(image, 9, 75, 75)
cv2.imshow('Gaussian', blurred)
cv2.imshow('Bilateral', bilateral)
cv2.waitKey(0)
cv2.destroyAllWindows()边缘检测
python
import cv2
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Sobel 边缘检测
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=5)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=5)
# Canny 边缘检测(最常用)
edges = cv2.Canny(gray, 100, 200)
# Laplacian 边缘检测
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()形态学操作
python
import cv2
import numpy as np
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 创建核(内核)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
# 腐蚀(缩小白色区域)
eroded = cv2.erode(binary, kernel, iterations=1)
# 膨胀(扩大白色区域)
dilated = cv2.dilate(binary, kernel, iterations=1)
# 开运算(先腐蚀后膨胀,去除小噪点)
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
# 闭运算(先膨胀后腐蚀,填补小孔洞)
closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
# 梯度(膨胀减去腐蚀,边界检测)
gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('Opening', opening)
cv2.imshow('Closing', closing)
cv2.imshow('Gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()特征检测和匹配
角点检测(Harris)
python
import cv2
import numpy as np
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Harris 角点检测
corners = cv2.cornerHarris(gray, 2, 3, 0.04)
# 将角点标记为红色
image_copy = image.copy()
image_copy[corners > 0.01 * corners.max()] = [0, 0, 255]
cv2.imshow('Harris Corners', image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()ORB 特征检测和描述
python
import cv2
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 创建 ORB 检测器
orb = cv2.ORB_create(nfeatures=500)
# 检测关键点和计算描述符
keypoints, descriptors = orb.detectAndCompute(gray, None)
# 绘制关键点
image_with_keypoints = cv2.drawKeypoints(
image, keypoints, None,
color=(0, 255, 0),
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
)
cv2.imshow('ORB Features', image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()SIFT 特征匹配
python
import cv2
# 读取两张图像
img1 = cv2.imread('scene.jpg')
img2 = cv2.imread('object.jpg')
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 创建 SIFT 检测器
sift = cv2.SIFT_create()
# 检测关键点和描述符
kp1, des1 = sift.detectAndCompute(gray1, None)
kp2, des2 = sift.detectAndCompute(gray2, None)
# 特征匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
# Lowe's 比率测试
good_matches = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good_matches.append(m)
# 绘制匹配结果
result = cv2.drawMatches(
img1, kp1,
img2, kp2,
good_matches, None,
flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS
)
cv2.imshow('Feature Matching', result)
cv2.waitKey(0)
cv2.destroyAllWindows()物体检测
轮廓检测
python
import cv2
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 检测轮廓
contours, hierarchy = cv2.findContours(
binary,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE
)
# 绘制轮廓
image_copy = image.copy()
cv2.drawContours(image_copy, contours, -1, (0, 255, 0), 2)
# 分析轮廓
for cnt in contours:
# 轮廓面积
area = cv2.contourArea(cnt)
# 轮廓周长
perimeter = cv2.arcLength(cnt, True)
# 最小包围矩形
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
# 最小包围圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
# 拟合椭圆
if len(cnt) > 5:
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(image_copy, ellipse, (255, 0, 0), 2)
cv2.imshow('Contours', image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()圆形检测
python
import cv2
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 高斯模糊
blurred = cv2.GaussianBlur(gray, (9, 9), 2)
# Hough 圆形检测
circles = cv2.HoughCircles(
blurred,
cv2.HOUGH_GRADIENT,
dp=1,
minDist=20,
param1=50,
param2=30,
minRadius=10,
maxRadius=100
)
image_copy = image.copy()
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# 外圆
cv2.circle(image_copy, (i[0], i[1]), i[2], (0, 255, 0), 2)
# 中心
cv2.circle(image_copy, (i[0], i[1]), 2, (0, 0, 255), 3)
cv2.imshow('Circles', image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()直线检测
python
import cv2
import numpy as np
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)
# Hough 直线检测
lines = cv2.HoughLines(edges, 1, np.pi/180, 100)
image_copy = image.copy()
if lines is not None:
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * a)
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * a)
cv2.line(image_copy, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imshow('Lines', image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()实时视频处理
基本视频处理框架
python
import cv2
def process_video(video_path=None):
"""
处理视频文件或实时摄像头
参数:
video_path: 视频文件路径,None 表示使用摄像头
"""
# 打开视频源
if video_path is None:
cap = cv2.VideoCapture(0) # 使用默认摄像头
else:
cap = cv2.VideoCapture(video_path)
# 检查视频是否打开成功
if not cap.isOpened():
print("错误:无法打开视频源")
return
# 获取视频属性
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"视频信息:{width}x{height}, {fps} FPS")
# 定义视频编码器和创建视频写入器
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, fps, (width, height))
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
# 处理帧
processed = process_frame(frame)
# 显示帧
cv2.imshow('Video', processed)
# 写入输出视频
out.write(processed)
frame_count += 1
if frame_count % 30 == 0:
print(f"处理了 {frame_count} 帧")
# 按 'q' 退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()
print(f"处理完成,总共 {frame_count} 帧")
def process_frame(frame):
"""处理单个帧"""
# 应用各种处理
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 100, 200)
# 转换回 BGR 用于显示
processed = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
# 添加文本
cv2.putText(
processed,
f"Frame: {processed.shape}",
(10, 30),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 255, 0),
2
)
return processed
# 使用示例
process_video() # 摄像头
# process_video('video.mp4') # 视频文件在 LeBot 中的应用
障碍物检测
python
import cv2
import numpy as np
class ObstacleDetector:
"""障碍物检测器"""
def __init__(self):
self.lower_obstacle = np.array([0, 0, 0])
self.upper_obstacle = np.array([180, 255, 100])
def detect_obstacles(self, frame):
"""检测障碍物"""
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 创建掩码
mask = cv2.inRange(hsv, self.lower_obstacle, self.upper_obstacle)
# 形态学操作
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 检测轮廓
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
obstacles = []
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 500: # 最小面积阈值
x, y, w, h = cv2.boundingRect(cnt)
obstacles.append((x, y, w, h))
return obstacles, mask
# 使用示例
detector = ObstacleDetector()
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
obstacles, mask = detector.detect_obstacles(frame)
# 绘制检测到的障碍物
for x, y, w, h in obstacles:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
cv2.imshow('Obstacle Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()性能优化
多线程处理
python
import cv2
import threading
from queue import Queue
class VideoProcessor:
"""多线程视频处理器"""
def __init__(self):
self.frame_queue = Queue(maxsize=10)
self.result_queue = Queue(maxsize=10)
def capture_frames(self):
"""捕获帧的线程"""
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
if not self.frame_queue.full():
self.frame_queue.put(frame)
cap.release()
def process_frames(self):
"""处理帧的线程"""
while True:
if not self.frame_queue.empty():
frame = self.frame_queue.get()
# 处理帧
processed = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
processed = cv2.GaussianBlur(processed, (5, 5), 0)
if not self.result_queue.full():
self.result_queue.put(processed)
def display_results(self):
"""显示结果的线程"""
while True:
if not self.result_queue.empty():
frame = self.result_queue.get()
cv2.imshow('Result', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 使用示例
processor = VideoProcessor()
capture_thread = threading.Thread(target=processor.capture_frames, daemon=True)
process_thread = threading.Thread(target=processor.process_frames, daemon=True)
display_thread = threading.Thread(target=processor.display_results)
capture_thread.start()
process_thread.start()
display_thread.start()
display_thread.join()总结
OpenCV 在 LeBot 中的关键应用:
- 图像采集和显示:处理摄像头输入
- 图像处理:增强、过滤、变换
- 特征检测:识别重要特征
- 物体检测:发现和跟踪对象
- 视觉导航:基于视觉的路径规划
- 实时处理:低延迟的视觉反馈
正确使用 OpenCV 对于 LeBot 的视觉系统至关重要。
参考资源
- OpenCV 官方文档:https://docs.opencv.org/
- OpenCV Python 教程:https://docs.opencv.org/master/d6/d00/tutorial_py_root.html
- GitHub 仓库:https://github.com/opencv/opencv