Python计算机视觉第十章-OpenCV

目录

[10.1 OpenCV的Python接口](#10.1 OpenCV的Python接口)

[10.2 OpenCV基础知识](#10.2 OpenCV基础知识)

10.2.1 读取和写入图像

10.2.2 颜色空间

10.2.3 显示图像及结果

10.3 处理视频

10.3.1 视频输入

10.3.2 将视频读取到NumPy数组中

10.4 跟踪

10.4.1 光流

[10.4.2 Lucas-Kanade算法](#10.4.2 Lucas-Kanade算法)


10.1 OpenCV的Python接口

OpenCV 是一个 C++ 库,它包含了计算机视觉领域的很多模块。除了 C++ 和 C, Python 作为一种简洁的脚本语言,在 C++ 代码基础上的 Python 接口得到了越来越广泛的支持。

OpenCV 2.3.1 版本实际上提供了两个 Python 接口。旧的 cv 模块使用 OpenCV 内部 数据类型,并且从 NumPy 使用起来可能需要一些技巧。新的 cv2 模块用到了 NumPy 数组,并且使用起来更加直观 1 ,可以通过以下方式导入新的 cv2 模块:

import cv2

10.2 OpenCV基础知识

10.2.1 读取和写入图像

载入一张图像,打印出图像大小,对图像进行转换并保存为 .png 格式:

实验代码:

python 复制代码
import cv2

# 读取图像
im = cv2.imread('suiyuan.jpg')

# 获取图像尺寸
h, w = im.shape[:2]
print(h, w)

# 保存图像为 .png 格式
cv2.imwrite('suiyuanresult.png', im)

分析:

  1. 读取图像 :使用 cv2.imread 函数加载图像文件。
  2. 获取尺寸 :通过 im.shape[:2] 获取图像的高度和宽度。
  3. 打印尺寸:输出图像的高度和宽度。
  4. 保存图像 :使用 cv2.imwrite 函数将原图保存为 PNG 格式。

结果:

10.2.2 颜色空间

实验代码:

python 复制代码
import cv2

# 读取图像
im = cv2.imread('suiyuan.jpg')

# 创建灰度图像
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

# 获取原图像尺寸
h, w = im.shape[:2]
print(f'Original Image Size: {h}x{w}')

# 保存灰度图像
cv2.imwrite('gray_image.png', gray)

# 将原图像转换为 RGB 格式
rgb_image = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
cv2.imwrite('result_rgb.png', rgb_image)

分析:

  1. 图像读取 :使用 cv2.imread 函数加载图像文件 "suiyuan.jpg"。
  2. 颜色空间转换
    • 将原图像从 BGR 转换为灰度图像,使用 cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    • 还可以将 BGR 图像转换为 RGB 格式,使用 cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
  3. 打印图像尺寸:输出原图像的高度和宽度。
  4. 保存图像
    • 保存灰度图像为 "gray_image.png"。
    • 保存 RGB 图像为 "result_rgb.png"。

结果:

原图像:

灰度图像:

RGB图像

10.2.3 显示图像及结果

实验代码:

python 复制代码
import cv2

# 读取图像
im = cv2.imread('guimie.jpg')

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

# 计算积分图像
intim = cv2.integral(gray)

# 归一化积分图像并保存
intim_normalized = (255.0 * intim) / intim.max()
cv2.imwrite('result.jpg', intim_normalized)

分析:

  1. 图像读取 :使用 cv2.imread 函数读取图像文件 "guimie.jpg"。
  2. 颜色空间转换 :将图像转换为灰度图像,使用 cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
  3. 计算积分图像 :通过 cv2.integral(gray) 创建积分图像,计算每个像素值为原图左上方所有像素强度的和,这在特征评估中非常有效。
  4. 归一化和保存 :将积分图像归一化到 0-255 范围,并使用 cv2.imwrite 保存为 "result.jpg"。

结果:

10.3 处理视频

10.3.1 视频输入

实验代码:

python 复制代码
import cv2

# 打开视频文件
cap = cv2.VideoCapture('wanjia.mp4')

# 获取视频的宽度和高度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 定义视频编码和输出文件
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output_video.avi', fourcc, 20.0, (frame_width, frame_height))

while True:
    ret, frame = cap.read()
    if not ret:
        break  # 如果没有读取到帧,结束循环

    # 在帧上添加文本
    cv2.putText(frame, 'Video Output Experiment', (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)

    # 写入输出视频
    out.write(frame)

    # 显示当前帧
    cv2.imshow('Video', frame)

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

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

分析:

  1. 视频读取 :使用 cv2.VideoCapture 打开视频文件。
  2. 获取视频信息 :通过 get 方法获取视频的宽度和高度。
  3. 视频输出设置 :使用 cv2.VideoWriter 定义输出视频文件,设置编码方式、帧率和帧大小。
  4. 处理每一帧
    • 在每帧上添加文本,使用 cv2.putText
    • 将处理后的帧写入输出视频。
    • 实时显示当前帧。
  5. 退出条件:用户可以按 'q' 键退出视频播放。
  6. 资源释放:在结束时释放视频捕获和写入资源,并关闭所有窗口。

结果:

10.3.2 将视频读取到NumPy数组中

实验代码:

python 复制代码
import cv2
import numpy as np

# 打开视频文件
cap = cv2.VideoCapture('wanjia.mp4')

# 创建一个空的列表来存储视频帧
frames = []

# 读取视频帧
while True:
    ret, frame = cap.read()
    if not ret:
        break  # 如果没有读取到帧,结束循环

    # 将帧添加到列表中
    frames.append(frame)

# 关闭视频文件
cap.release()

# 将列表转换为 NumPy 数组
video_array = np.array(frames)

# 打印视频数组的形状
print("视频数组形状:", video_array.shape)

# 可选:显示第一帧
cv2.imshow('First Frame', video_array[0])
cv2.waitKey(0)
cv2.destroyAllWindows()

分析:

  1. 打开视频文件 :使用 cv2.VideoCapture 打开指定的视频文件。
  2. 读取视频帧 :通过循环读取视频中的每一帧,使用 cap.read()
    • 如果读取成功,retTrueframe 为当前帧。
    • 将每一帧添加到 frames 列表中。
  3. 释放资源 :在读取完视频后,调用 cap.release() 释放视频文件。
  4. 转换为 NumPy 数组 :使用 np.array(frames) 将帧列表转换为 NumPy 数组。
  5. 打印形状 :输出视频数组的形状,可以看到数组的维度,形状为 (帧数, 高度, 宽度, 通道数)
  6. 显示第一帧:可选地展示第一帧,确保读取成功。

结果:

10.4 跟踪

10.4.1 光流

光流是目标、场景或摄像机在连续两帧图像间运动时造成的目标的运动。它是图像在平移过程中的二维矢量场。

光流法主要依赖于三个假设。
(1) 亮度恒定  图像中目标的像素强度在连续帧之间不会发生变化。
(2) 时间规律  相邻帧之间的时间足够短,以至于在考虑运行变化时可以忽略它们之间的差异。该假设用于导出下面的核心方程。
(3) 空间一致性  相邻像素具有相似的运动。
实验代码:

python 复制代码
import cv2
import numpy as np

def draw_flow(im, flow, step=16):
    """ 在间隔分开的像素采样点处绘制光流 """
    h, w = im.shape[:2]
    y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2, -1)
    fx, fy = flow[y.astype(int), x.astype(int)].T
    # 创建线的终点
    lines = np.vstack([x, y, x + fx, y + fy]).T.reshape(-1, 2, 2)
    lines = lines.astype(int)
    # 创建图像并绘制
    vis = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
    for (x1, y1), (x2, y2) in lines:
        cv2.line(vis, (x1, y1), (x2, y2), (0, 255, 0), 1)
        cv2.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
    return vis

# 设置视频捕获
cap = cv2.VideoCapture(0)

# 读取第一帧
ret, im = cap.read()
if not ret:
    print("无法读取视频流")
    exit()

prev_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

while True:
    # 获取灰度图像
    ret, im = cap.read()
    if not ret:
        break

    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

    # 计算光流
    flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
    prev_gray = gray

    # 画出光流
    cv2.imshow('Optical Flow', draw_flow(gray, flow))

    if cv2.waitKey(10) == 27:  # 按 'ESC' 退出
        break

cap.release()
cv2.destroyAllWindows()

分析:

  1. 引入库

    • cv2 用于计算机视觉处理。
    • numpy 用于处理数组和矩阵。
  2. 函数 draw_flow

    • 输入图像和光流数据,在采样点处绘制光流矢量。
    • 通过 np.mgrid 生成采样点,并利用光流计算终点。
    • 绘制线条和圆点以可视化流动。
  3. 视频捕获

    • 使用 cv2.VideoCapture 捕获视频流。
    • 读取第一帧并转换为灰度图。
  4. 光流计算

    • 在循环中读取新帧,计算光流并更新前一帧的灰度图。
    • 调用 draw_flow 函数可视化光流。
  5. 退出条件

    • 通过按 ESC 键退出循环,并释放视频捕获资源

结果:

10.4.2 Lucas-Kanade算法

跟踪最基本的形式是跟随感兴趣点,比如角点。对此,一次流行的算法是 Lucas-Kanade 跟踪算法,它利用了稀疏光流算法。

实验代码:

python 复制代码
import cv2
import numpy as np

def lucas_kanade_optical_flow(video_path):
    cap = cv2.VideoCapture(video_path)

    ret, old_frame = cap.read()
    if not ret:
        print("无法读取视频")
        return

    old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
    p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)

    mask = np.zeros_like(old_frame)

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

        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None)

        # 检查 p1 是否为 None
        if p1 is None or st is None:
            print("光流计算失败")
            break

        good_new = p1[st[:, 0] == 1]  # 注意这里的索引
        good_old = p0[st[:, 0] == 1]

        for i, (new, old) in enumerate(zip(good_new, good_old)):
            a, b = map(int, new.ravel())
            c, d = map(int, old.ravel())
            mask = cv2.line(mask, (a, b), (c, d), (0, 255, 0), 2)
            frame = cv2.circle(frame, (a, b), 5, (0, 0, 255), -1)

        img = cv2.add(frame, mask)
        cv2.imshow('Optical Flow', img)

        old_gray = frame_gray.copy()
        p0 = good_new.reshape(-1, 1, 2)

        if cv2.waitKey(30) & 0xFF == 27:
            break

    cap.release()
    cv2.destroyAllWindows()

# 调用函数
video_path = 'wanjia.mp4'  # 替换为你的视频路径
lucas_kanade_optical_flow(video_path)

分析:

  1. 光流原理

    • Lucas-Kanade 算法基于局部平滑性假设和亮度恒定性假设,利用图像的亮度变化来估计光流场。算法通过对邻域内的像素点进行线性最小二乘拟合,得到物体的运动信息。
  2. 参数设置

    • maxCorners:检测到的最大角点数量。
    • qualityLevel:角点质量的最小阈值。
    • minDistance:检测角点之间的最小距离。

结果:

  1. 运行代码后,将打开一个窗口,显示视频中物体的跟踪效果。

  2. 绿色线条表示跟踪的运动轨迹,红色圆点表示当前跟踪的角点。

相关推荐
好喜欢吃红柚子几秒前
万字长文解读空间、通道注意力机制机制和超详细代码逐行分析(SE,CBAM,SGE,CA,ECA,TA)
人工智能·pytorch·python·计算机视觉·cnn
小馒头学python4 分钟前
机器学习是什么?AIGC又是什么?机器学习与AIGC未来科技的双引擎
人工智能·python·机器学习
神奇夜光杯14 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
plmm烟酒僧18 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
千天夜26 分钟前
使用UDP协议传输视频流!(分片、缓存)
python·网络协议·udp·视频流
测试界的酸菜鱼29 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
羊小猪~~33 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
AI小杨34 分钟前
【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程
人工智能·opencv·计算机视觉·霍夫变换·车道线检测
放飞自我的Coder1 小时前
【python ROUGE BLEU jiaba.cut NLP常用的指标计算】
python·自然语言处理·bleu·rouge·jieba分词
正义的彬彬侠1 小时前
【scikit-learn 1.2版本后】sklearn.datasets中load_boston报错 使用 fetch_openml 函数来加载波士顿房价
python·机器学习·sklearn