从零开始学习 Python OpenCV – wiki基地


视觉之旅的起点:从零开始学习 Python OpenCV

计算机视觉,一个令人着迷的领域,它赋予了机器“看”的能力,理解和解释图像与视频中的信息。从自动驾驶到人脸识别,从医疗影像分析到工业自动化,计算机视觉的应用无处不在,深刻地改变着我们的世界。而 OpenCV (Open Source Computer Vision Library),作为目前最受欢迎的计算机视觉库之一,无疑是进入这个奇妙世界的一扇大门。

如果你是一个编程新手,或者已经熟悉 Python 但从未接触过图像处理,并渴望学习计算机视觉,那么恭喜你,这篇“从零开始学习 Python OpenCV”的指南正是为你准备的。我们将一步步揭开 OpenCV 的神秘面纱,用 Python 语言的简洁和易用性,带你踏上视觉之旅。

第一站:认识 OpenCV 与 Python 的结合

什么是 OpenCV?

OpenCV 是一个跨平台的计算机视觉库,由英特尔公司发起并持续发展。它包含了数百个计算机视觉算法,涵盖了图像处理、特征检测、目标识别、三维重建、机器学习等方面。最初主要用 C++ 开发,但随着时间的推移,它提供了包括 Python、Java 等多种语言的接口。

为什么选择 Python 与 OpenCV?

Python 语言以其简洁优雅的语法、丰富的库生态系统和强大的胶水能力而闻名。将 OpenCV 与 Python 结合,可以:

  1. 快速原型开发: Python 的交互式特性和动态类型,使得编写、测试和修改计算机视觉代码变得异常高效。
  2. 易于学习和使用: 相比 C++ 接口,Python 接口更加直观易懂,降低了学习门槛。
  3. 丰富的生态系统: 可以轻松与其他强大的 Python 库集成,如 NumPy (处理多维数组,OpenCV 图像的基础)、Matplotlib (数据可视化)、Scikit-learn (机器学习)、TensorFlow/PyTorch (深度学习) 等。
  4. 强大的社区支持: Python 和 OpenCV 都拥有庞大的用户社区,遇到问题很容易找到解决方案和学习资源。

因此,Python + OpenCV 是学习计算机视觉、进行科研和快速开发项目的绝佳组合。

第二站:环境搭建——迈出第一步

“工欲善其事,必先利其器。” 在开始编写 OpenCV 代码之前,你需要搭建必要的开发环境。

1. 安装 Python

首先,确保你的计算机上安装了 Python。建议安装 Python 3.6 或更高版本。你可以从 Python 官方网站 (python.org) 下载适合你操作系统的安装包。

安装时,请勾选“Add Python to PATH”(将 Python 添加到系统环境变量),这样可以在命令行中直接运行 Python 和 pip。

2. 安装 OpenCV Python 库

Python 的包管理器 pip 使得安装第三方库变得非常简单。打开你的终端或命令提示符,输入以下命令:

bash
pip install opencv-python

这个命令会下载并安装最新版本的 OpenCV Python 库。opencv-python 是官方提供的面向普通用户的版本,它包含了核心模块和常用的扩展模块。如果你需要更完整的功能(例如一些非自由或额外的算法),可以考虑安装 opencv-contrib-python

bash
pip install opencv-contrib-python

对于初学者来说,opencv-python 通常就足够了。

3. 推荐使用虚拟环境 (Optional but Recommended)

为了避免不同项目之间的库版本冲突,强烈建议使用虚拟环境。

  • 使用 venv (Python 3.3+):

    • 创建虚拟环境:python -m venv myenv (myenv 是你想创建的环境名称)
    • 激活虚拟环境:
      • Windows: myenv\Scripts\activate
      • macOS/Linux: source myenv/bin/activate
    • 在激活的环境中安装 OpenCV:pip install opencv-python
  • 使用 conda (如果你安装了 Anaconda/Miniconda):

    • 创建虚拟环境:conda create -n myenv python=3.9 (myenv 是环境名称,3.9 是 Python 版本)
    • 激活虚拟环境:conda activate myenv
    • 安装 OpenCV:conda install opencv

在虚拟环境中安装的库只会影响当前环境,非常便于管理。

4. 选择一个代码编辑器或集成开发环境 (IDE)

你可以使用任何文本编辑器编写 Python 代码,但使用一个好的代码编辑器或 IDE 会极大地提高效率,例如:

  • VS Code: 轻量级、功能强大、丰富的扩展。
  • PyCharm: 专门为 Python 开发设计的 IDE,功能非常强大(社区版免费)。
  • Jupyter Notebook/Lab: 适合进行交互式学习和实验,可以方便地展示图像结果。

选择一个你喜欢的工具即可。

第三站:基础概念——图像是什么?

在开始编程之前,理解图像在计算机中是如何表示的至关重要。

1. 像素 (Pixels)

图像是由一个个微小的点组成的,这些点称为像素。每个像素都包含颜色信息。图像的质量通常与像素的数量有关,像素越多,图像越细腻(分辨率越高)。

2. 颜色通道 (Color Channels)

彩色图像通常由多个颜色通道组合而成。最常见的彩色模型是 RGB (Red, Green, Blue),每个像素的颜色由红、绿、蓝三个通道的颜色强度值决定。

重要一点:OpenCV 默认加载彩色图像时使用的是 BGR 通道顺序 (Blue, Green, Red),而不是更常见的 RGB! 这点初学者经常会混淆,需要特别注意。

灰度图像 (Grayscale) 只有一个通道,表示像素的亮度信息,值通常在 0 (黑色) 到 255 (白色) 之间。

3. 图像作为多维数组

在 OpenCV 和 Python 中,图像被表示为 NumPy 库的多维数组 (ndarray)。

  • 灰度图像: 是一个二维数组 (高度 x 宽度),每个元素代表一个像素的灰度值。
  • 彩色图像: 是一个三维数组 (高度 x 宽度 x 通道数),例如,一个 BGR 图像是 (高度, 宽度, 3) 的数组,其中第三个维度包含每个像素的蓝色、绿色和红色值。

数组元素的类型通常是 uint8 (8位无符号整数),意味着每个通道的像素值范围是 0 到 255。

理解图像是 NumPy 数组,意味着你可以利用 NumPy 提供的各种强大的数组操作功能来处理图像。

第四站:核心操作——读、显、存图像

这是学习 OpenCV 的“Hello World”。

1. 导入 OpenCV 库

在 Python 脚本的开头,你需要导入 OpenCV 库:

python
import cv2

通常以 cv2 作为别名。

2. 读取图像

使用 cv2.imread() 函数读取图像文件:

“`python

读取彩色图像 (默认)

img_color = cv2.imread(‘my_image.jpg’, cv2.IMREAD_COLOR) # 或者直接用 1

读取灰度图像

img_gray = cv2.imread(‘my_image.jpg’, cv2.IMREAD_GRAYSCALE) # 或者直接用 0

读取包含 Alpha 通道的图像 (透明度)

img_alpha = cv2.imread(‘my_image.png’, cv2.IMREAD_UNCHANGED) # 或者直接用 -1

检查图像是否成功加载

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

注意:请将 ‘my_image.jpg’ 替换为你实际的图片文件名和路径

“`

  • cv2.imread() 的第一个参数是图像文件的路径。
  • 第二个参数是读取模式:
    • cv2.IMREAD_COLOR (或 1): 读取彩色图像,忽略 Alpha 通道。
    • cv2.IMREAD_GRAYSCALE (或 0): 读取灰度图像。
    • cv2.IMREAD_UNCHANGED (或 -1): 读取图像,包括 Alpha 通道。
  • 如果文件不存在或路径错误,imread() 返回 None,所以最好进行检查。

3. 显示图像

使用 cv2.imshow() 函数在窗口中显示图像:

“`python

显示彩色图像

cv2.imshow(‘彩色图像’, img_color)

显示灰度图像

cv2.imshow(‘灰度图像’, img_gray)

‘彩色图像’ 和 ‘灰度图像’ 是窗口的标题

“`

imshow() 会创建一个窗口来显示图像,但这个窗口需要一个事件循环来保持显示并响应键盘/鼠标事件。这就是 cv2.waitKey() 的作用。

“`python

等待按键

参数是等待的毫秒数。0 表示无限等待,直到按下任意键

cv2.waitKey(0)

关闭所有 OpenCV 窗口

cv2.destroyAllWindows()
“`

一个完整的读取并显示图像的例子:

“`python
import cv2

确保你有一个名为 ‘my_image.jpg’ 的图片文件在同一个目录下,或提供完整路径

image_path = ‘my_image.jpg’

读取图像

img = cv2.imread(image_path)

检查是否成功读取

if img is None:
print(f”错误:无法加载图像 {image_path}。”)
else:
# 显示图像
cv2.imshow(‘我的第一张 OpenCV 图像’, img)

# 等待按键
# 0 表示无限等待,直到按下任意键
cv2.waitKey(0)

# 关闭所有 OpenCV 窗口
cv2.destroyAllWindows()

“`

4. 保存图像

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

“`python

保存图像

cv2.imwrite(‘gray_image.png’, img_gray)

第一个参数是保存的文件名和路径

第二个参数是要保存的图像对象

“`

保存的文件格式由文件扩展名决定 (如 .jpg, .png, .bmp 等)。

5. 获取图像属性

你可以像操作 NumPy 数组一样获取图像的属性:

python
if img is not None:
print(f"图像形状 (高, 宽, 通道数):{img.shape}")
print(f"图像数据类型:{img.dtype}")
print(f"图像总像素数:{img.size}") # 高 * 宽 * 通道数

6. 访问和修改像素值

你可以像访问 NumPy 数组元素一样访问和修改图像的像素值:

“`python

对于彩色图像 (BGR)

获取 (行, 列) = (100, 150) 处的像素值 (BGR 顺序)

注意:OpenCV 的坐标系统原点在左上角,行对应高度,列对应宽度

pixel = img[100, 150]
print(f”像素 (100, 150) 的 BGR 值:{pixel}”)

修改 (行, 列) = (100, 150) 处的像素为蓝色 (BGR = [255, 0, 0])

img[100, 150] = [255, 0, 0]

对于灰度图像

获取 (行, 列) = (50, 80) 处的像素值 (灰度)

gray_pixel = img_gray[50, 80]
print(f”像素 (50, 80) 的灰度值:{gray_pixel}”)

修改 (行, 列) = (50, 80) 处的像素为黑色 (灰度 = 0)

img_gray[50, 80] = 0

注意:直接修改像素值通常效率较低,OpenCV 提供了更优化的函数进行区域操作。

“`

第五站:基本图像处理——动起来!

学会了读写显示,接下来我们学习一些基本的图像处理操作。

1. 图像缩放 (Resizing)

改变图像的尺寸:

“`python

缩放到指定大小 (宽=200, 高=300)

注意:参数顺序是 (宽度, 高度)

resized_img = cv2.resize(img, (200, 300))

按比例缩放 (例如,缩小一半)

scale_percent = 50
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
resized_img_scaled = cv2.resize(img, dim, interpolation = cv2.INTER_AREA) # 缩小通常用 INTER_AREA

显示结果 (记得 waitKey 和 destroyAllWindows)

cv2.imshow(‘Original’, img)
cv2.imshow(‘Resized’, resized_img)
cv2.imshow(‘Resized Scaled’, resized_img_scaled)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

cv2.resize() 的第三个参数 interpolation 指定插值方法,不同的方法适用于放大和缩小:
* cv2.INTER_AREA: 缩小效果最好。
* cv2.INTER_CUBICcv2.INTER_LINEAR: 放大效果较好,INTER_CUBIC 通常效果最好但计算量大。

2. 图像裁剪 (Cropping)

图像裁剪实际上就是 NumPy 数组的切片操作:

“`python

裁剪图像,获取从行 50 到 200,列 100 到 300 的区域

cropped_img = img[50:201, 100:301] # 切片范围是 [start:end),end 不包含

cv2.imshow(‘Cropped’, cropped_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

3. 图像旋转 (Rotating)

使用 cv2.rotate() 函数进行 90 度、180 度、270 度的旋转:

“`python

旋转 90 度

rotated_90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # 顺时针

旋转 180 度

rotated_180 = cv2.rotate(img, cv2.ROTATE_180)

旋转 270 度 (或逆时针 90 度)

rotated_270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)

cv2.imshow(‘Original’, img)
cv2.imshow(‘Rotated 90’, rotated_90)
cv2.imshow(‘Rotated 180’, rotated_180)
cv2.imshow(‘Rotated 270’, rotated_270)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

对于任意角度旋转,需要使用 cv2.getRotationMatrix2D()cv2.warpAffine()

4. 图像翻转 (Flipping)

使用 cv2.flip() 函数进行水平或垂直翻转:

“`python

水平翻转

flipped_horizontal = cv2.flip(img, 1) # 1 表示水平翻转

垂直翻转

flipped_vertical = cv2.flip(img, 0) # 0 表示垂直翻转

水平垂直都翻转

flipped_both = cv2.flip(img, -1) # -1 表示水平垂直都翻转

cv2.imshow(‘Original’, img)
cv2.imshow(‘Flipped Horizontal’, flipped_horizontal)
cv2.imshow(‘Flipped Vertical’, flipped_vertical)
cv2.imshow(‘Flipped Both’, flipped_both)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

第六站:在图像上绘制图形和文字

OpenCV 提供了一系列函数用于在图像上绘制基本图形(线条、矩形、圆形等)和文字。这些函数通常会直接修改输入的图像(除非你先复制一份)。

“`python

创建一个副本,避免修改原始图像

output_img = img.copy()

绘制一条线

参数:图像, 起点坐标(x, y), 终点坐标(x, y), 颜色(BGR元组), 线条粗细

cv2.line(output_img, (0, 0), (511, 511), (255, 0, 0), 5) # 蓝色线,从左上到右下

绘制一个矩形

参数:图像, 左上角坐标(x, y), 右下角坐标(x, y), 颜色, 线条粗细 (如果是负数,如-1,则填充矩形)

cv2.rectangle(output_img, (100, 100), (400, 400), (0, 255, 0), 3) # 绿色矩形

绘制一个圆形

参数:图像, 圆心坐标(x, y), 半径, 颜色, 线条粗细/填充

cv2.circle(output_img, (300, 300), 50, (0, 0, 255), -1) # 红色填充圆

添加文字

参数:图像, 文本字符串, 文本左下角坐标(x, y), 字体类型, 字体大小, 颜色, 线条粗细

font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(output_img, ‘Hello OpenCV!’, (50, 50), font, 1, (255, 255, 255), 2) # 白色文字

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

注意:坐标系统是 (x, y),其中 x 是列,y 是行。颜色是 BGR 元组 (Blue, Green, Red)

第七站:颜色空间的转换

除了 BGR 和灰度,OpenCV 支持多种颜色空间,如 HSV (Hue, Saturation, Value)。HSV 颜色空间在颜色检测和分割方面非常有用,因为它将颜色信息 (Hue) 与亮度 (Value) 和饱和度 (Saturation) 分开。

使用 cv2.cvtColor() 函数进行颜色空间转换:

“`python

将 BGR 图像转换为灰度图像

gray_img_converted = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

将 BGR 图像转换为 HSV 图像

hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

将 HSV 图像转换回 BGR

bgr_img_converted = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR)

cv2.imshow(‘Gray Converted’, gray_img_converted)
cv2.imshow(‘HSV’, hsv_img)
cv2.imshow(‘BGR Converted Back’, bgr_img_converted)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

cv2.cvtColor() 的第二个参数是转换的代码,格式通常是 cv2.COLOR_源颜色空间2目标颜色空间

第八站:图像平滑/模糊处理

平滑(或模糊)是常见的图像预处理步骤,用于降低图像噪声或进行边缘检测前的准备。常见的平滑方法包括均值滤波、高斯滤波、中值滤波等。

“`python

均值滤波

参数:图像, 卷积核大小 (ksize),例如 (5, 5) 表示 5×5 的卷积核

blurred_mean = cv2.blur(img, (5, 5))

高斯滤波 (更常用,效果通常更好)

参数:图像, 卷积核大小 (必须是奇数), X方向的标准差 (sigmaX),通常 sigmaY 设为 0 即可

blurred_gaussian = cv2.GaussianBlur(img, (5, 5), 0)

中值滤波 (对椒盐噪声效果很好)

参数:图像, 卷积核大小 (必须是大于1的奇数)

blurred_median = cv2.medianBlur(img, 5) # 卷积核大小为 5×5

cv2.imshow(‘Original’, img)
cv2.imshow(‘Mean Blur’, blurred_mean)
cv2.imshow(‘Gaussian Blur’, blurred_gaussian)
cv2.imshow(‘Median Blur’, blurred_median)
cv2.waitKey(0)
cv2.destroyAllWindows()
“`

这些滤波操作通过在像素周围的邻域(由卷积核大小决定)内计算某种值来替代中心像素的值。

第九站:玩转视频——读取摄像头或视频文件

OpenCV 不仅处理静态图像,也非常擅长处理视频流。视频本质上是连续的图像帧序列。

“`python

打开默认摄像头 (参数为摄像头索引,通常 0 是默认摄像头)

cap = cv2.VideoCapture(0)

或者打开视频文件

cap = cv2.VideoCapture(‘my_video.mp4’) # 替换为你的视频文件路径

检查摄像头/视频是否成功打开

if not cap.isOpened():
print(“错误:无法打开摄像头或视频文件。”)
exit()

循环读取视频帧

while True:
# read() 返回一个布尔值 (是否成功读取) 和当前帧
ret, frame = cap.read()

# 如果无法读取帧,则达到视频末尾或发生错误
if not ret:
    print("已到达视频末尾或读取错误。")
    break

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

# 显示原始帧和处理后的帧
cv2.imshow('Original Frame', frame)
cv2.imshow('Gray Frame', gray_frame)

# 等待按键
# cv2.waitKey() 参数为等待的毫秒数
# 对于视频流,通常设置为一个小的正数 (如 1 或 25) 来控制播放速度
# 如果按下 'q' 键 (ASCII 码是 ord('q')),则退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
    break

释放视频捕获对象

cap.release()

关闭所有 OpenCV 窗口

cv2.destroyAllWindows()
“`

这个代码结构是处理视频流的标准模式:打开捕获对象 -> 循环读取帧 -> 处理每一帧 -> 显示帧 -> 等待按键 (并检查退出条件) -> 循环结束后释放资源。

第十站:更进一步——探索 OpenCV 的高级功能

恭喜你,你已经掌握了 Python OpenCV 的基本操作!这仅仅是计算机视觉世界的冰山一角。OpenCV 提供了大量更高级的功能,你可以根据自己的兴趣继续深入学习:

  1. 图像阈值化与二值化: 将图像分割为前景和背景 (常用于目标检测预处理)。
  2. 轮廓检测: 查找和分析图像中的对象轮廓。
  3. 特征检测与匹配: 查找图像中具有代表性的点或区域 (如 SIFT, SURF, ORB 特征),用于图像拼接、物体识别等。
  4. 目标检测: 识别图像中是否存在特定的物体并标注位置 (如 Haar cascades, HOG, 以及集成 YOLO, SSD 等深度学习模型)。
  5. 人脸检测与识别: OpenCV 内置了基于 Haar 特征的人脸检测器,也可以集成更先进的识别算法。
  6. 图像分割: 将图像划分为有意义的区域。
  7. 图像校准: 消除摄像头畸变。
  8. 立体视觉与三维重建: 从多幅图像恢复场景的三维信息。
  9. 机器学习模块: OpenCV 内置了一些传统的机器学习算法 (如 SVM, K-Means),也可以方便地与 Scikit-learn 等库结合。
  10. 与深度学习框架集成: OpenCV 提供了 DNN 模块,可以直接加载和运行一些主流深度学习框架训练的模型(如 TensorFlow, PyTorch, Caffe, Darknet 等),进行目标检测、图像分类等任务。

学习建议与资源

  • 动手实践: 理论知识很重要,但计算机视觉更是实践的学科。多找图片、视频进行实验,修改代码,看看不同参数的效果。
  • 阅读官方文档: OpenCV 官方网站 (docs.opencv.org) 提供了详细的文档和教程,这是最权威的学习资源。Python 接口的文档也很完善。
  • 参考在线教程和博客: 互联网上有很多优秀的 Python OpenCV 教程,可以参考别人的代码和思路。
  • 参与社区讨论: 在 Stack Overflow 等论坛提问和学习别人的问题,是进步的有效途径。
  • 学习 NumPy: 由于 OpenCV 图像是 NumPy 数组,熟练掌握 NumPy 的数组操作对高效处理图像非常有帮助。
  • 理解基本数学原理: 图像处理和计算机视觉涉及一些线性代数、微积分、概率统计等数学知识。刚开始可以不必深究,但在深入学习高级算法时,理解背后的数学原理会更有助于掌握。

结语

从零开始学习 Python OpenCV 是一段充满挑战和乐趣的旅程。你将学会如何让计算机“看”懂世界,这本身就是一件非常酷的事情。本文为你搭建了学习环境,介绍了图像的基础概念,并带领你完成了图像的读取、显示、保存、基本处理以及视频的读取。

记住,这只是一个起点。计算机视觉的世界广阔而精彩,有无数的算法和应用等待你去探索。保持好奇心,持续实践,你一定能在视觉之旅中取得丰硕的成果!祝你学习顺利,享受用代码赋予机器视觉的乐趣!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部