Python OpenCV 快速入门指南 – wiki基地


Python OpenCV 快速入门指南:从零开始掌握计算机视觉基础

计算机视觉(Computer Vision)是人工智能领域的一个重要分支,旨在让计算机“看懂”世界。而 OpenCV(Open Source Computer Vision Library)是目前最流行、功能最强大的开源计算机视觉库之一。它提供了 C++, Python, Java 等多种语言的接口,其中 Python 接口因其简洁易用、生态丰富而备受青睐。

本文将为你提供一份详尽的 Python OpenCV 快速入门指南,带你从安装开始,逐步掌握 OpenCV 的核心概念和基本操作,为你打开计算机视觉的大门。无论你是学生、开发者还是对图像处理感兴趣的爱好者,本文都将是你迈出第一步的坚实基础。

文章目录

  1. 引言:什么是 OpenCV?为什么选择 Python?
  2. 环境搭建:安装 Python 和 OpenCV
  3. 核心概念:图像表示与基本属性
    • 图像是什么?(NumPy 数组)
    • 颜色空间(BGR vs RGB, 灰度图)
    • 坐标系统
  4. 基础操作:加载、显示和保存图像
    • 读取图像:cv2.imread()
    • 显示图像:cv2.imshow()
    • 等待按键与关闭窗口:cv2.waitKey(), cv2.destroyAllWindows()
    • 保存图像:cv2.imwrite()
  5. 图像属性与像素操作
    • 获取图像属性:形状、尺寸、数据类型
    • 访问和修改像素值
    • ROI (Region of Interest) 区域提取
  6. 在图像上绘制图形和文字
    • 绘制直线:cv2.line()
    • 绘制矩形:cv2.rectangle()
    • 绘制圆形:cv2.circle()
    • 绘制文字:cv2.putText()
  7. 基本的图像处理技术
    • 色彩空间转换:cv2.cvtColor() (BGR转灰度, BGR转HSV)
    • 图像阈值化:cv2.threshold(), cv2.adaptiveThreshold()
    • 图像平滑/模糊:cv2.GaussianBlur(), cv2.medianBlur()
    • 图像几何变换:
      • 图像缩放:cv2.resize()
      • 图像平移:cv2.warpAffine() (需要构建变换矩阵)
      • 图像旋转:cv2.getRotationMatrix2D(), cv2.warpAffine()
    • 图像算术运算:加法、减法、混合
    • 图像位运算:AND, OR, NOT, XOR (结合掩膜实现区域操作)
    • 边缘检测:cv2.Canny()
  8. 处理视频与摄像头
    • 读取视频或摄像头:cv2.VideoCapture()
    • 读取帧:cap.read()
    • 显示帧
    • 释放资源
  9. 下一步:进阶学习方向
  10. 总结与展望

1. 引言:什么是 OpenCV?为什么选择 Python?

什么是 OpenCV?

OpenCV 是一个跨平台的计算机视觉库,由英特尔公司发起并持续开发。它包含了大量的函数,涵盖了计算机视觉领域众多方向,包括:

  • 图像处理(Filtering, Transformation, etc.)
  • 特征检测与描述(Corners, Edges, Keypoints)
  • 目标检测(Face Detection, Object Detection using Haar Cascades, DNNs)
  • 目标跟踪(Object Tracking)
  • 三维重建
  • 相机校准
  • 机器学习算法(SVM, K-Means, etc. – 虽然更多用于计算机视觉任务)

OpenCV 设计之初就考虑了效率问题,其核心功能由 C++ 实现,因此运行速度较快。

为什么选择 Python 接口?

Python 作为一种高级编程语言,以其简洁的语法、丰富的库生态和强大的社区支持而闻名。将 OpenCV 与 Python 结合使用,具有以下优势:

  • 易学易用: Python 语法简单直观,可以快速上手。
  • 开发效率高: Python 的动态特性和丰富的标准库、第三方库(如 NumPy, Matplotlib)能极大地提高开发效率。OpenCV 的 Python 接口实际上是 C++ 库的 Python 封装,它返回和操作的对象通常是 NumPy 数组,这使得图像处理与科学计算库(如 NumPy, SciPy)的结合变得非常方便和高效。
  • 快速原型开发: Python 非常适合快速构建和测试计算机视觉算法的原型。
  • 丰富的生态系统: 可以轻松地将 OpenCV 与其他 Python 库集成,例如使用 Matplotlib 进行可视化,使用 Scikit-learn 进行机器学习,使用深度学习框架(TensorFlow, PyTorch)进行更高级的视觉任务。

因此,Python OpenCV 是学习和应用计算机视觉一个非常理想的起点。

2. 环境搭建:安装 Python 和 OpenCV

在开始之前,你需要确保你的计算机上已经安装了 Python。推荐安装 Python 3.6 或更高版本。你可以从 Python 官网 (python.org) 下载安装包。

安装好 Python 后,安装 OpenCV 的 Python 库非常简单,通常使用 pip 包管理器即可。

打开你的终端或命令提示符,运行以下命令:

bash
pip install opencv-python

如果你需要额外的contrib模块(包含一些实验性或非免费许可的功能,尽管现在大部分常用功能已集成),可以安装:

bash
pip install opencv-contrib-python

对于大多数入门用途,opencv-python 就足够了。

验证安装

安装完成后,打开 Python 交互式环境或创建一个 Python 脚本,尝试导入 cv2 库:

python
import cv2
print(cv2.__version__)

如果能成功导入并打印出版本号,说明 OpenCV 已经成功安装。

推荐使用虚拟环境

为了避免不同项目之间的库版本冲突,强烈建议使用虚拟环境(Virtual Environment)。你可以使用 venv(Python 3.3+ 自带)或 conda

使用 venv 创建虚拟环境:

“`bash
python -m venv myenv

激活虚拟环境

Windows: myenv\Scripts\activate

macOS/Linux: source myenv/bin/activate

在激活的虚拟环境中安装 OpenCV

pip install opencv-python
“`

使用 conda 创建虚拟环境:

bash
conda create -n myenv python=3.8
conda activate myenv
conda install opencv

本文后续的代码示例都假设你已经进入了安装有 OpenCV 的 Python 环境。

3. 核心概念:图像表示与基本属性

在计算机中,图像是如何被表示和处理的呢?OpenCV 主要使用 NumPy 库来处理图像。

图像是什么?(NumPy 数组)

在 OpenCV 中,图像被视为多维的 NumPy 数组(numpy.ndarray)。

  • 灰度图像: 是一个二维数组,每个元素代表一个像素的灰度值,范围通常是 0 到 255(8 位)。数组的形状是 (高度, 宽度)
  • 彩色图像: 是一个三维数组,形状是 (高度, 宽度, 通道数)。对于常见的 RGB 或 BGR 图像,通道数是 3。每个像素由一个包含三个元素的数组表示,分别代表不同通道的强度值。

颜色空间(BGR vs RGB, 灰度图)

  • 灰度图 (Grayscale): 只包含一个通道,表示亮度信息。像素值范围 0-255,0 代表黑色,255 代表白色。
  • BGR (Blue-Green-Red): OpenCV 默认的彩色图像格式是 BGR,而不是我们通常认为的 RGB。这意味着对于一个彩色像素,其存储顺序是蓝色分量、绿色分量、红色分量。例如,白色像素在 8 位 BGR 图像中是 (255, 255, 255),纯蓝色是 (255, 0, 0),纯红色是 (0, 0, 255)。理解这一点非常重要,否则颜色操作可能会出错。
  • RGB (Red-Green-Blue): Web 和许多图像文件格式使用 RGB。OpenCV 也支持 RGB 格式,但默认是 BGR。
  • HSV (Hue-Saturation-Value): 色调-饱和度-明度。HSV 颜色空间更符合人类感知颜色的方式,并且在基于颜色的目标检测等任务中非常有用,因为它能将颜色(Hue)与亮度和饱和度分离。OpenCV 也支持 HSV。

坐标系统

在 OpenCV 中,图像的坐标原点 (0, 0) 位于图像的左上角。水平方向是 x 轴(列),垂直方向是 y 轴(行)。

  • 访问像素时,使用 img[y, x]img[y, x, c],其中 y 是行索引,x 是列索引,c 是通道索引。注意,先行后列,与我们数学中习惯的 (x, y) 坐标顺序 (列, 行) 相反,但与 NumPy 数组的索引 [row, column] 保持一致。

4. 基础操作:加载、显示和保存图像

这是使用 OpenCV 进行图像处理的第一步。

读取图像:cv2.imread()

cv2.imread(filepath, flags) 函数用于从指定文件路径加载图像。

  • filepath: 图像文件的路径(可以是相对路径或绝对路径)。
  • flags: 指定读取图像的方式。
    • cv2.IMREAD_COLOR1: 读取彩色图像(默认)。忽略图像的透明度信息。
    • cv2.IMREAD_GRAYSCALE0: 读取灰度图像。
    • cv2.IMREAD_UNCHANGED-1: 读取包含 alpha 通道的完整图像(如果存在)。

“`python
import cv2
import numpy as np

假设你有一张名为 ‘cat.jpg’ 的图片在当前目录下

读取彩色图像

img_color = cv2.imread(‘cat.jpg’, cv2.IMREAD_COLOR)

读取灰度图像

img_gray = cv2.imread(‘cat.jpg’, cv2.IMREAD_GRAYSCALE)

检查图像是否成功读取

if img_color is None:
print(“错误:无法读取图像文件 cat.jpg”)
exit() # 如果无法读取则退出程序
else:
print(“图像 cat.jpg 读取成功!”)

打印一些信息

print(“彩色图像的类型:”, type(img_color)) # 通常是
print(“彩色图像的形状 (高, 宽, 通道):”, img_color.shape)
print(“灰度图像的形状 (高, 宽):”, img_gray.shape) # 注意灰度图没有通道信息

图像是一个 NumPy 数组

可以像操作 NumPy 数组一样操作它

print(img_color) # 这会打印整个数组,非常大!

“`

显示图像:cv2.imshow()

cv2.imshow(winname, mat) 函数用于在窗口中显示图像。

  • winname: 窗口的名称,一个字符串。多个窗口需要不同的名称。
  • mat: 要显示的图像矩阵(NumPy 数组)。

“`python

在名为 ‘彩色图像’ 的窗口中显示彩色图像

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

在名为 ‘灰度图像’ 的窗口中显示灰度图像

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

注意:cv2.imshow() 会创建一个窗口,但程序会立即继续执行,

如果程序结束,窗口也会立即关闭。因此,你需要使用 cv2.waitKey()

来保持窗口打开,直到用户按下按键。

“`

等待按键与关闭窗口:cv2.waitKey(), cv2.destroyAllWindows()

  • cv2.waitKey(delay): 等待用户按下键盘上的一个键。
    • delay 参数是等待的毫秒数。如果 delay <= 0,函数会无限期地等待,直到用户按下任意键。
    • 如果按下了键,函数返回按键的 ASCII 码;如果没有按下键(当 delay > 0 时),函数返回 -1。
    • 这是一个非常重要的函数,它不仅处理键盘事件,也是刷新 OpenCV 窗口的关键。没有 waitKeyimshow 可能不会正常工作。
  • cv2.destroyAllWindows(): 销毁所有 OpenCV 创建的窗口。
  • cv2.destroyWindow(winname): 销毁指定名称的窗口。

“`python

显示图像后,等待用户按下任意键

0 表示无限等待

cv2.waitKey(0)

按键后,销毁所有 OpenCV 窗口

cv2.destroyAllWindows()

一个完整的读取、显示、等待、关闭的流程:

img = cv2.imread(‘cat.jpg’)
if img is not None:
cv2.imshow(‘Cat’, img)
# 等待 5000 毫秒 (5秒),如果期间按下任意键则立即返回
# key = cv2.waitKey(5000)
# 等待任意键按下
key = cv2.waitKey(0)
print(“您按下了键码:”, key) # 打印按下的键的ASCII码
cv2.destroyAllWindows()
else:
print(“无法加载图像”)
“`

保存图像:cv2.imwrite()

cv2.imwrite(filename, img) 函数用于将图像保存到文件。

  • filename: 保存文件的路径和名称(包括扩展名,如 ‘.jpg’, ‘.png’)。
  • img: 要保存的图像矩阵。

根据文件扩展名,OpenCV 会自动选择相应的图像编码格式。

“`python

将灰度图像保存为 ‘cat_gray.png’

注意:保存为 PNG 格式通常是无损的

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

将彩色图像保存为 ‘cat_color.jpg’

注意:保存为 JPG 格式是压缩的,可能导致质量损失,但文件更小

cv2.imwrite(‘cat_color.jpg’, img_color)

print(“图像已保存。”)
“`

5. 图像属性与像素操作

图像在 OpenCV 中是 NumPy 数组,因此我们可以利用 NumPy 的强大功能来获取图像属性和操作像素。

获取图像属性

NumPy 数组的几个重要属性:

  • img.shape: 返回图像的形状。灰度图返回 (高度, 宽度),彩色图返回 (高度, 宽度, 通道数)
  • img.size: 返回图像的总像素数。对于彩色图,是 高度 * 宽度 * 通道数;对于灰度图,是 高度 * 宽度
  • img.dtype: 返回图像中每个像素值的数据类型。通常是 uint8(无符号 8 位整数),表示像素值在 0 到 255 之间。

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
print(“图像形状 (高, 宽, 通道):”, img.shape) # e.g., (500, 800, 3)
print(“图像总像素数:”, img.size) # e.g., 500 * 800 * 3
print(“像素数据类型:”, img.dtype) # e.g., uint8
else:
print(“无法加载图像”)
“`

访问和修改像素值

你可以使用 NumPy 的索引方式访问或修改特定像素的值。记住索引顺序是 [y, x][y, x, c]

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
# 获取 (100, 150) 坐标处的像素值
# 对于彩色图像,这将是一个 BGR 值的数组 [B, G, R]
pixel = img[150, 100] # 注意:先高(y/行), 后宽(x/列)
print(“像素 (100, 150) 的值 (BGR):”, pixel)

# 获取 (100, 150) 坐标处像素的蓝色分量
blue_channel = img[150, 100, 0] # 索引 0 是蓝色
green_channel = img[150, 100, 1] # 索引 1 是绿色
red_channel = img[150, 100, 2] # 索引 2 是红色
print("像素 (100, 150) 的蓝色分量:", blue_channel)

# 修改 (100, 150) 坐标处的像素值为纯蓝色
img[150, 100] = [255, 0, 0] # BGR顺序

# 将 (100, 150) 处像素的红色分量设置为 255
img[150, 100, 2] = 255 # 注意:这里只修改了红色分量

# OpenCV 函数通常比直接修改像素更快,但对于少量像素的修改,直接索引很方便。

# 显示修改后的图像
cv2.imshow('Modified Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

ROI (Region of Interest) 区域提取

利用 NumPy 的切片(slicing)功能,可以非常方便地提取图像的任意矩形区域,这就是 ROI。ROI 本身也是一个 NumPy 数组,是原图像的一个“视图”,对 ROI 的修改会反映到原图像上(除非你创建了副本)。

切片格式:img[y1:y2, x1:x2],其中 y1y2-1 是行的范围,x1x2-1 是列的范围。

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
# 提取图像中从行 50 到 250,列 100 到 400 的区域
roi = img[50:250, 100:400]

# 显示提取的 ROI
cv2.imshow('ROI', roi)
cv2.waitKey(0)

# 示例:将 ROI 区域的像素值设置为 0(黑色)
img[50:250, 100:400] = [0, 0, 0]

# 显示修改后的原图
cv2.imshow('Image with Black ROI', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

ROI 的概念非常重要,它允许你只处理图像的特定部分,提高效率。

6. 在图像上绘制图形和文字

OpenCV 提供了一系列函数可以在图像上绘制直线、矩形、圆形等多边形以及添加文本。这些函数通常会直接修改原始图像。

常用绘制函数:

  • cv2.line(img, pt1, pt2, color, thickness): 绘制直线。pt1pt2 是起点和终点坐标 (x, y)
  • cv2.rectangle(img, pt1, pt2, color, thickness): 绘制矩形。pt1 是左上角坐标,pt2 是右下角坐标。thickness=-1 表示填充矩形。
  • cv2.circle(img, center, radius, color, thickness): 绘制圆形。center 是圆心坐标 (x, y)
  • cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType): 绘制文字。text 是文字内容,org 是文字的起始坐标 (x, y)(通常是文字基线的左下角),fontFace 是字体类型(如 cv2.FONT_HERSHEY_SIMPLEX),fontScale 是字体缩放比例。

参数说明:

  • img: 要在其上绘制的图像。
  • color: 绘制的颜色,以 BGR 元组形式表示,如 (0, 255, 0) 表示绿色。
  • thickness: 线条的粗细。对于填充图形,设置为 -1

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
# 绘制一条红色的对角线,粗细为 2 像素
cv2.line(img, (0, 0), (img.shape[1], img.shape[0]), (0, 0, 255), 2)

# 绘制一个绿色的矩形
cv2.rectangle(img, (100, 50), (300, 200), (0, 255, 0), 3)

# 绘制一个填充的蓝色圆形
cv2.circle(img, (400, 300), 50, (255, 0, 0), -1)

# 在图像上添加文字
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'Hello OpenCV!', (50, 50), font, 1, (255, 255, 255), 2, cv2.LINE_AA)

cv2.imshow('Drawing Demo', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

7. 基本的图像处理技术

OpenCV 提供了大量的图像处理函数。这里介绍一些最基本和常用的。

色彩空间转换:cv2.cvtColor()

用于将图像从一种颜色空间转换到另一种。

cv2.cvtColor(src, code)

  • src: 输入图像(NumPy 数组)。
  • code: 转换的代码,例如 cv2.COLOR_BGR2GRAY 将 BGR 图像转换为灰度图,cv2.COLOR_BGR2HSV 将 BGR 图像转换为 HSV 图像。

“`python
img_color = cv2.imread(‘cat.jpg’)

if img_color is not None:
# 将彩色图像转换为灰度图像
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)

# 将彩色图像转换为 HSV 图像
img_hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV)

cv2.imshow('Original (BGR)', img_color)
cv2.imshow('Grayscale', img_gray)
cv2.imshow('HSV', img_hsv)

# 注意:HSV 图像通常不直接显示其三个通道,因为人眼无法直接感知。
# 你可以显示它的某个通道,例如 H 通道
cv2.imshow('Hue Channel', img_hsv[:, :, 0]) # 显示色调通道

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

图像阈值化:cv2.threshold(), cv2.adaptiveThreshold()

阈值化是图像分割的一种简单方法,将图像转换为二值图(只有黑白两个像素值)。

  • cv2.threshold(src, thresh, maxval, type): 全局阈值化。
    • src: 输入图像(通常是灰度图)。
    • thresh: 阈值。
    • maxval: 最大值(通常是 255)。
    • type: 阈值类型,如 cv2.THRESH_BINARY(大于阈值设为 maxval,否则为 0),cv2.THRESH_BINARY_INV(反向二值化),cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, cv2.THRESH_TOZERO_INV 等。
    • 返回两个值:实际使用的阈值和阈值化后的图像。
  • cv2.adaptiveThreshold(src, maxval, adaptiveMethod, thresholdType, blockSize, C): 自适应阈值化,根据像素周围的小区域计算不同的阈值,适合处理光照不均的图像。
    • adaptiveMethod: 自适应方法,如 cv2.ADAPTIVE_THRESH_MEAN_C(邻域像素平均值)或 cv2.ADAPTIVE_THRESH_GAUSSIAN_C(邻域像素加权平均值)。
    • blockSize: 用于计算阈值的邻域大小(奇数)。
    • C: 从计算出的平均值或加权平均值中减去的常数。

“`python
img_gray = cv2.imread(‘cat.jpg’, cv2.IMREAD_GRAYSCALE)

if img_gray is not None:
# 全局二值化阈值设为 127
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

# 全局反向二值化阈值设为 127
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)

# 自适应阈值化 (均值)
# blockSize 11x11,C=2
thresh_adaptive_mean = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)

# 自适应阈值化 (高斯)
# blockSize 11x11,C=2
thresh_adaptive_gaussian = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

cv2.imshow('Original Gray', img_gray)
cv2.imshow('Binary Threshold', thresh1)
cv2.imshow('Binary Inverse Threshold', thresh2)
cv2.imshow('Adaptive Mean Threshold', thresh_adaptive_mean)
cv2.imshow('Adaptive Gaussian Threshold', thresh_adaptive_gaussian)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载灰度图像”)
“`

图像平滑/模糊

用于减少图像噪声,使图像更平滑。常见的滤波器有均值滤波、高斯滤波、中值滤波等。

  • cv2.GaussianBlur(src, ksize, sigmaX): 高斯模糊。ksize 是高斯核的大小(奇数元组,如 (5, 5)),sigmaX 是高斯函数在 X 方向的标准差(设为 0 会根据 ksize 自动计算)。
  • cv2.medianBlur(src, ksize): 中值模糊。ksize 是中值滤波器的大小(奇数,如 5)。对椒盐噪声(salt-and-pepper noise)效果较好。

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
# 应用高斯模糊,核大小 5×5
blur_gaussian = cv2.GaussianBlur(img, (5, 5), 0)

# 应用中值模糊,核大小 5x5
blur_median = cv2.medianBlur(img, 5)

cv2.imshow('Original', img)
cv2.imshow('Gaussian Blur', blur_gaussian)
cv2.imshow('Median Blur', blur_median)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

图像几何变换

包括缩放、平移、旋转等。

  • 缩放:cv2.resize()
    cv2.resize(src, dsize, fx, fy, interpolation)

    • dsize: 输出图像的大小 (宽度, 高度)。如果设置为 (0, 0),则根据 fxfy 计算大小。
    • fx, fy: 沿水平和垂直方向的缩放比例。
    • interpolation: 插值方法,如 cv2.INTER_AREA(缩小时推荐),cv2.INTER_CUBIC(放大时推荐,效果好但慢),cv2.INTER_LINEAR(默认,较快)。

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
# 按比例缩放,缩小到原来的一半
img_small = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)

# 缩放到指定大小 (宽 300, 高 200)
img_fixed_size = cv2.resize(img, (300, 200), interpolation=cv2.INTER_LINEAR)

cv2.imshow('Original', img)
cv2.imshow('Scaled Down (0.5x)', img_small)
cv2.imshow('Fixed Size (300x200)', img_fixed_size)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

  • 平移与旋转:cv2.warpAffine()

平移和旋转通常通过一个 2×3 的变换矩阵实现,然后使用 cv2.warpAffine() 应用这个变换。

  • 平移
    变换矩阵 M = [[1, 0, tx], [0, 1, ty]],其中 tx 是水平平移量,ty 是垂直平移量。

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
rows, cols = img.shape[:2] # 获取图像的高和宽

# 构建平移矩阵:向右平移 100 像素,向下平移 50 像素
# M = [[1, 0, 100], [0, 1, 50]]
M_translation = np.float32([[1, 0, 100], [0, 1, 50]])

# 应用平移变换
img_translated = cv2.warpAffine(img, M_translation, (cols, rows)) # 指定输出图像大小

cv2.imshow('Original', img)
cv2.imshow('Translated', img_translated)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

  • 旋转
    使用 cv2.getRotationMatrix2D(center, angle, scale) 生成旋转矩阵。

    • center: 旋转中心坐标 (x, y),通常是图像中心 (cols/2, rows/2)
    • angle: 旋转角度(逆时针为正)。
    • scale: 缩放比例(保持原大小设为 1.0)。

    然后使用 cv2.warpAffine() 应用旋转。

“`python
img = cv2.imread(‘cat.jpg’)

if img is not None:
rows, cols = img.shape[:2]

# 获取旋转矩阵:围绕中心旋转 45 度,不缩放
M_rotation = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 1.0)

# 应用旋转变换
img_rotated = cv2.warpAffine(img, M_rotation, (cols, rows)) # 注意输出大小通常与原图相同,可能会裁剪掉一部分内容

cv2.imshow('Original', img)
cv2.imshow('Rotated 45 Degrees', img_rotated)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

图像算术运算

OpenCV 提供了一些函数进行图像的加法、减法、混合等运算。注意,这些操作是基于像素值的。

  • cv2.add(img1, img2): 图像加法。像素值相加,结果超过 255 会被截断为 255(饱和操作)。
  • cv2.addWeighted(img1, alpha, img2, beta, gamma): 图像混合(加权求和)。result = img1 * alpha + img2 * beta + gamma。常用于图像叠加或透明效果。

“`python
img1 = cv2.imread(‘cat.jpg’)

创建一个与img1大小相同的纯色图像或加载另一张图像

为了简单,这里使用纯色图像

img2 = np.full_like(img1, (50, 50, 50), dtype=np.uint8) # 创建一个增加亮度的纯灰色图像

if img1 is not None:
# 图像加法 (增加亮度)
img_added = cv2.add(img1, img2)

# 图像混合:img1 占 70%, img2 占 30%, gamma 为 0
# 制造半透明效果
img_blended = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)

cv2.imshow('Original', img1)
cv2.imshow('Added (Brighter)', img_added)
cv2.imshow('Blended', img_blended) # 这里因为img2是纯色,看起来像调整了img1的亮度

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

图像位运算

位运算(AND, OR, NOT, XOR)在图像处理中非常有用,特别是结合掩膜(Mask)进行图像区域提取或操作。

  • cv2.bitwise_and(src1, src2, mask)
  • cv2.bitwise_or(src1, src2, mask)
  • cv2.bitwise_not(src, mask)
  • cv2.bitwise_xor(src1, src2, mask)

这些函数都支持一个可选的 mask 参数。如果提供了掩膜,操作只会在掩膜中非零(白色)的区域进行。

“`python
img1 = cv2.imread(‘cat.jpg’)

if img1 is not None:
rows, cols = img1.shape[:2]

# 创建一个黑色的背景图像
img2 = np.zeros((rows, cols, 3), dtype=np.uint8)

# 在黑色图像上创建一个白色的圆形作为掩膜
# 注意:掩膜通常是灰度图像或单通道图像
mask = np.zeros((rows, cols), dtype=np.uint8)
cv2.circle(mask, (cols // 2, rows // 2), 100, 255, -1) # 在中心绘制一个填充的白色圆

# 显示掩膜
cv2.imshow('Mask', mask)

# 应用位 AND 运算结合掩膜:只保留 img1 中掩膜非零区域的内容
# img2 (全黑) & img1 (原图) 并在 mask 非零区域进行操作
img_masked = cv2.bitwise_and(img1, img1, mask=mask) # 常用技巧: src1和src2都是原图

# 应用位 NOT 运算结合掩膜:只对 img1 中掩膜非零区域进行反色
img_not_masked = cv2.bitwise_not(img1, mask=mask)

cv2.imshow('Original', img1)
cv2.imshow('Masked Region', img_masked)
cv2.imshow('NOT Masked Region', img_not_masked)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载图像”)
“`

边缘检测:cv2.Canny()

Canny 边缘检测器是经典的边缘检测算法,效果较好。

cv2.Canny(image, threshold1, threshold2)

  • image: 8 位输入图像(通常是灰度图)。
  • threshold1, threshold2: 滞后性阈值。小于 threshold1 的被排除;大于 threshold2 的被确定为边缘;介于两者之间的,如果与确定边缘相连,也被认为是边缘。推荐 threshold2threshold1 的 2-3 倍。

“`python
img_gray = cv2.imread(‘cat.jpg’, cv2.IMREAD_GRAYSCALE)

if img_gray is not None:
# 应用 Canny 边缘检测
# 参数 100 和 200 是阈值
edges = cv2.Canny(img_gray, 100, 200)

cv2.imshow('Original Gray', img_gray)
cv2.imshow('Canny Edges', edges)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(“无法加载灰度图像”)
“`

8. 处理视频与摄像头

OpenCV 不仅处理静态图像,也能方便地处理视频流,无论是来自文件还是摄像头。

  • 读取视频或摄像头:cv2.VideoCapture()
    cv2.VideoCapture(index)cv2.VideoCapture(filename)

    • index: 设备索引号。通常 0 代表默认摄像头,1 代表第二个摄像头,以此类推。
    • filename: 视频文件的路径。
  • 读取帧:cap.read()
    在一个循环中调用 cap.read() 来读取视频流中的下一帧。
    它返回两个值:

    • success: 布尔值,如果成功读取帧则为 True,否则为 False
    • frame: 读取到的帧图像(一个 NumPy 数组)。如果没有读取到帧(视频结束或出错),则为 None
  • 释放资源:cap.release(), cv2.destroyAllWindows()
    处理完毕后,需要释放视频捕获对象和关闭所有窗口。

“`python

0 表示打开默认摄像头

cap = cv2.VideoCapture(0)

或者打开一个视频文件

cap = cv2.VideoCapture(‘my_video.mp4’)

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

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

循环读取并显示帧

while True:
# 读取一帧
success, frame = cap.read()

# 如果无法读取帧(例如视频结束)则退出循环
if not success:
    print("无法接收帧 (视频流已结束?)。退出...")
    break

# 你可以在这里对每一帧进行图像处理
# 例如:将帧转换为灰度图
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# 显示原始帧
cv2.imshow('Original Frame', frame)

# 显示处理后的帧
cv2.imshow('Gray Frame', gray_frame)

# 检测按键,如果按下 'q' 键则退出
# waitKey 参数为 1ms,表示每帧之间等待 1ms,以确保窗口响应和显示帧
# 按下 'q' 键的 ASCII 码是 104 (小写q) 或 81 (大写Q),但更通用的是 ord('q')
if cv2.waitKey(1) == ord('q'):
    break

循环结束后,释放视频捕获对象并关闭所有窗口

cap.release()
cv2.destroyAllWindows()

print(“视频处理结束。”)
“`

这段代码会打开你的摄像头,实时显示原始画面和灰度化后的画面,直到你按下键盘上的 ‘q’ 键。

9. 下一步:进阶学习方向

恭喜你已经掌握了 Python OpenCV 的基础知识!这只是计算机视觉的冰山一角。接下来,你可以根据自己的兴趣深入学习以下方向:

  • 特征检测与匹配: SIFT, SURF, ORB 等特征点检测算法,用于图像拼接、目标识别等。
  • 轮廓检测: 查找和分析图像中的轮廓,常用于目标识别和形状分析。
  • 图像分割: 将图像分成有意义的区域(例如,前景和背景)。
  • 对象检测: 使用 Haar 特征级联(如人脸检测)或更先进的深度学习方法(如 YOLO, SSD, Faster R-CNN)。
  • 目标跟踪: 在视频序列中跟踪特定对象。
  • 相机校准与三维重建: 理解相机的内外参数,从二维图像恢复三维信息。
  • 机器学习模块: 虽然现在更多使用独立的机器学习库,但 OpenCV 仍包含一些基础算法。
  • 深度学习推理: OpenCV 的 DNN 模块支持加载和运行主流深度学习框架(如 TensorFlow, PyTorch, Caffe)训练的模型。

10. 总结与展望

通过本文,你已经了解了 Python OpenCV 的基本概念、环境搭建方法、如何加载、显示、保存图像,以及如何进行基本的像素操作、图形绘制和一些核心的图像处理技术(色彩空间转换、阈值化、滤波、几何变换、算术和位运算、边缘检测)。你还学会了如何使用 OpenCV 处理视频流。

这为你进入更广阔的计算机视觉世界打下了坚实的基础。计算机视觉是一个充满挑战和机遇的领域,广泛应用于自动驾驶、医疗影像分析、工业自动化、安防监控、增强现实等众多领域。

持续实践是掌握任何技术的关键。尝试运行本文中的代码示例,并尝试修改它们,处理不同的图像和视频。查阅 OpenCV 官方文档(虽然主要是 C++ 文档,但函数名和参数通常一致,结合 Python 文档或示例进行理解)是进一步学习的好方法。

祝你在计算机视觉的学习旅程中取得更多进展!


发表评论

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

滚动至顶部