OpenCV 计算机视觉库入门

1. OpenCV 简介

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,由英特尔公司发起并维护。它提供了丰富的图像处理和计算机视觉算法,被广泛应用于工业、研究和教育领域。

1.1 OpenCV 的主要特点

  • 跨平台支持:可在Windows、Linux、macOS等多种操作系统上运行
  • 丰富的算法:包含2500+种优化的算法,涵盖图像处理、目标检测、人脸识别等多个领域
  • 高性能实现:核心模块采用C++实现,保证了处理速度
  • 广泛的应用:被用于工业检测、医疗影像、安防监控、自动驾驶等多个领域
  • 活跃的社区:持续更新和改进,拥有庞大的用户社区

1.2 OpenCV 的应用场景

  • 图像处理:图像滤波、边缘检测、形态学操作等
  • 目标检测:物体识别、人脸检测、行人检测等
  • 视频分析:视频跟踪、动作识别、视频分割等
  • 计算机视觉:立体视觉、3D重建、视觉SLAM等
  • 机器学习:支持与机器学习库的集成,用于图像分类、目标识别等

2. 安装 OpenCV

2.1 环境要求

  • Python 3.6 或更高版本
  • 足够的磁盘空间
  • 可选:CUDA支持(用于GPU加速)

2.2 安装方法

2.2.1 使用 pip 安装

# 安装基本版本
pip install opencv-python

# 安装包含额外模块的版本
pip install opencv-contrib-python

2.2.2 从源码编译

对于需要自定义配置或最新版本的用户,可以从源码编译:

# 克隆仓库
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git

# 创建构建目录
mkdir build && cd build

# 配置
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..

# 编译
make -j4

# 安装
sudo make install

3. OpenCV 核心概念

3.1 图像表示

OpenCV 中图像以 NumPy 数组形式表示:

  • 灰度图像:二维数组,每个元素表示像素的灰度值(0-255)
  • 彩色图像:三维数组,通常使用 BGR 颜色空间(蓝、绿、红)

3.2 基本数据结构

  • Mat:OpenCV 的核心数据结构,用于存储图像和矩阵
  • Point:表示二维点坐标
  • Rect:表示矩形区域
  • Scalar:表示颜色值

3.3 坐标系统

OpenCV 使用笛卡尔坐标系统:

  • 原点 (0, 0) 位于图像的左上角
  • x 轴向右延伸
  • y 轴向下延伸

4. 基本操作

4.1 图像读取和显示

import cv2
import matplotlib.pyplot as plt

# 读取图像
img = cv2.imread('image.jpg')

# 显示图像
cv2.imshow('Image', img)
cv2.waitKey(0)  # 等待按键
cv2.destroyAllWindows()  # 关闭窗口

# 使用 matplotlib 显示(注意颜色空间转换)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.axis('off')
plt.show()

4.2 图像保存

# 保存图像
cv2.imwrite('output.jpg', img)

4.3 图像基本操作

# 调整图像大小
resized = cv2.resize(img, (width, height))

# 裁剪图像
cropped = img[y1:y2, x1:x2]

# 旋转图像
(h, w) = img.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(img, M, (w, h))

# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

5. 图像处理

5.1 图像滤波

# 高斯模糊
blurred = cv2.GaussianBlur(img, (5, 5), 0)

# 中值滤波
median = cv2.medianBlur(img, 5)

# 双边滤波
bilateral = cv2.bilateralFilter(img, 9, 75, 75)

5.2 边缘检测

# Canny 边缘检测
edges = cv2.Canny(gray, 100, 200)

# Sobel 边缘检测
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=5)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=5)
sobel = cv2.magnitude(sobelx, sobely)

5.3 形态学操作

import numpy as np

# 定义结构元素
kernel = np.ones((5, 5), np.uint8)

# 膨胀
dilation = cv2.dilate(img, kernel, iterations=1)

# 腐蚀
erosion = cv2.erode(img, kernel, iterations=1)

# 开运算(先腐蚀后膨胀)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

# 闭运算(先膨胀后腐蚀)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

5.4 阈值处理

# 全局阈值
ret, thresh1 = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 自适应阈值
thresh2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                               cv2.THRESH_BINARY, 11, 2)

# Otsu 阈值
ret, thresh3 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

6. 特征提取

6.1 角点检测

# Harris 角点检测
corners = cv2.cornerHarris(gray, 2, 3, 0.04)

# 标记角点
img[corners > 0.01 * corners.max()] = [0, 0, 255]

# Shi-Tomasi 角点检测
corners = cv2.goodFeaturesToTrack(gray, 25, 0.01, 10)
corners = np.int0(corners)

for i in corners:
    x, y = i.ravel()
    cv2.circle(img, (x, y), 3, 255, -1)

6.2 SIFT 特征

# 创建 SIFT 检测器
sift = cv2.SIFT_create()

# 检测关键点和描述符
keypoints, descriptors = sift.detectAndCompute(gray, None)

# 绘制关键点
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None)

6.3 SURF 特征

# 创建 SURF 检测器
surf = cv2.xfeatures2d.SURF_create(400)

# 检测关键点和描述符
keypoints, descriptors = surf.detectAndCompute(gray, None)

# 绘制关键点
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None)

6.4 ORB 特征

# 创建 ORB 检测器
orb = cv2.ORB_create()

# 检测关键点和描述符
keypoints, descriptors = orb.detectAndCompute(gray, None)

# 绘制关键点
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None)

7. 目标检测

7.1 人脸检测

# 加载 Haar 级联分类器
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# 检测人脸
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

# 绘制人脸边界框
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

7.2 眼睛检测

# 加载眼睛级联分类器
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')

# 检测眼睛
for (x, y, w, h) in faces:
    roi_gray = gray[y:y+h, x:x+w]
    roi_color = img[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex, ey, ew, eh) in eyes:
        cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)

7.3 目标跟踪

# 创建跟踪器
tracker = cv2.TrackerCSRT_create()

# 选择跟踪区域
bbox = cv2.selectROI('Tracking', img, False)
tracker.init(img, bbox)

# 打开视频
cap = cv2.VideoCapture('video.mp4')

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    # 更新跟踪
    success, bbox = tracker.update(frame)
    
    if success:
        # 绘制跟踪框
        x, y, w, h = int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
    
    cv2.imshow('Tracking', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

8. 视频处理

8.1 视频读取和显示

# 打开视频
cap = cv2.VideoCapture('video.mp4')

# 检查视频是否打开
if not cap.isOpened():
    print("无法打开视频")
    exit()

while True:
    # 读取帧
    ret, frame = cap.read()
    if not ret:
        break
    
    # 显示帧
    cv2.imshow('Video', frame)
    
    # 按 'q' 退出
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()

8.2 摄像头实时处理

# 打开摄像头
cap = cv2.VideoCapture(0)  # 0 表示默认摄像头

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    # 转换为灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    # 边缘检测
    edges = cv2.Canny(gray, 100, 200)
    
    # 显示结果
    cv2.imshow('Original', frame)
    cv2.imshow('Edges', edges)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

8.3 视频保存

# 打开视频
cap = cv2.VideoCapture('video.mp4')

# 获取视频属性
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))

# 创建视频编写器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, fps, (width, height))

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    # 处理帧
    # ...
    
    # 写入帧
    out.write(frame)
    
    cv2.imshow('Frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()

9. 实用技巧

9.1 性能优化

  • 使用适当的图像大小:根据任务需求调整图像大小
  • 使用 ROI:只处理感兴趣的区域
  • 使用适当的滤波器:根据噪声类型选择合适的滤波器
  • 使用 GPU 加速:在支持 CUDA 的环境中启用 GPU 加速
  • 批处理:批量处理图像以提高效率

9.2 颜色空间转换

# BGR 转 RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# BGR 转 HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# BGR 转灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

9.3 图像拼接

# 读取图像
img1 = cv2.imread('image1.jpg')
img2 = cv2.imread('image2.jpg')

# 创建 ORB 检测器
orb = cv2.ORB_create()

# 检测关键点和描述符
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

# 创建 BFMatcher
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# 匹配描述符
matches = matcher.match(des1, des2)

# 按距离排序
matches = sorted(matches, key=lambda x: x.distance)

# 提取匹配点
pts1 = np.float32([kp1[m.queryIdx].pt for m in matches])
pts2 = np.float32([kp2[m.trainIdx].pt for m in matches])

# 计算 Homography 矩阵
M, mask = cv2.findHomography(pts1, pts2, cv2.RANSAC, 5.0)

# 拼接图像
result = cv2.warpPerspective(img1, M, (img1.shape[1] + img2.shape[1], img1.shape[0]))
result[0:img2.shape[0], 0:img2.shape[1]] = img2

# 显示结果
cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

9.4 图像分割

# 使用 GrabCut 进行图像分割
img = cv2.imread('image.jpg')
mask = np.zeros(img.shape[:2], np.uint8)

# 定义背景和前景模型
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)

# 定义矩形区域(包含前景)
rect = (50, 50, 450, 290)

# 应用 GrabCut
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)

# 处理掩码
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img = img * mask2[:, :, np.newaxis]

# 显示结果
cv2.imshow('Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

10. 总结

OpenCV 是一个功能强大的计算机视觉库,它提供了丰富的图像处理和计算机视觉算法,使开发者能够快速实现各种计算机视觉任务。无论是基本的图像处理操作,还是复杂的目标检测和视频分析,OpenCV 都能提供可靠的支持。

通过本教程的学习,你应该已经掌握了 OpenCV 的核心概念和基本使用方法,可以开始使用 OpenCV 进行自己的计算机视觉项目开发。OpenCV 的跨平台性和高性能使其成为工业和研究领域的理想选择,而其丰富的功能和活跃的社区则使其能够不断发展和改进。

11. 进一步学习资源