Python OpenCV 完整指南:从入门到实践 – wiki大全

“`markdown

Python OpenCV 完整指南:从入门到实践

引言

计算机视觉是人工智能领域中一个快速发展的分支,它赋予机器“看”和“理解”世界的能力。而 OpenCV(Open Source Computer Vision Library)则是这个领域中最流行、功能最强大的开源库之一。本指南将带你从零开始,逐步掌握 Python OpenCV 的各项功能,最终能够应用于实际项目。

什么是 OpenCV?

OpenCV 是一个跨平台的计算机视觉库,最初由 Intel 开发,现在由 Willow Garage 维护。它包含了超过 2500 种优化过的算法,涵盖了计算机视觉和机器学习领域的诸多经典及前沿算法。这些算法可以用于图像处理、视频分析、特征检测、对象识别、机器学习模型部署等多种任务。

OpenCV 在计算机视觉中的应用

OpenCV 的应用范围极其广泛,包括但不限于:
* 图像增强与修复:降噪、去模糊、色彩校正。
* 目标检测与识别:人脸识别、物体跟踪、车牌识别。
* 图像分析:图像分割、纹理分析、形状识别。
* 机器人视觉:导航、避障、物体抓取。
* 医学图像分析:疾病诊断辅助。
* 安全监控:行为分析、异常检测。
* 自动驾驶:车道线识别、交通标志识别。

为什么选择 Python 和 OpenCV?

Python 以其简洁的语法和丰富的库生态系统,成为了数据科学和人工智能领域的首选语言。当 Python 与强大的 OpenCV 库结合时,开发者能够以极高的效率构建复杂的计算机视觉应用程序。
* 易学易用:Python 的语法简单直观,降低了学习曲线。
* 开发效率高:Python 脚本化特性使得快速原型开发成为可能。
* 丰富的生态系统:除了 OpenCV,还有 NumPy (用于数值计算)、Matplotlib (用于数据可视化)、Scikit-learn (用于机器学习) 等众多库可以与 OpenCV 无缝集成。
* 社区支持:拥有庞大活跃的开发者社区,遇到问题时容易找到解决方案和资源。

环境搭建

开始之前,我们需要搭建 Python 和 OpenCV 的开发环境。

1. 安装 Python

如果你的系统尚未安装 Python,请访问 Python 官方网站 下载并安装最新版本(推荐 Python 3.8+)。在安装过程中,务必勾选“Add Python to PATH”选项,以便在命令行中直接使用 Python。

2. 安装 OpenCV

Python 版的 OpenCV 通常通过 pip 包管理器进行安装。
打开你的命令行工具(Windows 用户可以使用 CMD 或 PowerShell,macOS/Linux 用户可以使用 Terminal),然后执行以下命令:

bash
pip install opencv-python

如果你需要额外的贡献模块(例如 SIFT/SURF 算法,尽管某些版本可能需要额外安装),可以安装 opencv-contrib-python

bash
pip install opencv-contrib-python

注意opencv-python 包含了 OpenCV 的主要模块,而 opencv-contrib-python 则包含了额外的非免费或非开源模块(如 SIFT, SURF,尽管新版本已将这些移入主包)。通常安装 opencv-python 就足够满足大部分需求。如果你遇到 SIFT/SURF 无法使用的问题,可以尝试安装 opencv-contrib-python

3. 其他常用库

在进行图像处理时,NumPyMatplotlib 是两个非常有用的辅助库。
* NumPy:是 Python 进行科学计算的基础库,OpenCV 图像在 Python 中被表示为 NumPy 数组。
* Matplotlib:是一个绘图库,常用于显示图像和绘制数据。

安装它们:

bash
pip install numpy matplotlib

至此,你的开发环境已经搭建完毕,可以开始计算机视觉之旅了!

入门:图像与视频基础操作

本节将介绍如何使用 OpenCV 读取、显示、保存图像和视频,以及进行一些基本的操作。

1. 读取、显示和保存图像

读取图像

使用 cv2.imread() 函数来读取图像。图像文件应与你的 Python 脚本位于同一目录,或提供完整路径。

“`python
import cv2

读取图像

cv2.imread(filepath, flag)

flag=1 (默认) 加载彩色图像

flag=0 加载灰度图像

flag=-1 加载包含 Alpha 通道的图像

img = cv2.imread(‘test.jpg’, 1)

检查图像是否成功加载

if img is None:
print(“错误:无法加载图像文件。请检查文件路径和名称。”)
else:
print(“图像加载成功!”)
“`

显示图像

使用 cv2.imshow() 函数在一个窗口中显示图像。cv2.waitKey() 函数等待按键事件,cv2.destroyAllWindows() 则关闭所有 OpenCV 窗口。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
cv2.imshow(‘My Image’, img) # ‘My Image’ 是窗口的名称
cv2.waitKey(0) # 等待任意按键,0 表示无限等待
cv2.destroyAllWindows() # 销毁所有窗口
``
**注意**:
cv2.waitKey(delay)中的delay参数表示等待的毫秒数。如果delay` 为 0,则表示无限期等待。

保存图像

使用 cv2.imwrite() 函数将图像保存到文件中。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
cv2.imwrite(‘new_image.png’, img) # 保存为 PNG 格式
print(“图像已保存为 new_image.png”)
``cv2.imwrite()` 会根据文件扩展名自动选择编码格式。

2. 图像的基本属性 (尺寸、类型)

图像在 OpenCV 中是 NumPy 数组。你可以像处理 NumPy 数组一样获取其属性。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
print(“图像尺寸 (高, 宽, 通道):”, img.shape) # 对于彩色图像 (height, width, channels)
print(“图像像素总数:”, img.size) # 像素总数
print(“图像数据类型:”, img.dtype) # 像素数据类型,通常是 uint8 (无符号8位整型)
``
对于灰度图像,
img.shape将只返回(height, width)`。

3. 图像的访问与修改 (像素操作)

你可以直接访问和修改图像的像素值。彩色图像的像素通常以 BGR 顺序存储。

“`python
import cv2
import numpy as np

img = cv2.imread(‘test.jpg’)

if img is not None:
# 获取图像的第一个像素 (左上角) 的 BGR 值
px = img[0, 0]
print(“左上角像素 BGR 值:”, px)

# 访问特定通道 (例如:蓝色通道)
blue = img[100, 100, 0]  # 访问 (100, 100) 坐标的蓝色通道值
print("(100, 100) 像素的蓝色值:", blue)

# 修改像素值 (例如:将左上角像素设为红色)
img[0, 0] = [0, 0, 255]  # B=0, G=0, R=255
print("修改后的左上角像素 BGR 值:", img[0, 0])

# 截取图像 ROI (Region of Interest)
# 例如,截取图像的 (100, 100) 到 (200, 200) 区域
roi = img[100:200, 100:200]
cv2.imshow('ROI', roi)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 将 ROI 区域复制到图像的另一个位置
img[0:100, 0:100] = roi
cv2.imshow('Image with ROI copied', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

4. 图像的缩放、旋转与翻转

缩放 (Resize)

使用 cv2.resize() 函数。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
# 按比例缩放
resized_img_half = cv2.resize(img, (0, 0), fx=0.5, fy=0.5) # fx, fy 是缩放因子
cv2.imshow(‘Resized Half’, resized_img_half)

# 缩放到指定尺寸 (宽, 高)
resized_img_fixed = cv2.resize(img, (300, 200)) # (width, height)
cv2.imshow('Resized Fixed', resized_img_fixed)

cv2.waitKey(0)
cv2.destroyAllWindows()

``
常用的插值方法有:
*
cv2.INTER_AREA:用于缩小图像,效果最好。
*
cv2.INTER_CUBIC:用于放大图像(默认)。
*
cv2.INTER_LINEAR`:用于放大图像(速度较快)。

旋转 (Rotate)

旋转需要一个旋转矩阵,可以通过 cv2.getRotationMatrix2D() 生成。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
rows, cols, _ = img.shape
# 获取旋转矩阵:参数 (旋转中心, 旋转角度, 缩放比例)
M = cv2.getRotationMatrix2D(((cols – 1) / 2.0, (rows – 1) / 2.0), 90, 1)
rotated_img = cv2.warpAffine(img, M, (cols, rows)) # warpAffine 进行仿射变换

cv2.imshow('Rotated 90 Degrees', rotated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

翻转 (Flip)

使用 cv2.flip() 函数。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
# 垂直翻转 (flipCode = 0)
flipped_vertical = cv2.flip(img, 0)
cv2.imshow(‘Flipped Vertical’, flipped_vertical)

# 水平翻转 (flipCode = 1)
flipped_horizontal = cv2.flip(img, 1)
cv2.imshow('Flipped Horizontal', flipped_horizontal)

# 水平垂直翻转 (flipCode = -1)
flipped_both = cv2.flip(img, -1)
cv2.imshow('Flipped Both', flipped_both)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

5. 绘制图形和文字

OpenCV 提供了多种函数用于在图像上绘制点、线、矩形、圆形和文字。

“`python
import cv2
import numpy as np

创建一个黑色空白图像 (高, 宽, 通道)

img = np.zeros((512, 512, 3), np.uint8)

绘制直线 (图像, 起点坐标, 终点坐标, 颜色(BGR), 线宽)

cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5) # 蓝色对角线

绘制矩形 (图像, 左上角坐标, 右下角坐标, 颜色(BGR), 线宽/是否填充)

线宽为 -1 表示填充矩形

cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3) # 绿色矩形边框
cv2.rectangle(img, (50, 50), (150, 150), (0, 0, 255), -1) # 红色填充矩形

绘制圆形 (图像, 圆心坐标, 半径, 颜色(BGR), 线宽/是否填充)

cv2.circle(img, (447, 63), 63, (0, 0, 255), -1) # 红色填充圆形

绘制椭圆 (图像, 中心坐标, (长轴, 短轴), 旋转角度, 起始角度, 结束角度, 颜色, 线宽)

cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, (255, 255, 0), -1) # 黄色半椭圆

添加文字 (图像, 文字内容, 左下角坐标, 字体, 字体缩放, 颜色, 线宽, 线型)

font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, ‘Hello OpenCV!’, (10, 500), font, 1, (255, 255, 255), 2, cv2.LINE_AA)

cv2.imshow(‘Drawing’, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

6. 处理视频 (读取、显示、保存)

读取和显示视频

使用 cv2.VideoCapture() 对象来读取视频文件或摄像头。

“`python
import cv2

创建 VideoCapture 对象

参数 0 表示默认摄像头,也可以是视频文件路径

cap = cv2.VideoCapture(0)

检查摄像头是否成功打开

if not cap.isOpened():
print(“错误:无法打开摄像头或视频文件。”)
else:
while True:
ret, frame = cap.read() # ret 为布尔值,表示是否成功读取帧;frame 为读取到的帧

    if not ret:
        print("无法接收帧 (流结束?)。退出...")
        break

    # 对每一帧进行操作,例如转换为灰度
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    cv2.imshow('Frame', frame)        # 显示原始彩色帧
    cv2.imshow('Gray Frame', gray_frame) # 显示灰度帧

    # 按 'q' 键退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

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

“`

保存视频

保存视频需要 cv2.VideoWriter() 对象,并指定编码器、帧率和帧尺寸。

“`python
import cv2

cap = cv2.VideoCapture(0)

if not cap.isOpened():
print(“错误:无法打开摄像头。”)
else:
# 获取视频的宽度、高度和帧率
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

# 定义编解码器并创建 VideoWriter 对象
# 例如,使用 XVID 编解码器,扩展名为 .avi
fourcc = cv2.VideoWriter_fourcc(*'XVID') # 可选值:'MJPG', 'XVID', 'DIVX', 'mp4v'
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (frame_width, frame_height))

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # 写入帧到文件
    out.write(frame)

    cv2.imshow('Recording', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release() # 释放 VideoWriter
cv2.destroyAllWindows()
print("视频已保存为 output.avi")

``
**注意**:
fourcc编码器可能在不同操作系统上有所不同。‘XVID’` 通常比较通用。

图像处理核心技术

OpenCV 提供了大量的图像处理功能,本节将介绍一些最常用和最重要的技术。

1. 色彩空间转换 (Color Space Conversion)

除了我们常见的 RGB(红绿蓝)色彩空间,还有许多其他色彩空间,例如灰度(Grayscale)、HSV(色相、饱和度、亮度)等。转换色彩空间在许多图像处理任务中都非常有用。

BGR 到灰度

灰度图像只有一个通道,每个像素的值代表其亮度。这可以大大简化图像处理的复杂性。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

cv2.imshow('Original Image', img)
cv2.imshow('Grayscale Image', gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

BGR 到 HSV

HSV 色彩空间在颜色描述上更直观,色相(Hue)代表颜色本身,饱和度(Saturation)代表颜色的纯度,亮度(Value)代表颜色的明暗。这对于基于颜色的对象检测非常有用。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

cv2.imshow('Original Image', img)
cv2.imshow('HSV Image', hsv_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

2. 图像阈值处理 (Image Thresholding)

阈值处理是一种将灰度图像转换为二值图像(只有黑白两种颜色)的方法。通过设定一个阈值,像素值高于阈值的设为白色,低于阈值的设为黑色(或反之)。

简单阈值 (Simple Thresholding)

“`python
import cv2

img = cv2.imread(‘test.jpg’, 0) # 读取灰度图像

if img is not None:
# cv2.threshold(src, thresh, maxval, type)
# src: 输入图像 (灰度图)
# thresh: 阈值
# maxval: 超过阈值后设定的最大值
# type: 阈值类型
# ret 是实际使用的阈值,thresh1 是二值图像

# THRESH_BINARY: 大于阈值设为 maxval,否则为 0
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
cv2.imshow('Binary', thresh1)

# THRESH_BINARY_INV: 大于阈值设为 0,否则为 maxval (反转)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
cv2.imshow('Binary Inverse', thresh2)

# THRESH_TRUNC: 大于阈值设为阈值,否则不变
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
cv2.imshow('Trunc', thresh3)

# THRESH_TOZERO: 大于阈值不变,否则设为 0
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
cv2.imshow('To Zero', thresh4)

# THRESH_TOZERO_INV: 大于阈值设为 0,否则不变
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
cv2.imshow('To Zero Inverse', thresh5)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

自适应阈值 (Adaptive Thresholding)

当图像在不同区域具有不同的光照条件时,简单阈值可能效果不佳。自适应阈值根据图像局部区域的像素值来计算阈值。

“`python
import cv2

img = cv2.imread(‘test.jpg’, 0)

if img is not None:
# cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
# adaptiveMethod: 自适应阈值计算方法 (ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C)
# blockSize: 邻域大小 (必须是奇数)
# C: 从均值或高斯加权平均值中减去的常数

thresh_mean = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('Adaptive Mean Threshold', thresh_mean)

thresh_gaussian = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('Adaptive Gaussian Threshold', thresh_gaussian)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

Otsu 阈值 (Otsu’s Binarization)

Otsu 阈值是一种自动计算最佳阈值的方法,适用于具有双峰直方图的图像。

“`python
import cv2

img = cv2.imread(‘test.jpg’, 0)

if img is not None:
# Otsu 阈值通常与 THRESH_BINARY 或 THRESH_BINARY_INV 结合使用
ret, otsu_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print(“Otsu 自动计算的阈值:”, ret)
cv2.imshow(‘Otsu Threshold’, otsu_thresh)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

3. 图像平滑与模糊 (Image Smoothing and Blurring)

图像平滑(模糊)是一种常用的图像预处理技术,用于去除噪声、减少图像细节。

均值滤波 (Averaging)

使用图像周围像素的平均值来替换中心像素。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
# cv2.blur(src, ksize)
# ksize: 内核大小 (例如 (5, 5))
blurred_img = cv2.blur(img, (5, 5))

cv2.imshow('Original', img)
cv2.imshow('Blurred (Averaging)', blurred_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

高斯滤波 (Gaussian Blurring)

使用高斯核进行卷积操作,对离中心像素越近的像素赋予更大的权重。在去除高斯噪声方面表现良好。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
# cv2.GaussianBlur(src, ksize, sigmaX)
# sigmaX: X 方向的标准差,为 0 时根据 ksize 自动计算
gaussian_blurred_img = cv2.GaussianBlur(img, (5, 5), 0)

cv2.imshow('Original', img)
cv2.imshow('Blurred (Gaussian)', gaussian_blurred_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

中值滤波 (Median Blurring)

使用图像周围像素的中值来替换中心像素。在去除椒盐噪声(Salt-and-Pepper Noise)方面效果显著。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
# cv2.medianBlur(src, ksize)
# ksize: 卷积核大小 (必须是大于 1 的奇数)
median_blurred_img = cv2.medianBlur(img, 5)

cv2.imshow('Original', img)
cv2.imshow('Blurred (Median)', median_blurred_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

4. 边缘检测 (Edge Detection)

边缘检测是图像处理中一项基本而重要的任务,用于识别图像中亮度变化剧烈的区域,通常对应着物体的边界。

Sobel 和 Scharr 算子

Sobel 算子是一种常用的边缘检测算子,可以计算图像在 X 和 Y 方向上的梯度近似。Scharr 算子是 Sobel 算子的改进版本,能提供更精确的边缘检测。

“`python
import cv2
import numpy as np

img = cv2.imread(‘test.jpg’, 0) # 读取灰度图像

if img is not None:
# 计算 X 方向梯度
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5) # cv2.CV_64F 确保负值不会被截断
# 计算 Y 方向梯度
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)

# 计算梯度幅值
sobel_combined = cv2.magnitude(sobelx, sobely)

cv2.imshow('Original', img)
cv2.imshow('Sobel X', np.uint8(np.absolute(sobelx))) # 取绝对值并转换为 uint8
cv2.imshow('Sobel Y', np.uint8(np.absolute(sobely)))
cv2.imshow('Sobel Combined', np.uint8(sobel_combined))
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

Laplacian 算子

Laplacian 算子是一种二阶导数算子,可以检测图像中的孤立点、线和边缘。

“`python
import cv2
import numpy as np

img = cv2.imread(‘test.jpg’, 0) # 读取灰度图像

if img is not None:
laplacian = cv2.Laplacian(img, cv2.CV_64F)
laplacian_8bit = np.uint8(np.absolute(laplacian))

cv2.imshow('Original', img)
cv2.imshow('Laplacian', laplacian_8bit)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

Canny 边缘检测

Canny 边缘检测是一种多级算法,被广泛认为是边缘检测的“黄金标准”。它能够检测出宽范围的图像边缘。

“`python
import cv2

img = cv2.imread(‘test.jpg’, 0) # 读取灰度图像

if img is not None:
# cv2.Canny(image, threshold1, threshold2)
# threshold1 和 threshold2 是滞后阈值,用于边缘连接
edges = cv2.Canny(img, 100, 200) # 较低的阈值用于边缘连接,较高的阈值用于检测强边缘

cv2.imshow('Original', img)
cv2.imshow('Canny Edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

“`

5. 形态学操作 (Morphological Operations)

形态学操作是基于图像形状进行处理的技术,主要用于二值图像。它们通过结构元素(kernel)与图像进行卷积来修改图像。

腐蚀与膨胀 (Erosion and Dilation)

  • 腐蚀 (Erosion):使图像中的前景物体(白色区域)缩小,通常用于去除小块噪声。
  • 膨胀 (Dilation):使图像中的前景物体(白色区域)增大,可以连接断开的物体。

“`python
import cv2
import numpy as np

img = cv2.imread(‘test.jpg’, 0)

if img is not None:
# 创建 5×5 的矩形结构元素 (kernel)
kernel = np.ones((5, 5), np.uint8)

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

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

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

开运算与闭运算 (Opening and Closing)

  • 开运算 (Opening):先腐蚀后膨胀。常用于去除图像中的小白点噪声(独立的小块白色区域),同时保持物体形状不变。
  • 闭运算 (Closing):先膨胀后腐蚀。常用于填充物体内部的小空洞,或连接断开的物体。

“`python
import cv2
import numpy as np

img = cv2.imread(‘test.jpg’, 0)

if img is not None:
kernel = np.ones((5, 5), np.uint8)

# 开运算
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow('Opening', opening)

# 闭运算
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Closing', closing)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

梯度、顶帽、黑帽 (Gradient, Top Hat, Black Hat)

  • 形态学梯度 (Morphological Gradient):膨胀图像减去腐蚀图像,得到物体的边缘。
  • 顶帽 (Top Hat):原始图像减去开运算结果,用于提取图像中的小亮点。
  • 黑帽 (Black Hat):闭运算结果减去原始图像,用于提取图像中的小黑点。

“`python
import cv2
import numpy as np

img = cv2.imread(‘test.jpg’, 0)

if img is not None:
kernel = np.ones((5, 5), np.uint8)

# 形态学梯度
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('Gradient', gradient)

# 顶帽
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('Top Hat', tophat)

# 黑帽
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('Black Hat', blackhat)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

6. 图像金字塔 (Image Pyramids)

图像金字塔是一系列图像的集合,所有图像都源于同一张原始图像,但具有不同的分辨率。它们在对象尺寸不确定或需要分析不同尺度信息时非常有用(例如,特征匹配、对象检测)。

  • 高斯金字塔 (Gaussian Pyramid):用于向下采样(缩小图像)。
  • 拉普拉斯金字塔 (Laplacian Pyramid):可以从高斯金字塔中重建原始图像。

“`python
import cv2

img = cv2.imread(‘test.jpg’)

if img is not None:
# 向下采样 (缩小)
lower_res = cv2.pyrDown(img)
cv2.imshow(‘Lower Resolution’, lower_res)

# 向上采样 (放大)
higher_res = cv2.pyrUp(lower_res) # 注意:无法完全恢复原始图像,会有信息损失
cv2.imshow('Higher Resolution', higher_res)

cv2.waitKey(0)
cv2.destroyAllWindows()

“`

7. 图像梯度 (Image Gradients)

图像梯度表示图像强度变化的速率和方向,常用于边缘检测。我们已经在 Sobel 和 Scharr 算子中接触了梯度计算。

目标检测与识别

目标检测是计算机视觉的核心任务之一,旨在识别图像或视频中特定对象的位置和类别。

1. 轮廓检测 (Contour Detection)

轮廓是连接所有连续点(沿着边界)的曲线,具有相同的颜色或强度。轮廓在形状分析、对象检测和识别中非常有用。

查找轮廓

cv2.findContours() 函数用于查找图像中的轮廓。通常需要对图像进行二值化处理(如阈值处理或 Canny 边缘检测)才能得到良好的轮廓。

“`python
import cv2

img = cv2.imread(‘shape.png’) # 假设 ‘shape.png’ 是一个带有白色形状的黑色背景图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV) # 反转以使形状为白色

cv2.findContours(image, mode, method)

mode: 轮廓检索模式 (例如 cv2.RETR_EXTERNAL 只检索最外层轮廓)

method: 轮廓近似方法 (例如 cv2.CHAIN_APPROX_SIMPLE 压缩水平、垂直和对角线段,只保留端点)

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

print(f”找到 {len(contours)} 个轮廓”)

绘制轮廓到一个空白图像上

output_img = img.copy()
cv2.drawContours(output_img, contours, -1, (0, 255, 0), 3) # -1 表示绘制所有轮廓,绿色,线宽 3

cv2.imshow(‘Original’, img)
cv2.imshow(‘Threshold’, thresh)
cv2.imshow(‘Contours’, output_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

轮廓属性、近似与外接矩形

你可以通过轮廓获取形状的面积、周长、中心点等属性,还可以对轮廓进行近似,或绘制其外接矩形、最小外接圆等。

“`python
import cv2

img = cv2.imread(‘shape.png’)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

output_img = img.copy()

for cnt in contours:
# 轮廓面积
area = cv2.contourArea(cnt)
print(f”轮廓面积: {area}”)

# 轮廓周长 (True 表示闭合轮廓)
perimeter = cv2.arcLength(cnt, True)
print(f"轮廓周长: {perimeter}")

# 轮廓近似 (epsilon 是原始轮廓到近似轮廓的最大距离)
epsilon = 0.02 * perimeter
approx = cv2.approxPolyDP(cnt, epsilon, True)
cv2.drawContours(output_img, [approx], -1, (0, 0, 255), 2) # 绘制近似轮廓 (红色)

# 外接矩形 (不考虑旋转)
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(output_img, (x, y), (x + w, y + h), (255, 0, 0), 2) # 蓝色矩形

# 最小外接圆
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
cv2.circle(output_img, center, radius, (0, 255, 255), 2) # 黄色圆形

# 轮廓的中心矩
M = cv2.moments(cnt)
if M['m00'] != 0:
    cx = int(M['m10'] / M['m00'])
    cy = int(M['m01'] / M['m00'])
    cv2.circle(output_img, (cx, cy), 5, (0, 255, 0), -1) # 绿色中心点

cv2.imshow(‘Contour Properties’, output_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

2. 模板匹配 (Template Matching)

模板匹配是在一张大图像中查找与给定模板图像相匹配的区域。

“`python
import cv2
import numpy as np

img = cv2.imread(‘full_image.jpg’, 0) # 原始图像
template = cv2.imread(‘template.jpg’, 0) # 模板图像

if img is not None and template is not None:
w, h = template.shape[::-1] # 模板的宽度和高度

# 进行模板匹配
# cv2.matchTemplate(image, templ, method)
# method: 匹配方法 (例如 cv2.TM_CCOEFF_NORMED)
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# 查找最佳匹配位置 (使用 minMaxLoc 找到最大值或最小值的位置)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# 根据匹配方法,可能需要取 min_loc 或 max_loc
# 对于 TM_CCOEFF_NORMED, TM_CCORR_NORMED, TM_SQDIFF_NORMED,最大值表示最佳匹配
# 对于 TM_SQDIFF,最小值表示最佳匹配
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)

# 在原始图像上绘制矩形
cv2.rectangle(img, top_left, bottom_right, (0, 0, 255), 2) # 红色矩形

cv2.imshow('Detected', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“错误:无法加载图像或模板。”)
“`

3. Haar 级联分类器 (Haar Cascade Classifiers)

Haar 级联分类器是一种基于机器学习的物体检测方法,主要用于实时人脸检测。OpenCV 提供了预训练的 Haar 级联分类器模型。

“`python
import cv2

加载预训练的 Haar 级联人脸检测器

face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + ‘haarcascade_fronta lface_default.xml’)

加载预训练的 Haar 级联眼睛检测器

eye_cascade = cv2.CascadeClassifier(cv2.data.haascades + ‘haarcascade_eye.xml’)

if face_cascade.empty() or eye_cascade.empty():
print(“错误:无法加载 Haar 级联文件。请检查路径。”)
else:
img = cv2.imread(‘people.jpg’) # 假设 ‘people.jpg’ 是一张包含人脸的图片

if img is not None:
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 进行人脸检测
    # detectMultiScale(image, scaleFactor, minNeighbors)
    # scaleFactor: 每次图像缩小的比例
    # minNeighbors: 每个矩形应该保留的邻近数量,以减少假阳性
    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) # 蓝色矩形框住人脸
        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) # 绿色矩形框住眼睛

    cv2.imshow('Face and Eye Detection', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print("错误:无法加载图像文件。")

``
**注意**:
haarcascade_frontalface_default.xmlhaarcascade_eye.xml这些 XML 文件通常位于 OpenCV 安装目录的data/haarcascades文件夹中。为了方便,OpenCV 提供了cv2.data.haarcascades` 来获取这些文件的路径。

实践项目示例

理论知识学习完毕后,通过实践项目来巩固和提升技能至关重要。

1. 实时摄像头人脸识别

结合前面学到的视频处理和 Haar 级联分类器,我们可以实现一个实时摄像头人脸识别应用。

“`python
import cv2

face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + ‘haarcascade_frontalface_default.xml’)
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + ‘haarcascade_eye.xml’)

cap = cv2.VideoCapture(0)

if not cap.isOpened():
print(“错误:无法打开摄像头。”)
else:
while True:
ret, frame = cap.read()
if not ret:
break

    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)
        roi_gray = gray[y:y + h, x:x + w]
        roi_color = frame[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)

    cv2.imshow('Live Face Detection', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

“`

2. 图像拼接 (Image Stitching)

图像拼接是将多张具有重叠区域的图像组合成一张更大、视野更广的图像的技术。OpenCV 提供了 Stitcher 类来实现这一功能。

“`python
import cv2

创建 Stitcher 对象

stitcher = cv2.Stitcher.create() # Python 3.x

stitcher = cv2.createStitcher(False) # Python 2.x

加载多张图片

img1 = cv2.imread(‘left_image.jpg’)

img2 = cv2.imread(‘right_image.jpg’)

images = [img1, img2] # 假设你有两张图片

status, stitched_image = stitcher.stitch(images)

if status == cv2.Stitcher_OK:

cv2.imshow(‘Stitched Image’, stitched_image)

cv2.waitKey(0)

cv2.destroyAllWindows()

else:

print(“图像拼接失败:”, status)

实际应用中,你需要准备多张有重叠区域的图片

print(“图像拼接需要多张有重叠区域的图片,请自行准备并取消代码注释以运行。”)
“`
注意:图像拼接相对复杂,需要多张图片有足够重叠区域且特征点丰富。

3. 条形码/二维码识别

OpenCV 本身不直接提供条形码/二维码解码功能,但可以与其他库结合使用,例如 pyzbar

“`python

安装 pyzbar: pip install pyzbar

import cv2
from pyzbar.pyzbar import decode

img = cv2.imread(‘barcode_qr.png’) # 假设 ‘barcode_qr.png’ 包含条形码或二维码

if img is not None:
# 解码图像中的所有条形码和二维码
decoded_objects = decode(img)

for obj in decoded_objects:
    print("数据:", obj.data.decode('utf-8'))
    print("类型:", obj.type)

    # 绘制检测到的区域
    points = obj.polygon
    if len(points) > 4: # 如果是二维码,可能不止四个点
        hull = cv2.convexHull(points)
        cv2.polylines(img, [hull], True, (0, 255, 0), 2)
    else:
        x, y, w, h = obj.rect
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 在图像上显示解码数据
    cv2.putText(img, obj.data.decode('utf-8'), (obj.rect.left, obj.rect.top - 10),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

cv2.imshow('Barcode/QR Code Detection', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“错误:无法加载图像文件。”)
“`

4. 车道线检测 (Lane Detection)

车道线检测是自动驾驶中的一个重要任务。其基本思路通常包括灰度化、高斯模糊、Canny 边缘检测、ROI(Region of Interest)选择、霍夫变换(Hough Transform)来检测直线,并最终绘制车道线。

“`python
import cv2
import numpy as np

def draw_lines(img, lines, color=(0, 255, 255), thickness=3):
# 绘制检测到的线条
if lines is None:
return
img = np.copy(img)
line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
for line in lines:
for x1, y1, x2, y2 in line:
cv2.line(line_img, (x1, y1), (x2, y2), color, thickness)
img = cv2.addWeighted(img, 0.8, line_img, 1.0, 0.0)
return img

def process_image_for_lanes(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
canny = cv2.Canny(blur, 50, 150)

# 定义感兴趣区域 (ROI)
height = image.shape[0]
width = image.shape[1]
roi_vertices = [
    (0, height),
    (width / 2, height / 2 + 50), # 可以根据实际情况调整
    (width, height)
]
mask = np.zeros_like(canny)
cv2.fillPoly(mask, np.array([roi_vertices], np.int32), 255)
masked_edges = cv2.bitwise_and(canny, mask)

# 霍夫变换检测直线
# cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap)
lines = cv2.HoughLinesP(masked_edges, rho=1, theta=np.pi / 180, threshold=20,
                        minLineLength=20, maxLineGap=10)

# 绘制车道线 (这里简化处理,实际需要更复杂的车道线拟合逻辑)
line_image = draw_lines(image, lines)
return line_image

# 加载图像或视频帧进行测试

img = cv2.imread(‘road_image.jpg’) # 假设 ‘road_image.jpg’ 是一张道路图片

if img is not None:

lane_detected_image = process_image_for_lanes(img)

cv2.imshow(‘Lane Detection’, lane_detected_image)

cv2.waitKey(0)

cv2.destroyAllWindows()

else:

print(“错误:无法加载道路图像。”)

print(“车道线检测需要一张道路图片进行测试,请自行准备并取消代码注释以运行。”)
print(“注意:车道线检测的参数和 ROI 区域需要根据具体图像进行调优。”)
“`
注意:车道线检测是一个更复杂的任务,上述代码仅为简化示例。实际应用中需要更 robust 的直线拟合、左右车道线分离、以及视频流处理等逻辑。

进阶主题与展望

1. 深度学习与 OpenCV (DNN 模块)

OpenCV 3.3 及更高版本引入了 DNN(Deep Neural Network)模块,允许加载和运行各种预训练的深度学习模型,例如用于图像分类、目标检测(如 YOLO、SSD)、图像分割等。这使得 OpenCV 可以直接与深度学习框架(如 TensorFlow, Caffe, PyTorch (通过 ONNX))集成。

“`python

示例代码(仅作演示,需要下载模型文件)

import cv2

# 加载预训练的 Caffe 模型 (例如:MobileNet SSD 目标检测模型)

net = cv2.dnn.readNetFromCaffe(‘deploy.prototxt’, ‘weights.caffemodel’)

# 设置模型输入

blob = cv2.dnn.blobFromImage(image, 1.0/255, (300, 300), (0, 0, 0), swapRB=True, crop=False)

net.setInput(blob)

# 进行前向传播

detections = net.forward()

# 解析检测结果并绘制边界框

# … (此处省略具体解析代码,因模型输出格式各异)

cv2.imshow(‘DNN Detection’, image)

cv2.waitKey(0)

cv2.destroyAllWindows()

print(“OpenCV 的 DNN 模块可以集成深度学习模型,但需要下载模型文件,代码仅为演示。”)
“`

2. 性能优化

对于实时计算机视觉应用,性能至关重要。OpenCV 提供了多种优化方法:
* 使用 cv2.setUseOptimized(True):开启 OpenCV 内部的优化功能(如 SSE2/AVX 指令集)。
* 使用 NumPy 数组操作:避免 Python 循环,尽可能使用 NumPy 的矢量化操作。
* 适当的图像尺寸:处理较小的图像可以显著提高速度。
* 多线程/多进程:对于计算密集型任务,可以考虑使用多线程或多进程。
* GPU 加速:OpenCV 提供了 CUDA 模块(cv2.cuda),允许在支持 CUDA 的 GPU 上运行某些函数,从而获得巨大的性能提升。

3. OpenCV 的未来

OpenCV 社区持续活跃,不断推出新功能和改进。未来的发展趋势可能包括:
* 更紧密地与深度学习框架集成。
* 更高效的跨平台性能优化。
* 支持更多先进的计算机视觉算法。
* 在边缘设备和嵌入式系统上的应用扩展。

总结

本指南带你全面了解了 Python OpenCV 的从入门到实践。从环境搭建到图像与视频的基础操作,再到色彩空间转换、阈值处理、平滑模糊、边缘检测、形态学操作等核心技术,以及轮廓检测、模板匹配、Haar 级联分类器等目标检测方法,最后还展望了深度学习与 OpenCV 的结合。

通过学习本指南,你已经掌握了使用 OpenCV 处理图像和视频的基本技能,并具备了构建简单计算机视觉应用的能力。计算机视觉是一个充满挑战和机遇的领域,鼓励你继续深入学习,探索更多高级算法和实际应用,不断提升你的技能!

希望这篇指南能帮助你开启精彩的 OpenCV 学习之旅!

I have generated the article about “Python OpenCV 完整指南:从入门到实践”. It covers:

  1. Introduction: What is OpenCV, its applications, and why Python + OpenCV is a good choice.
  2. Environment Setup: How to install Python, OpenCV, NumPy, and Matplotlib.
  3. Basic Image and Video Operations: Reading, displaying, saving images; image properties; pixel manipulation; resizing, rotating, flipping; drawing shapes and text; and basic video handling.
  4. Core Image Processing Techniques: Color space conversion (BGR to Grayscale, HSV), image thresholding (simple, adaptive, Otsu), image smoothing (averaging, Gaussian, median), edge detection (Sobel, Scharr, Laplacian, Canny), morphological operations (erosion, dilation, opening, closing, gradient, top hat, black hat), and image pyramids.
  5. Object Detection and Recognition: Contour detection (finding, drawing, properties), template matching, and Haar Cascade classifiers for face and eye detection.
  6. Practical Project Examples: Real-time camera face detection, image stitching (conceptual), barcode/QR code recognition (with pyzbar), and lane detection (conceptual).
  7. Advanced Topics and Outlook: DNN module integration with deep learning, performance optimization, and the future of OpenCV.
  8. Conclusion: A summary of the guide.

I’ve included code examples for most concepts to make it practical.The article “Python OpenCV 完整指南:从入门到实践” has been generated as requested. It covers a comprehensive range of topics from basic setup and operations to advanced image processing and object detection techniques, including practical examples and an outlook on future trends.

滚动至顶部