使用 Python 和 OpenCV 进行图像处理:入门介绍 – wiki基地


使用 Python 和 OpenCV 进行图像处理:入门介绍

引言:图像处理的世界与强大的工具组合

图像处理,顾名思义,是对图像进行各种操作,以达到增强、分析、识别或变换图像内容的目的。从智能手机的滤镜、无人驾驶汽车的视觉识别,到医学影像分析和工业质量检测,图像处理技术无处不在,深刻影响着我们的生活和技术发展。

在众多图像处理工具中,Python 凭借其简洁易读的语法和丰富的生态系统,成为了科研、数据科学和开发领域的首选语言之一。而 OpenCV(Open Source Computer Vision Library),作为一个开源的计算机视觉和机器学习软件库,则提供了海量高效的图像处理和计算机视觉算法。当 Python 遇到 OpenCV,便擦出了强大的火花,形成了一套既易于学习又功能强大的图像处理工具组合。

本文将带领大家踏入使用 Python 和 OpenCV 进行图像处理的大门。我们将从基础概念开始,一步步学习如何安装环境、读取和显示图像、理解图像数据、进行基本的几何变换和颜色空间转换,以及如何在图像上绘制图形和文本。无论您是编程新手还是希望了解图像处理的开发者,都能从本文中获得实用的知识和技能。

第一章:为何选择 Python 和 OpenCV?

在深入学习之前,让我们先了解一下为何 Python 和 OpenCV 会是如此受欢迎的图像处理组合。

  1. Python 的优势:

    • 易学易用: Python 的语法清晰直观,上手快,非常适合初学者。
    • 生态系统丰富: Python 拥有庞大的第三方库支持,如 NumPy(强大的数值计算库)、Matplotlib(绘图库)、Scikit-image(另一个图像处理库)等,这些库可以与 OpenCV 无缝协作,极大地扩展了功能。
    • 社区活跃: 遇到问题时,可以在活跃的社区中快速找到帮助和解决方案。
    • 跨平台: Python 可以在多种操作系统上运行。
  2. OpenCV 的优势:

    • 功能强大且全面: OpenCV 提供了从最基本的图像操作(如滤波、边缘检测)到复杂的计算机视觉任务(如特征匹配、目标检测、人脸识别、姿态估计)所需的各种算法。
    • 高性能: 尽管通过 Python 接口调用,但 OpenCV 的核心算法是用 C++ 实现的,这意味着它们执行效率高,适用于处理大型图像或实时视频流。
    • 开源且免费: OpenCV 是在 BSD 许可下发布的,可以免费用于学术和商业用途。
    • 跨平台支持: OpenCV 支持 Windows, macOS, Linux, Android, iOS 等多个平台。

将 Python 的易用性与 OpenCV 的强大功能相结合,使得复杂的图像处理任务变得触手可及,无论是进行快速原型开发还是构建完整的视觉应用,这套组合都能胜任。

第二章:搭建你的图像处理环境

开始之前,我们需要确保计算机上安装了必要的软件。

  1. 安装 Python:
    如果您尚未安装 Python,请访问 Python 官方网站 (https://www.python.org/) 下载并安装最新版本(推荐使用 Python 3.6 或更高版本)。在安装过程中,务必勾选 “Add Python to PATH”(将 Python 添加到环境变量),这样可以在命令行中直接使用 pythonpip 命令。

  2. 安装 OpenCV Python 库:
    通过 Python 的包管理器 pip,安装 OpenCV 库非常简单。打开命令行终端(Windows 用户可以使用 Command Prompt 或 PowerShell,macOS/Linux 用户使用 Terminal),然后运行以下命令:

    bash
    pip install opencv-python

    这个命令会安装 OpenCV 的主模块。如果需要额外的贡献模块(包含一些实验性或不太常用的算法,例如 SIFT、SURF 等受专利保护的算法,尽管这些专利在某些地区已经过期),可以使用:

    bash
    pip install opencv-contrib-python

    对于入门学习,安装 opencv-python 就足够了。

  3. 安装 NumPy (可选但强烈推荐):
    OpenCV 图像在 Python 中被表示为 NumPy 数组,因此 NumPy 是 OpenCV 的重要依赖。通常安装 opencv-python 时会自动安装 NumPy,但如果未安装,可以手动安装:

    bash
    pip install numpy

  4. 验证安装:
    安装完成后,可以启动 Python 解释器或创建一个简单的 Python 脚本来验证安装是否成功。

    打开终端,输入 python 进入交互模式,然后输入:

    python
    import cv2
    print(cv2.__version__)

    如果成功导入 cv2 并且输出了 OpenCV 的版本号(例如 4.5.5),则说明安装成功。

第三章:图像的载入、显示与保存

这是进行图像处理最基础的操作。我们需要学会如何将图像文件读取到程序中进行处理,处理后如何显示结果,以及如何将结果保存为新的图像文件。

OpenCV 使用 cv2 这个名称作为 Python 接口的模块名。

  1. 载入图像 (cv2.imread):
    cv2.imread() 函数用于从指定路径载入图像文件。它的基本语法是:

    python
    cv2.imread(filename, flags)

    • filename: 图像文件的完整路径或相对路径。
    • flags: 指定图像的读取方式。常用的 flag 有:
      • cv2.IMREAD_COLOR1: 载入彩色图像。图像的透明度信息会被忽略。这是默认值。
      • cv2.IMREAD_GRAYSCALE0: 载入灰度图像。
      • cv2.IMREAD_UNCHANGED-1: 载入图像,包括 alpha 通道(如果存在)。

    注意: 如果文件路径错误或文件不存在,cv2.imread() 不会抛出异常,而是返回 None。因此,读取后检查返回值非常重要。

    示例代码:

    “`python
    import cv2

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    载入彩色图像

    img_color = cv2.imread(image_path, cv2.IMREAD_COLOR)

    载入灰度图像

    img_gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

    检查图像是否成功载入

    if img_color is None:
    print(f”错误:无法载入图像文件 {image_path}”)
    else:
    print(f”成功载入彩色图像:{image_path}”)

    if img_gray is None:
    print(f”错误:无法载入图像文件 {image_path}”)
    else:
    print(f”成功载入灰度图像:{image_path}”)

    此时,img_color 和 img_gray 是代表图像数据的 NumPy 数组

    ``
    请将
    ‘path/to/your/image.jpg’` 替换为您实际的图像文件路径。

  2. 显示图像 (cv2.imshow):
    cv2.imshow() 函数用于在一个窗口中显示图像。它的语法是:

    python
    cv2.imshow(winname, mat)

    • winname: 窗口的名称(字符串)。
    • mat: 要显示的图像矩阵(NumPy 数组)。

    cv2.imshow() 创建一个窗口并在其中显示图像。但是,这个窗口需要事件循环来保持显示并响应用户操作(如关闭)。因此,通常需要配合 cv2.waitKey()cv2.destroyAllWindows() 使用。

    cv2.waitKey() 函数会等待键盘事件。它的参数是等待的毫秒数。
    * 如果参数是 0,表示无限等待,直到按下任意键。
    * 如果参数是正整数 n,表示等待 n 毫秒;如果在 n 毫秒内没有按键,函数返回 -1,否则返回按下键的 ASCII 值。
    * 这个函数是必要的,因为它允许窗口刷新并处理事件。

    cv2.destroyAllWindows() 函数用于销毁所有创建的 OpenCV 窗口。

    示例代码:

    “`python
    import cv2
    import numpy as np # 通常与OpenCV一起使用,最好导入

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    载入彩色图像

    img = cv2.imread(image_path)

    检查图像是否成功载入

    if img is not None:
    # 创建一个窗口并显示图像
    cv2.imshow(‘Image Display’, img)

    # 等待按键,0表示无限等待
    print("按任意键关闭图像窗口...")
    cv2.waitKey(0)
    
    # 销毁所有OpenCV窗口
    cv2.destroyAllWindows()
    print("窗口已关闭。")
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    “`
    运行这段代码,会弹出一个名为 ‘Image Display’ 的窗口,显示您的图像。程序会暂停执行,直到您按下窗口处于焦点时的任意键盘按键,然后窗口会关闭,程序继续执行或退出。

  3. 保存图像 (cv2.imwrite):
    cv2.imwrite() 函数用于将图像矩阵保存到指定文件。它的语法是:

    python
    cv2.imwrite(filename, img, params)

    • filename: 保存文件的路径和名称,包括文件扩展名(如 .jpg, .png, .bmp 等)。文件扩展名决定了图像的编码格式。
    • img: 要保存的图像矩阵(NumPy 数组)。
    • params (可选): 特定格式的保存参数,例如 JPEG 格式的压缩质量 (0-100)。

    示例代码:

    “`python
    import cv2

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’
    output_path_gray = ‘output_gray.png’
    output_path_compressed = ‘output_compressed.jpg’

    载入彩色图像并转换为灰度

    img_color = cv2.imread(image_path, cv2.IMREAD_COLOR)

    if img_color is not None:
    img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY) # 先进内容,后面会解释

    # 保存灰度图像为PNG格式
    success_gray = cv2.imwrite(output_path_gray, img_gray)
    
    # 保存彩色图像为JPEG格式,设置压缩质量为 90 (默认是 95)
    # 参数是一个列表或元组,格式为 [cv2.IMWRITE_JPEG_QUALITY, quality_value]
    success_compressed = cv2.imwrite(output_path_compressed, img_color, [cv2.IMWRITE_JPEG_QUALITY, 90])
    
    if success_gray:
        print(f"灰度图像已保存到:{output_path_gray}")
    else:
        print(f"保存灰度图像失败:{output_path_gray}")
    
    if success_compressed:
         print(f"压缩彩色图像已保存到:{output_path_compressed}")
    else:
         print(f"保存压缩彩色图像失败:{output_path_compressed}")
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    ``
    运行这段代码后,您会在程序运行的目录下找到
    output_gray.pngoutput_compressed.jpg` 两个文件。

第四章:理解图像数据:像素与属性

在 OpenCV 中,图像被视为多维 NumPy 数组。理解这一点对于进行任何图像操作至关重要。

  1. 图像作为 NumPy 数组:
    载入的图像实际上是一个 numpy.ndarray 对象。这意味着我们可以使用 NumPy 提供的所有功能(如切片、索引、数学运算等)来操作图像数据。

  2. 图像的属性:
    作为 NumPy 数组,图像对象有几个重要的属性:

    • .shape: 返回一个元组,表示数组的维度。对于彩色图像(BGR 格式),shape(height, width, channels)。对于灰度图像,shape(height, width)height 是图像的行数(垂直分辨率),width 是图像的列数(水平分辨率),channels 是通道数(彩色图像通常是 3 或 4,灰度图像是 1)。
    • .size: 返回数组中元素的总数 (height * width * channels)。
    • .dtype: 返回数组元素的 数据类型。图像像素通常是 uint8 (无符号 8 位整型),表示像素值范围是 0 到 255。其他可能的类型包括 uint16 (0-65535) 或 float32 (浮点数)。

    示例代码:

    “`python
    import cv2

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img_color = cv2.imread(image_path, cv2.IMREAD_COLOR)
    img_gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

    if img_color is not None:
    print(“彩色图像属性:”)
    print(f” 形状 (高度, 宽度, 通道): {img_color.shape}”)
    print(f” 总像素数: {img_color.size}”)
    print(f” 数据类型: {img_color.dtype}”)
    else:
    print(f”错误:无法载入彩色图像文件 {image_path}”)

    if img_gray is not None:
    print(“\n灰度图像属性:”)
    print(f” 形状 (高度, 宽度): {img_gray.shape}”)
    print(f” 总像素数: {img_gray.size}”) # 注意灰度图没有通道数在 shape 中,但 size 仍然是 height * width
    print(f” 数据类型: {img_gray.dtype}”)
    else:
    print(f”错误:无法载入灰度图像文件 {image_path}”)
    “`

  3. 访问和修改像素值:
    可以通过 NumPy 数组的索引方式访问和修改单个像素或像素区域。对于彩色图像,像素的访问方式通常是 img[y, x, channel],其中 y 是行索引(从上到下),x 是列索引(从左到右),channel 是通道索引(在 OpenCV 中默认为 BGR 顺序,所以 0 是蓝色,1 是绿色,2 是红色)。对于灰度图像,访问方式是 img[y, x],直接得到灰度值。

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

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

    # 访问特定像素的颜色值 (例如:左上角像素)
    # 注意:OpenCV 是 BGR 顺序
    pixel_0_0 = img[0, 0]
    print(f"左上角像素 (0, 0) 的 BGR 值: {pixel_0_0}") # 输出 [B, G, R]
    
    # 访问特定像素的某个通道值 (例如:中间像素的蓝色通道)
    center_y, center_x = height // 2, width // 2
    blue_channel_center = img[center_y, center_x, 0] # 0是蓝色通道
    print(f"中心像素 ({center_y}, {center_x}) 的蓝色通道值: {blue_channel_center}")
    
    # 修改特定像素的颜色 (例如:将左上角像素变为纯红色)
    img[0, 0] = [0, 0, 255] # [B, G, R] = [0, 0, 255] 纯红色
    
    # 修改一个像素区域的颜色 (例如:将右上角 50x50 的区域变为纯绿色)
    img[0:50, width-50:width] = [0, 255, 0] # [B, G, R] = [0, 255, 0] 纯绿色
    
    # 显示修改后的图像
    cv2.imshow('Modified Image', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    # 对于灰度图像:
    img_gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    if img_gray is not None:
         # 访问灰度值
         gray_pixel_0_0 = img_gray[0, 0]
         print(f"\n灰度图像左上角像素 (0, 0) 的灰度值: {gray_pixel_0_0}")
    
         # 修改灰度值 (例如:将左上角像素变为白色)
         img_gray[0, 0] = 255 # 0是黑色,255是白色
    
         cv2.imshow('Modified Gray Image', img_gray)
         cv2.waitKey(0)
         cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)

    “`
    通过直接操作 NumPy 数组,我们可以高效地进行像素级别的修改。

  4. 感兴趣区域 (ROI):
    NumPy 的切片功能可以非常方便地提取图像的某个矩形区域,这就是感兴趣区域 (Region of Interest, ROI)。你可以对 ROI 进行独立的操作,而不会影响图像的其他部分。

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

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

    # 定义 ROI 区域 (例如:左上角 100x150 的区域)
    # 注意:切片是 [y_start:y_end, x_start:x_end]
    roi = img[10:160, 20:120] # 高度从10到159,宽度从20到119
    
    # 对 ROI 进行操作 (例如:将 ROI 区域变为纯蓝色)
    roi[:] = [255, 0, 0] # [B, G, R] = [255, 0, 0] 纯蓝色
    
    # 显示修改了 ROI 的图像
    cv2.imshow('Image with Modified ROI', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    # 提取 ROI 并单独显示
    roi_to_show = img[10:160, 20:120] # 再次提取同一个区域来显示
    cv2.imshow('Extracted ROI', roi_to_show)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    ``
    修改 ROI 的像素会直接反映在原图像上,因为 ROI 实际上是原图像的一个视图(引用),而不是一个独立的拷贝。如果需要独立的拷贝,可以使用
    .copy()` 方法。

第五章:颜色空间转换

图像可以表示在不同的颜色空间中。最常见的有:

  • BGR: OpenCV 默认的彩色图像格式,蓝、绿、红三通道。
  • 灰度: 单通道图像,表示像素的亮度信息,值通常在 0-255 之间(0 表示黑色,255 表示白色)。
  • HSV: 色相(Hue)、饱和度(Saturation)、明度(Value)。HSV 空间在颜色分割、基于颜色的目标跟踪等方面非常有用,因为它将颜色信息(H)与亮度信息(V)分离。

OpenCV 提供了 cv2.cvtColor() 函数用于在不同的颜色空间之间进行转换。

python
dst = cv2.cvtColor(src, code)

  • src: 输入图像。
  • code: 颜色空间转换的标志。OpenCV 提供了大量的标志,例如:
    • cv2.COLOR_BGR2GRAY: 将 BGR 图像转换为灰度图像。
    • cv2.COLOR_GRAY2BGR: 将灰度图像转换为 BGR 图像(每个灰度值复制到 BGR 三个通道)。
    • cv2.COLOR_BGR2HSV: 将 BGR 图像转换为 HSV 图像。
    • cv2.COLOR_HSV2BGR: 将 HSV 图像转换为 BGR 图像。
    • 还有很多其他格式的转换(例如 RGB, LAB 等)。

示例代码:

“`python
import cv2
import numpy as np

请替换为您自己的图像文件路径

image_path = ‘path/to/your/image.jpg’

img_color = cv2.imread(image_path, cv2.IMREAD_COLOR)

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)

# 显示原始彩色、灰度、HSV 图像 (HSV 图像直接显示通常看起来怪异,因为它不是为直接显示设计的)
cv2.imshow('Original BGR Image', img_color)
cv2.imshow('Grayscale Image', img_gray)
cv2.imshow('HSV Image', img_hsv) # 显示的HSV图像看起来可能颜色失真,这是正常的

cv2.waitKey(0)
cv2.destroyAllWindows()

# 可以通过分离 HSV 通道来查看各个通道
# H(色相) 通常范围是 0-180 (OpenCV 默认)
# S(饱和度) 通常范围是 0-255
# V(明度) 通常范围是 0-255
h, s, v = cv2.split(img_hsv) # 分离通道,cv2.split() 返回多个灰度图像

cv2.imshow('Hue Channel (H)', h)
cv2.imshow('Saturation Channel (S)', s)
cv2.imshow('Value Channel (V)', v)

cv2.waitKey(0)
cv2.destroyAllWindows()

else:
print(f”错误:无法载入图像文件 {image_path}”)
“`
颜色空间转换是许多图像处理和分析任务的预处理步骤,例如在 HSV 空间中可以更容易地通过阈值分割出特定颜色的物体。

第六章:基本的几何变换

几何变换是改变图像的空间位置或形状的操作,包括缩放、平移、旋转、裁剪等。

  1. 缩放 (cv2.resize):
    改变图像的大小。

    python
    dst = cv2.resize(src, dsize, fx=None, fy=None, interpolation=None)

    • src: 输入图像。
    • dsize: 输出图像的大小元组 (width, height)。如果设置为 None,则需要通过 fxfy 来指定缩放比例。
    • fx, fy: 沿水平和垂直方向的缩放比例。如果 dsize 非空,这两个参数可以省略。
    • interpolation: 插值方法。用于计算新像素值的算法。常用的有:
      • cv2.INTER_AREA: 像素区域关系重采样。缩小时推荐。
      • cv2.INTER_CUBIC: 4×4 像素邻域的立方插值。放大时推荐,速度较慢。
      • cv2.INTER_LINEAR: 双线性插值。默认方法。

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

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

    # 缩放到指定大小 (例如:300x200 像素)
    img_fixed_size = cv2.resize(img, (300, 200), interpolation=cv2.INTER_LINEAR) # (width, height)
    
    cv2.imshow('Original Image', img)
    cv2.imshow('Half Size Image', img_half_size)
    cv2.imshow('Fixed Size Image (300x200)', img_fixed_size)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    “`

  2. 平移:
    将图像沿水平和垂直方向移动。平移需要一个 2×3 的变换矩阵 [[1, 0, tx], [0, 1, ty]],其中 tx 是水平移动距离,ty 是垂直移动距离。然后使用 cv2.warpAffine() 函数进行变换。

    python
    dst = cv2.warpAffine(src, M, dsize)

    • src: 输入图像。
    • M: 2×3 的变换矩阵(NumPy 数组)。
    • dsize: 输出图像的大小元组 (width, height)

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

    if img is not None:
    height, width = img.shape[:2]

    # 定义平移矩阵 M
    tx, ty = 100, 50 # 向右平移100像素,向下平移50像素
    M = np.float32([[1, 0, tx], [0, 1, ty]]) # 2x3 矩阵
    
    # 应用平移变换
    # 输出图像大小与原图相同
    img_translated = cv2.warpAffine(img, M, (width, height))
    
    cv2.imshow('Original Image', img)
    cv2.imshow('Translated Image', img_translated)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    “`

  3. 旋转:
    围绕一个中心点旋转图像。需要先通过 cv2.getRotationMatrix2D() 获取旋转矩阵,再使用 cv2.warpAffine() 进行变换。

    python
    M = cv2.getRotationMatrix2D(center, angle, scale)

    • center: 旋转中心点元组 (x, y)
    • angle: 旋转角度(以度为单位)。正值表示逆时针旋转。
    • scale: 缩放比例。

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

    if img is not None:
    height, width = img.shape[:2]

    # 定义旋转中心 (例如:图像中心)
    center = (width // 2, height // 2)
    
    # 定义旋转角度 (例如:逆时针旋转 45 度) 和缩放比例
    angle = 45
    scale = 1.0
    
    # 获取旋转矩阵
    M = cv2.getRotationMatrix2D(center, angle, scale)
    
    # 应用旋转变换
    # 输出图像大小与原图相同
    img_rotated = cv2.warpAffine(img, M, (width, height))
    
    cv2.imshow('Original Image', img)
    cv2.imshow('Rotated Image (45 degrees)', img_rotated)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    “`
    请注意,旋转后的图像可能会超出原图边界,且背景区域通常填充为黑色。更复杂的旋转(保留完整图像)需要计算新的边界大小,这超出了入门范围。

  4. 裁剪:
    裁剪实际上就是通过 NumPy 的切片功能提取 ROI。

    python
    cropped_img = img[y_start:y_end, x_start:x_end]

    这已经在第四章的 ROI 部分介绍过。

  5. 翻转 (cv2.flip):
    水平或垂直翻转图像。

    python
    dst = cv2.flip(src, flipCode)

    • src: 输入图像。
    • flipCode: 翻转代码:
      • 0: 垂直翻转 (沿 x 轴)。
      • > 0 (通常是 1): 水平翻转 (沿 y 轴)。
      • < 0 (通常是 -1): 同时水平和垂直翻转。

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

    if img is not None:
    # 水平翻转
    img_flipped_horizontally = cv2.flip(img, 1)

    # 垂直翻转
    img_flipped_vertically = cv2.flip(img, 0)
    
    cv2.imshow('Original Image', img)
    cv2.imshow('Flipped Horizontally', img_flipped_horizontally)
    cv2.imshow('Flipped Vertically', img_flipped_vertically)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    “`

第七章:简单的图像滤波与平滑

滤波是图像处理中常用的技术,用于去除噪声、增强特征等。平滑(或模糊)是滤波的一种,通常用于去除图像中的高频噪声。

理解滤波通常需要了解卷积和卷积核(kernel)。卷积核是一个小的矩阵,在图像上滑动,对每个像素及其邻域像素进行加权求和,结果作为该像素位置的新值。不同的卷积核产生不同的滤波效果。

OpenCV 提供了多种滤波函数。这里介绍最简单的一种:高斯模糊。

  1. 高斯模糊 (cv2.GaussianBlur):
    使用高斯函数生成一个卷积核,然后与图像进行卷积,达到平滑效果。高斯模糊是常见的去噪方法,能有效减少高斯噪声。

    python
    dst = cv2.GaussianBlur(src, ksize, sigmaX, sigmaY=None, borderType=None)

    • src: 输入图像。
    • ksize: 高斯核的大小元组 (width, height)。宽度和高度必须是正奇数。例如 (5, 5)
    • sigmaX: 沿 X 方向(水平方向)的高斯核标准差。
    • sigmaY: 沿 Y 方向(垂直方向)的高斯核标准差。如果设置为 0,则 sigmaY 等于 sigmaX。如果都设置为 0,则会根据 ksize 自动计算。建议只指定 ksizesigmaX,让 sigmaY 为 0。
    • borderType (可选): 边界处理模式。

    示例代码:

    “`python
    import cv2
    import numpy as np

    请替换为您自己的图像文件路径

    image_path = ‘path/to/your/image.jpg’

    img = cv2.imread(image_path)

    if img is not None:
    # 应用高斯模糊 (使用 5×5 的核,sigmaX=0)
    img_blurred = cv2.GaussianBlur(img, (5, 5), 0)

    # 应用更强的模糊 (使用 15x15 的核,sigmaX=0)
    img_more_blurred = cv2.GaussianBlur(img, (15, 15), 0)
    
    cv2.imshow('Original Image', img)
    cv2.imshow('Blurred Image (5x5)', img_blurred)
    cv2.imshow('More Blurred Image (15x15)', img_more_blurred)
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    else:
    print(f”错误:无法载入图像文件 {image_path}”)
    “`
    核越大,模糊效果越明显。

第八章:在图像上绘制图形和文本

OpenCV 提供了在图像上绘制点、线、矩形、圆以及添加文本的函数,这在标注图像、可视化处理结果等方面非常有用。这些函数通常会直接修改输入的图像。

绘制函数的一些共同参数:
* img: 要在其上绘制的图像。
* color: 绘制的颜色。对于 BGR 图像,是一个元组 (B, G, R)。对于灰度图像,是一个标量值 (0-255)。
* thickness: 线条或边界的粗细。-1 通常表示填充整个形状。
* lineType (可选): 线条类型,如 cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA (抗锯齿)。

  1. 绘制线条 (cv2.line):
    python
    img = cv2.line(img, pt1, pt2, color, thickness, lineType)

    • pt1: 起点坐标元组 (x, y)
    • pt2: 终点坐标元组 (x, y)
  2. 绘制矩形 (cv2.rectangle):
    python
    img = cv2.rectangle(img, pt1, pt2, color, thickness, lineType)

    • pt1: 矩形左上角坐标元组 (x, y)
    • pt2: 矩形右下角坐标元组 (x, y)
  3. 绘制圆形 (cv2.circle):
    python
    img = cv2.circle(img, center, radius, color, thickness, lineType)

    • center: 圆心坐标元组 (x, y)
    • radius: 圆的半径。
  4. 添加文本 (cv2.putText):
    python
    img = cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin)

    • text: 要添加的文本字符串。
    • org: 文本框的左下角坐标元组 (x, y)
    • fontFace: 字体类型,如 cv2.FONT_HERSHEY_SIMPLEX
    • fontScale: 字体缩放比例。
    • bottomLeftOrigin (可选): 如果为 True,图像数据原点在左下角;否则在左上角。默认为 False (左上角)。

示例代码:

“`python
import cv2
import numpy as np

创建一个空白的黑色图像作为画布 (500×500 像素,3通道 BGR)

np.zeros 创建一个全零的数组

canvas = np.zeros((500, 500, 3), dtype=’uint8′)

1. 绘制一条蓝色的线,从左上角到右下角,粗细为 5 像素

cv2.line(canvas, (0, 0), (500, 500), (255, 0, 0), 5) # BGR: (255, 0, 0) 是蓝色

2. 绘制一个绿色的矩形,从 (100, 50) 到 (400, 450),粗细为 3 像素

cv2.rectangle(canvas, (100, 50), (400, 450), (0, 255, 0), 3) # BGR: (0, 255, 0) 是绿色

3. 绘制一个填充的红色圆形,圆心在 (250, 250),半径为 100 像素

cv2.circle(canvas, (250, 250), 100, (0, 0, 255), -1) # BGR: (0, 0, 255) 是红色, thickness=-1 填充

4. 在图像上添加文本

text = “Hello, OpenCV!”
org = (50, 50) # 文本框左下角坐标
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 1.2
color = (255, 255, 255) # BGR: (255, 255, 255) 是白色
thickness = 2

cv2.putText(canvas, text, org, font, font_scale, color, thickness, cv2.LINE_AA) # 使用抗锯齿线条

显示绘制结果

cv2.imshow(‘Drawing on Canvas’, canvas)

cv2.waitKey(0)
cv2.destroyAllWindows()
“`
通过这些函数,您可以轻松地在图像上添加各种标记和信息。

第九章:简单处理视频

除了静态图像,OpenCV 也提供了处理视频的功能。视频可以被看作是连续的图像帧序列。我们可以逐帧读取视频,对每一帧进行处理,然后显示或保存处理后的视频。

  1. 读取视频 (cv2.VideoCapture):
    用于打开视频文件或摄像头。

    python
    cap = cv2.VideoCapture(source)

    • source: 可以是视频文件的路径(字符串),或者设备的索引号(整数)。例如,0 通常指代默认的内置摄像头,1 指代外接摄像头等。
  2. 读取视频帧 (cap.read):
    从视频流中读取一帧。

    python
    ret, frame = cap.read()

    • ret: 布尔值,如果成功读取帧,则为 True;如果到达视频末尾或发生错误,则为 False
    • frame: 读取到的帧图像(NumPy 数组)。如果 retFalse,则 frameNone
  3. 释放资源 (cap.release):
    完成视频处理后,需要释放 VideoCapture 对象。

    python
    cap.release()

示例代码:读取并显示视频或摄像头画面

“`python
import cv2

指定视频文件路径或摄像头索引号

source = ‘path/to/your/video.mp4’ # 视频文件

source = 0 # 0 表示默认摄像头

创建 VideoCapture 对象

cap = cv2.VideoCapture(source)

检查 VideoCapture 是否成功打开

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

print(“按 ‘q’ 键退出视频播放。”)

while True:
# 逐帧读取
ret, frame = cap.read()

# 如果正确读取帧,则 ret 为 True
if not ret:
    print("无法读取帧或视频已结束。")
    break

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

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

# 显示处理后的帧 (例如:灰度帧)
cv2.imshow('Grayscale Frame', gray_frame)


# 等待按键,每帧等待 25 毫秒 (或根据视频帧率调整)
# 如果按下 'q' 键 (ASCII 码为 113),则退出循环
if cv2.waitKey(25) & 0xFF == ord('q'): # ord('q') 返回字符 'q' 的 ASCII 值
    break

释放 VideoCapture 对象和销毁所有窗口

cap.release()
cv2.destroyAllWindows()
print(“视频播放结束,窗口已关闭。”)
“`
这段代码会打开指定的视频文件或摄像头,然后在一个循环中逐帧读取图像,并显示原始帧和灰度处理后的帧。按下键盘上的 ‘q’ 键可以退出播放。

第十章:超越入门:下一步去哪里?

恭喜您已经掌握了使用 Python 和 OpenCV 进行图像处理的入门基础!这仅仅是冰山一角。OpenCV 提供了极其丰富的功能,可以进行更多高级的图像处理和计算机视觉任务:

  • 更多滤波技术: 中值滤波、双边滤波等,用于处理不同类型的噪声。
  • 边缘检测: Sobel, Scharr, Laplace, Canny 等算法,用于找到图像中的边缘。
  • 形态学操作: 腐蚀、膨胀、开运算、闭运算等,用于处理二值图像(例如去除小噪点或连接断开的区域)。
  • 图像阈值分割: 将图像转换为二值图像(黑白图像),例如简单阈值、自适应阈值、Otsu 阈值等。
  • 轮廓检测与分析: 找到图像中的物体轮廓,并计算轮廓的属性(面积、周长、形状等)。
  • 特征检测与匹配: SIFT, SURF (非免费), ORB, AKAZE 等算法,用于在不同图像中找到相同的物体或特征点。
  • 目标检测: 使用 Haar cascades, HOG + SVM, 或深度学习模型 (如 YOLO, SSD) 来检测图像中的特定物体(如人脸、汽车)。
  • 目标跟踪: 在视频序列中跟踪特定物体。
  • 相机标定与三维重建: 了解相机参数,并从二维图像中恢复三维信息。
  • 机器学习模块: OpenCV 包含一些传统的机器学习算法(如 SVM, K-Means)以及对深度学习框架的支持。

要继续深入学习,您可以:

  1. 查阅官方文档: OpenCV 官方文档 (https://docs.opencv.org/) 是最权威的学习资源,虽然可能需要一些时间来适应其结构。
  2. 参考在线教程和课程: 网上有大量关于 OpenCV 和图像处理的免费和付费教程。
  3. 阅读相关书籍: 有一些优秀的介绍 OpenCV 和图像处理的书籍。
  4. 动手实践: 尝试自己实现一些小的图像处理想法,比如编写一个简单的图片编辑器、一个基本的物体颜色识别程序等。实践是掌握技能的最佳方式。

结论

本文详细介绍了使用 Python 和 OpenCV 进行图像处理的入门知识,包括环境搭建、图像的基本操作、数据表示、颜色空间、几何变换、简单滤波以及视频处理基础。Python 的易用性和 OpenCV 的强大功能相结合,为图像处理领域提供了无限的可能性。

这仅仅是开始。图像处理和计算机视觉是一个广阔而迷人的领域,充满了挑战和机遇。掌握了这些基础,您就已经迈出了坚实的第一步。现在,带着对图像处理的热情,继续探索 OpenCV 的更深层次功能,尝试解决实际问题,构建属于您自己的视觉应用吧!祝您在图像处理的学习旅程中一切顺利!


发表评论

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

滚动至顶部