活动公告

系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

使用OpenCV实现高效视频输出的完整指南从基础配置到高级应用技巧助您轻松掌握计算机视觉视频处理核心技术

SunJu_FaceMall

3万

主题

2697

科技点

3万

积分

执行版主

碾压王

积分
32881

塔罗立华奏

执行版主 发表于 2025-8-30 12:20:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,它提供了丰富的图像和视频处理功能。在当今数字化时代,视频处理技术已经广泛应用于安防监控、自动驾驶、医疗影像、视频编辑等多个领域。本文将带您深入了解如何使用OpenCV实现高效的视频输出,从基础配置到高级应用技巧,帮助您掌握计算机视觉视频处理的核心技术。

1. OpenCV基础配置

1.1 安装OpenCV

在开始使用OpenCV之前,我们需要先安装它。OpenCV支持多种操作系统,包括Windows、Linux和macOS。
  1. # 使用pip安装OpenCV
  2. pip install opencv-python
  3. pip install opencv-python-headless  # 无GUI版本
  4. # 如果需要额外的模块(如contrib模块)
  5. pip install opencv-contrib-python
复制代码
  1. # 在Ubuntu/Debian系统上
  2. sudo apt-get update
  3. sudo apt-get install python3-opencv
  4. # 或者使用pip
  5. pip3 install opencv-python
复制代码
  1. # 使用Homebrew安装
  2. brew install opencv
  3. # 或者使用pip
  4. pip install opencv-python
复制代码

1.2 验证安装

安装完成后,我们可以通过以下Python代码验证OpenCV是否安装成功:
  1. import cv2
  2. import numpy as np
  3. # 打印OpenCV版本
  4. print("OpenCV版本:", cv2.__version__)
  5. # 创建一个简单的图像并显示
  6. image = np.zeros((300, 400, 3), dtype=np.uint8)
  7. cv2.putText(image, "OpenCV is working!", (50, 150),
  8.             cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
  9. cv2.imshow("Test Image", image)
  10. cv2.waitKey(0)
  11. cv2.destroyAllWindows()
复制代码

如果成功显示一个黑色背景上有绿色文字的窗口,说明OpenCV已正确安装。

1.3 配置开发环境

为了更高效地开发OpenCV应用,建议配置一个合适的开发环境:

1. IDE选择:PyCharm、Visual Studio Code或Jupyter Notebook都是不错的选择
2. 虚拟环境:使用venv或conda创建独立的Python环境
3. 版本控制:使用Git管理代码版本
  1. # 创建虚拟环境示例
  2. python -m venv opencv_env
  3. source opencv_env/bin/activate  # Linux/macOS
  4. # 或
  5. opencv_env\Scripts\activate  # Windows
  6. # 安装所需包
  7. pip install opencv-python numpy matplotlib
复制代码

2. 视频处理基础

2.1 读取视频文件

OpenCV提供了VideoCapture类来读取视频文件或摄像头捕获的视频流。
  1. import cv2
  2. # 从视频文件读取
  3. cap = cv2.VideoCapture('input_video.mp4')
  4. # 检查视频是否成功打开
  5. if not cap.isOpened():
  6.     print("无法打开视频文件")
  7.     exit()
  8. # 获取视频属性
  9. frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  10. frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  11. fps = cap.get(cv2.CAP_PROP_FPS)
  12. frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
  13. print(f"视频尺寸: {frame_width}x{frame_height}")
  14. print(f"视频帧率: {fps}")
  15. print(f"总帧数: {frame_count}")
  16. # 读取视频帧
  17. while True:
  18.     ret, frame = cap.read()
  19.    
  20.     # 如果正确读取帧,ret为True
  21.     if not ret:
  22.         print("视频结束或无法读取帧")
  23.         break
  24.    
  25.     # 显示帧
  26.     cv2.imshow('Video', frame)
  27.    
  28.     # 按'q'键退出
  29.     if cv2.waitKey(25) & 0xFF == ord('q'):
  30.         break
  31. # 释放资源
  32. cap.release()
  33. cv2.destroyAllWindows()
复制代码

2.2 从摄像头捕获视频
  1. import cv2
  2. # 创建VideoCapture对象,参数0表示默认摄像头
  3. cap = cv2.VideoCapture(0)
  4. # 检查摄像头是否成功打开
  5. if not cap.isOpened():
  6.     print("无法打开摄像头")
  7.     exit()
  8. # 设置摄像头分辨率
  9. cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
  10. cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
  11. while True:
  12.     # 逐帧捕获
  13.     ret, frame = cap.read()
  14.    
  15.     if not ret:
  16.         print("无法获取帧")
  17.         break
  18.    
  19.     # 显示结果帧
  20.     cv2.imshow('Camera', frame)
  21.    
  22.     # 按'q'键退出
  23.     if cv2.waitKey(1) & 0xFF == ord('q'):
  24.         break
  25. # 释放资源
  26. cap.release()
  27. cv2.destroyAllWindows()
复制代码

2.3 保存视频文件

使用VideoWriter类可以将处理后的视频保存到文件。
  1. import cv2
  2. # 打开视频文件
  3. cap = cv2.VideoCapture('input_video.mp4')
  4. # 检查视频是否成功打开
  5. if not cap.isOpened():
  6.     print("无法打开视频文件")
  7.     exit()
  8. # 获取视频属性
  9. frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  10. frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  11. fps = cap.get(cv2.CAP_PROP_FPS)
  12. # 定义编码器并创建VideoWriter对象
  13. # 四字符代码(FourCC)用于指定视频编解码器
  14. fourcc = cv2.VideoWriter_fourcc(*'XVID')
  15. out = cv2.VideoWriter('output_video.avi', fourcc, fps, (frame_width, frame_height))
  16. while True:
  17.     ret, frame = cap.read()
  18.    
  19.     if not ret:
  20.         break
  21.    
  22.     # 在这里可以对帧进行处理
  23.     # 例如:转换为灰度图
  24.     gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  25.     # 转回BGR格式以便保存为彩色视频
  26.     gray_frame_bgr = cv2.cvtColor(gray_frame, cv2.COLOR_GRAY2BGR)
  27.    
  28.     # 写入帧
  29.     out.write(gray_frame_bgr)
  30.    
  31.     # 显示帧
  32.     cv2.imshow('Original', frame)
  33.     cv2.imshow('Processed', gray_frame)
  34.    
  35.     if cv2.waitKey(25) & 0xFF == ord('q'):
  36.         break
  37. # 释放资源
  38. cap.release()
  39. out.release()
  40. cv2.destroyAllWindows()
复制代码

2.4 视频编解码器选择

不同的视频编解码器适用于不同的场景。以下是常见的FourCC代码及其用途:
  1. # 常见的FourCC代码
  2. fourcc_dict = {
  3.     'XVID': 'XVID MPEG-4编码',
  4.     'MP4V': 'MPEG-4编码',
  5.     'H264': 'H.264编码',
  6.     'MJPG': 'Motion JPEG编码',
  7.     'DIVX': 'DivX MPEG-4编码',
  8.     'X264': 'X264编码',
  9.     'WMV1': 'Windows Media Video 7',
  10.     'WMV2': 'Windows Media Video 8'
  11. }
  12. # 使用示例
  13. def save_with_different_codecs(input_path, output_dir):
  14.     cap = cv2.VideoCapture(input_path)
  15.    
  16.     if not cap.isOpened():
  17.         print("无法打开视频文件")
  18.         return
  19.    
  20.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  21.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  22.     fps = cap.get(cv2.CAP_PROP_FPS)
  23.    
  24.     # 创建输出目录
  25.     import os
  26.     os.makedirs(output_dir, exist_ok=True)
  27.    
  28.     # 使用不同的编码器保存视频
  29.     for codec, description in fourcc_dict.items():
  30.         fourcc = cv2.VideoWriter_fourcc(*codec)
  31.         output_path = f"{output_dir}/output_{codec}.avi"
  32.         out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
  33.         
  34.         # 重置视频位置到开始
  35.         cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
  36.         
  37.         while True:
  38.             ret, frame = cap.read()
  39.             if not ret:
  40.                 break
  41.             out.write(frame)
  42.         
  43.         out.release()
  44.         print(f"已使用{description}保存视频到 {output_path}")
  45.    
  46.     cap.release()
  47. # 调用函数
  48. # save_with_different_codecs('input_video.mp4', 'output_videos')
复制代码

3. 视频处理高级技巧

3.1 帧操作与处理

视频是由一系列连续的图像帧组成的,对视频的处理本质上是对每一帧图像的处理。

帧差分法是一种简单的运动检测方法,通过比较连续帧之间的差异来检测运动。
  1. import cv2
  2. import numpy as np
  3. def frame_difference_detection(video_path):
  4.     cap = cv2.VideoCapture(video_path)
  5.    
  6.     if not cap.isOpened():
  7.         print("无法打开视频文件")
  8.         return
  9.    
  10.     # 读取第一帧
  11.     ret, prev_frame = cap.read()
  12.     if not ret:
  13.         print("无法读取视频帧")
  14.         return
  15.    
  16.     # 转换为灰度图
  17.     prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
  18.     prev_gray = cv2.GaussianBlur(prev_gray, (5, 5), 0)
  19.    
  20.     while True:
  21.         ret, curr_frame = cap.read()
  22.         if not ret:
  23.             break
  24.         
  25.         # 转换为灰度图并模糊处理
  26.         curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)
  27.         curr_gray = cv2.GaussianBlur(curr_gray, (5, 5), 0)
  28.         
  29.         # 计算帧差
  30.         diff = cv2.absdiff(prev_gray, curr_gray)
  31.         
  32.         # 阈值处理
  33.         thresh = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)[1]
  34.         
  35.         # 膨胀操作,连接相近的区域
  36.         thresh = cv2.dilate(thresh, None, iterations=2)
  37.         
  38.         # 查找轮廓
  39.         contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  40.         
  41.         # 在原始帧上绘制检测到的运动区域
  42.         for contour in contours:
  43.             if cv2.contourArea(contour) > 500:  # 过滤小区域
  44.                 (x, y, w, h) = cv2.boundingRect(contour)
  45.                 cv2.rectangle(curr_frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
  46.         
  47.         # 显示结果
  48.         cv2.imshow("Motion Detection", curr_frame)
  49.         cv2.imshow("Difference", thresh)
  50.         
  51.         # 更新前一帧
  52.         prev_gray = curr_gray
  53.         
  54.         # 按'q'键退出
  55.         if cv2.waitKey(25) & 0xFF == ord('q'):
  56.             break
  57.    
  58.     cap.release()
  59.     cv2.destroyAllWindows()
  60. # 调用函数
  61. # frame_difference_detection('input_video.mp4')
复制代码

背景减除法是一种更高级的运动检测方法,它通过建立背景模型并与当前帧比较来检测前景对象。
  1. import cv2
  2. import numpy as np
  3. def background_subtraction(video_path):
  4.     cap = cv2.VideoCapture(video_path)
  5.    
  6.     if not cap.isOpened():
  7.         print("无法打开视频文件")
  8.         return
  9.    
  10.     # 创建背景减除器
  11.     # 可选:cv2.createBackgroundSubtractorMOG2() 或 cv2.createBackgroundSubtractorKNN()
  12.     back_sub = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)
  13.    
  14.     while True:
  15.         ret, frame = cap.read()
  16.         if not ret:
  17.             break
  18.         
  19.         # 应用背景减除器
  20.         fg_mask = back_sub.apply(frame)
  21.         
  22.         # 对前景掩码进行形态学操作,去除噪声
  23.         kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
  24.         fg_mask = cv2.morphologyEx(fg_mask, cv2.MORPH_OPEN, kernel)
  25.         
  26.         # 查找轮廓
  27.         contours, _ = cv2.findContours(fg_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  28.         
  29.         # 在原始帧上绘制检测到的运动对象
  30.         for contour in contours:
  31.             if cv2.contourArea(contour) > 500:  # 过滤小区域
  32.                 (x, y, w, h) = cv2.boundingRect(contour)
  33.                 cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
  34.         
  35.         # 显示结果
  36.         cv2.imshow("Original", frame)
  37.         cv2.imshow("Foreground Mask", fg_mask)
  38.         
  39.         # 按'q'键退出
  40.         if cv2.waitKey(25) & 0xFF == ord('q'):
  41.             break
  42.    
  43.     cap.release()
  44.     cv2.destroyAllWindows()
  45. # 调用函数
  46. # background_subtraction('input_video.mp4')
复制代码

3.2 视频增强技术

视频增强技术可以改善视频质量,提高视觉体验或为后续处理提供更好的输入。
  1. import cv2
  2. import numpy as np
  3. def adjust_brightness_contrast(video_path, alpha=1.0, beta=0):
  4.     """
  5.     调整视频的亮度和对比度
  6.     :param video_path: 输入视频路径
  7.     :param alpha: 对比度控制(1.0-3.0)
  8.     :param beta: 亮度控制(0-100)
  9.     """
  10.     cap = cv2.VideoCapture(video_path)
  11.    
  12.     if not cap.isOpened():
  13.         print("无法打开视频文件")
  14.         return
  15.    
  16.     # 获取视频属性
  17.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  18.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  19.     fps = cap.get(cv2.CAP_PROP_FPS)
  20.    
  21.     # 创建视频写入对象
  22.     fourcc = cv2.VideoWriter_fourcc(*'XVID')
  23.     out = cv2.VideoWriter('brightness_contrast_adjusted.avi', fourcc, fps, (frame_width, frame_height))
  24.    
  25.     while True:
  26.         ret, frame = cap.read()
  27.         if not ret:
  28.             break
  29.         
  30.         # 调整亮度和对比度
  31.         # new_image = alpha * original_image + beta
  32.         adjusted = cv2.convertScaleAbs(frame, alpha=alpha, beta=beta)
  33.         
  34.         # 写入帧
  35.         out.write(adjusted)
  36.         
  37.         # 显示结果
  38.         cv2.imshow("Original", frame)
  39.         cv2.imshow("Adjusted", adjusted)
  40.         
  41.         # 按'q'键退出
  42.         if cv2.waitKey(25) & 0xFF == ord('q'):
  43.             break
  44.    
  45.     cap.release()
  46.     out.release()
  47.     cv2.destroyAllWindows()
  48. # 调用函数示例
  49. # adjust_brightness_contrast('input_video.mp4', alpha=1.5, beta=30)
复制代码

直方图均衡化可以增强图像的对比度,特别适用于曝光不足或过度的图像。
  1. import cv2
  2. import numpy as np
  3. def histogram_equalization(video_path):
  4.     cap = cv2.VideoCapture(video_path)
  5.    
  6.     if not cap.isOpened():
  7.         print("无法打开视频文件")
  8.         return
  9.    
  10.     # 获取视频属性
  11.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  12.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  13.     fps = cap.get(cv2.CAP_PROP_FPS)
  14.    
  15.     # 创建视频写入对象
  16.     fourcc = cv2.VideoWriter_fourcc(*'XVID')
  17.     out = cv2.VideoWriter('histogram_equalized.avi', fourcc, fps, (frame_width, frame_height))
  18.    
  19.     while True:
  20.         ret, frame = cap.read()
  21.         if not ret:
  22.             break
  23.         
  24.         # 转换为YUV颜色空间
  25.         yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV)
  26.         
  27.         # 对Y通道进行直方图均衡化
  28.         yuv[:,:,0] = cv2.equalizeHist(yuv[:,:,0])
  29.         
  30.         # 转换回BGR颜色空间
  31.         equalized = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR)
  32.         
  33.         # 写入帧
  34.         out.write(equalized)
  35.         
  36.         # 显示结果
  37.         cv2.imshow("Original", frame)
  38.         cv2.imshow("Equalized", equalized)
  39.         
  40.         # 按'q'键退出
  41.         if cv2.waitKey(25) & 0xFF == ord('q'):
  42.             break
  43.    
  44.     cap.release()
  45.     out.release()
  46.     cv2.destroyAllWindows()
  47. # 调用函数
  48. # histogram_equalization('input_video.mp4')
复制代码

3.3 视频特效处理
  1. import cv2
  2. import numpy as np
  3. def blur_and_sharpen(video_path):
  4.     cap = cv2.VideoCapture(video_path)
  5.    
  6.     if not cap.isOpened():
  7.         print("无法打开视频文件")
  8.         return
  9.    
  10.     # 获取视频属性
  11.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  12.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  13.     fps = cap.get(cv2.CAP_PROP_FPS)
  14.    
  15.     # 创建视频写入对象
  16.     fourcc = cv2.VideoWriter_fourcc(*'XVID')
  17.     out_blur = cv2.VideoWriter('blurred_video.avi', fourcc, fps, (frame_width, frame_height))
  18.     out_sharpen = cv2.VideoWriter('sharpened_video.avi', fourcc, fps, (frame_width, frame_height))
  19.    
  20.     # 创建锐化核
  21.     sharpen_kernel = np.array([[-1, -1, -1],
  22.                               [-1,  9, -1],
  23.                               [-1, -1, -1]])
  24.    
  25.     while True:
  26.         ret, frame = cap.read()
  27.         if not ret:
  28.             break
  29.         
  30.         # 模糊处理
  31.         blurred = cv2.GaussianBlur(frame, (15, 15), 0)
  32.         
  33.         # 锐化处理
  34.         sharpened = cv2.filter2D(frame, -1, sharpen_kernel)
  35.         
  36.         # 写入帧
  37.         out_blur.write(blurred)
  38.         out_sharpen.write(sharpened)
  39.         
  40.         # 显示结果
  41.         cv2.imshow("Original", frame)
  42.         cv2.imshow("Blurred", blurred)
  43.         cv2.imshow("Sharpened", sharpened)
  44.         
  45.         # 按'q'键退出
  46.         if cv2.waitKey(25) & 0xFF == ord('q'):
  47.             break
  48.    
  49.     cap.release()
  50.     out_blur.release()
  51.     out_sharpen.release()
  52.     cv2.destroyAllWindows()
  53. # 调用函数
  54. # blur_and_sharpen('input_video.mp4')
复制代码
  1. import cv2
  2. import numpy as np
  3. def edge_detection(video_path):
  4.     cap = cv2.VideoCapture(video_path)
  5.    
  6.     if not cap.isOpened():
  7.         print("无法打开视频文件")
  8.         return
  9.    
  10.     # 获取视频属性
  11.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  12.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  13.     fps = cap.get(cv2.CAP_PROP_FPS)
  14.    
  15.     # 创建视频写入对象
  16.     fourcc = cv2.VideoWriter_fourcc(*'XVID')
  17.     out_canny = cv2.VideoWriter('canny_edges.avi', fourcc, fps, (frame_width, frame_height))
  18.    
  19.     while True:
  20.         ret, frame = cap.read()
  21.         if not ret:
  22.             break
  23.         
  24.         # 转换为灰度图
  25.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  26.         
  27.         # Canny边缘检测
  28.         edges = cv2.Canny(gray, 100, 200)
  29.         
  30.         # 转换回BGR格式以便保存为彩色视频
  31.         edges_bgr = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
  32.         
  33.         # 写入帧
  34.         out_canny.write(edges_bgr)
  35.         
  36.         # 显示结果
  37.         cv2.imshow("Original", frame)
  38.         cv2.imshow("Canny Edges", edges)
  39.         
  40.         # 按'q'键退出
  41.         if cv2.waitKey(25) & 0xFF == ord('q'):
  42.             break
  43.    
  44.     cap.release()
  45.     out_canny.release()
  46.     cv2.destroyAllWindows()
  47. # 调用函数
  48. # edge_detection('input_video.mp4')
复制代码

4. 性能优化

4.1 多线程处理

视频处理通常是计算密集型任务,使用多线程可以显著提高处理速度。
  1. import cv2
  2. import numpy as np
  3. import threading
  4. import queue
  5. import time
  6. class VideoProcessor:
  7.     def __init__(self, video_path, output_path):
  8.         self.video_path = video_path
  9.         self.output_path = output_path
  10.         self.frame_queue = queue.Queue(maxsize=10)
  11.         self.result_queue = queue.Queue(maxsize=10)
  12.         self.stop_event = threading.Event()
  13.         
  14.     def read_frames(self):
  15.         """读取视频帧并放入队列"""
  16.         cap = cv2.VideoCapture(self.video_path)
  17.         
  18.         if not cap.isOpened():
  19.             print("无法打开视频文件")
  20.             self.stop_event.set()
  21.             return
  22.         
  23.         while not self.stop_event.is_set():
  24.             ret, frame = cap.read()
  25.             if not ret:
  26.                 break
  27.             
  28.             # 如果队列已满,等待
  29.             while self.frame_queue.full() and not self.stop_event.is_set():
  30.                 time.sleep(0.01)
  31.             
  32.             if not self.stop_event.is_set():
  33.                 self.frame_queue.put(frame)
  34.         
  35.         cap.release()
  36.         print("帧读取完成")
  37.         
  38.     def process_frames(self):
  39.         """处理视频帧"""
  40.         while not self.stop_event.is_set() or not self.frame_queue.empty():
  41.             # 如果队列为空,等待
  42.             while self.frame_queue.empty() and not self.stop_event.is_set():
  43.                 time.sleep(0.01)
  44.             
  45.             if not self.frame_queue.empty():
  46.                 frame = self.frame_queue.get()
  47.                
  48.                 # 在这里进行帧处理
  49.                 # 示例:转换为灰度图
  50.                 processed_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  51.                 processed_frame = cv2.cvtColor(processed_frame, cv2.COLOR_GRAY2BGR)
  52.                
  53.                 # 如果结果队列已满,等待
  54.                 while self.result_queue.full() and not self.stop_event.is_set():
  55.                     time.sleep(0.01)
  56.                
  57.                 if not self.stop_event.is_set():
  58.                     self.result_queue.put(processed_frame)
  59.         
  60.         print("帧处理完成")
  61.         
  62.     def write_frames(self):
  63.         """写入处理后的帧"""
  64.         # 获取第一帧以确定视频属性
  65.         if self.frame_queue.empty():
  66.             time.sleep(0.1)
  67.             if self.frame_queue.empty():
  68.                 print("无法获取帧信息")
  69.                 self.stop_event.set()
  70.                 return
  71.         
  72.         # 获取视频属性
  73.         first_frame = self.frame_queue.queue[0]
  74.         frame_height, frame_width = first_frame.shape[:2]
  75.         fps = 30  # 假设帧率为30
  76.         
  77.         # 创建视频写入对象
  78.         fourcc = cv2.VideoWriter_fourcc(*'XVID')
  79.         out = cv2.VideoWriter(self.output_path, fourcc, fps, (frame_width, frame_height))
  80.         
  81.         while not self.stop_event.is_set() or not self.result_queue.empty():
  82.             # 如果结果队列为空,等待
  83.             while self.result_queue.empty() and not self.stop_event.is_set():
  84.                 time.sleep(0.01)
  85.             
  86.             if not self.result_queue.empty():
  87.                 frame = self.result_queue.get()
  88.                 out.write(frame)
  89.         
  90.         out.release()
  91.         print("帧写入完成")
  92.         
  93.     def run(self):
  94.         """运行多线程视频处理"""
  95.         # 创建并启动线程
  96.         read_thread = threading.Thread(target=self.read_frames)
  97.         process_thread = threading.Thread(target=self.process_frames)
  98.         write_thread = threading.Thread(target=self.write_frames)
  99.         
  100.         read_thread.start()
  101.         process_thread.start()
  102.         write_thread.start()
  103.         
  104.         # 等待线程完成
  105.         read_thread.join()
  106.         process_thread.join()
  107.         write_thread.join()
  108.         
  109.         print("视频处理完成")
  110. # 使用示例
  111. # processor = VideoProcessor('input_video.mp4', 'output_threaded.avi')
  112. # processor.run()
复制代码

4.2 GPU加速

OpenCV支持使用CUDA进行GPU加速,可以显著提高视频处理速度。
  1. import cv2
  2. import numpy as np
  3. import time
  4. def gpu_accelerated_processing(video_path, output_path):
  5.     # 检查CUDA是否可用
  6.     if cv2.cuda.getCudaEnabledDeviceCount() == 0:
  7.         print("CUDA不可用,将使用CPU处理")
  8.         use_gpu = False
  9.     else:
  10.         print("CUDA可用,将使用GPU加速")
  11.         use_gpu = True
  12.    
  13.     cap = cv2.VideoCapture(video_path)
  14.    
  15.     if not cap.isOpened():
  16.         print("无法打开视频文件")
  17.         return
  18.    
  19.     # 获取视频属性
  20.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  21.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  22.     fps = cap.get(cv2.CAP_PROP_FPS)
  23.    
  24.     # 创建视频写入对象
  25.     fourcc = cv2.VideoWriter_fourcc(*'XVID')
  26.     out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
  27.    
  28.     # 记录开始时间
  29.     start_time = time.time()
  30.     frame_count = 0
  31.    
  32.     while True:
  33.         ret, frame = cap.read()
  34.         if not ret:
  35.             break
  36.         
  37.         frame_count += 1
  38.         
  39.         if use_gpu:
  40.             # 上传帧到GPU
  41.             gpu_frame = cv2.cuda_GpuMat()
  42.             gpu_frame.upload(frame)
  43.             
  44.             # 在GPU上转换为灰度图
  45.             gpu_gray = cv2.cuda.cvtColor(gpu_frame, cv2.COLOR_BGR2GRAY)
  46.             
  47.             # 在GPU上进行高斯模糊
  48.             gpu_blur = cv2.cuda.GpuMat()
  49.             gpu_blur = cv2.cuda.GaussianBlur(gpu_gray, (15, 15), 0)
  50.             
  51.             # 在GPU上进行Canny边缘检测
  52.             gpu_edges = cv2.cuda.GpuMat()
  53.             gpu_edges = cv2.cuda.Canny(gpu_blur, 50, 150)
  54.             
  55.             # 下载结果到CPU
  56.             edges = gpu_edges.download()
  57.             
  58.             # 转换回BGR格式
  59.             edges_bgr = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
  60.         else:
  61.             # CPU处理
  62.             gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  63.             blur = cv2.GaussianBlur(gray, (15, 15), 0)
  64.             edges = cv2.Canny(blur, 50, 150)
  65.             edges_bgr = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
  66.         
  67.         # 写入帧
  68.         out.write(edges_bgr)
  69.         
  70.         # 显示结果
  71.         cv2.imshow("Edges", edges_bgr)
  72.         
  73.         # 按'q'键退出
  74.         if cv2.waitKey(1) & 0xFF == ord('q'):
  75.             break
  76.    
  77.     # 计算处理时间
  78.     end_time = time.time()
  79.     processing_time = end_time - start_time
  80.    
  81.     # 计算并显示FPS
  82.     if frame_count > 0:
  83.         actual_fps = frame_count / processing_time
  84.         print(f"处理了 {frame_count} 帧")
  85.         print(f"总处理时间: {processing_time:.2f} 秒")
  86.         print(f"平均处理速度: {actual_fps:.2f} FPS")
  87.         print(f"使用GPU: {use_gpu}")
  88.    
  89.     cap.release()
  90.     out.release()
  91.     cv2.destroyAllWindows()
  92. # 使用示例
  93. # gpu_accelerated_processing('input_video.mp4', 'output_gpu.avi')
复制代码

4.3 使用FFmpeg进行高效视频编码

OpenCV的VideoWriter虽然方便,但在某些情况下可能不如FFmpeg高效。我们可以通过FFmpeg实现更高效的视频编码。
  1. import cv2
  2. import numpy as np
  3. import subprocess
  4. import os
  5. def ffmpeg_video_processing(input_path, output_path):
  6.     # 检查FFmpeg是否可用
  7.     try:
  8.         subprocess.run(["ffmpeg", "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  9.     except FileNotFoundError:
  10.         print("FFmpeg未找到,请确保已安装FFmpeg并添加到PATH中")
  11.         return
  12.    
  13.     # 打开输入视频
  14.     cap = cv2.VideoCapture(input_path)
  15.    
  16.     if not cap.isOpened():
  17.         print("无法打开视频文件")
  18.         return
  19.    
  20.     # 获取视频属性
  21.     frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  22.     frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  23.     fps = cap.get(cv2.CAP_PROP_FPS)
  24.    
  25.     # FFmpeg命令
  26.     # 使用管道将处理后的帧传递给FFmpeg
  27.     command = [
  28.         'ffmpeg',
  29.         '-y',  # 覆盖输出文件
  30.         '-f', 'rawvideo',
  31.         '-vcodec', 'rawvideo',
  32.         '-s', f'{frame_width}x{frame_height}',
  33.         '-pix_fmt', 'bgr24',
  34.         '-r', str(fps),
  35.         '-i', '-',  # 从标准输入读取
  36.         '-c:v', 'libx264',  # 使用H.264编码
  37.         '-pix_fmt', 'yuv420p',
  38.         '-crf', '23',  # 质量参数(18-28是合理范围,值越小质量越高)
  39.         '-preset', 'fast',  # 编码速度预设
  40.         output_path
  41.     ]
  42.    
  43.     # 启动FFmpeg进程
  44.     process = subprocess.Popen(command, stdin=subprocess.PIPE)
  45.    
  46.     frame_count = 0
  47.     start_time = cv2.getTickCount()
  48.    
  49.     while True:
  50.         ret, frame = cap.read()
  51.         if not ret:
  52.             break
  53.         
  54.         frame_count += 1
  55.         
  56.         # 在这里进行帧处理
  57.         # 示例:转换为灰度图并转回BGR
  58.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  59.         processed_frame = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
  60.         
  61.         # 将处理后的帧写入FFmpeg进程
  62.         process.stdin.write(processed_frame.tobytes())
  63.         
  64.         # 显示处理进度
  65.         if frame_count % 30 == 0:
  66.             print(f"已处理 {frame_count} 帧")
  67.    
  68.     # 计算处理时间
  69.     end_time = cv2.getTickCount()
  70.     processing_time = (end_time - start_time) / cv2.getTickFrequency()
  71.    
  72.     # 关闭FFmpeg进程
  73.     process.stdin.close()
  74.     process.wait()
  75.    
  76.     # 释放资源
  77.     cap.release()
  78.    
  79.     print(f"处理完成!共处理 {frame_count} 帧")
  80.     print(f"处理时间: {processing_time:.2f} 秒")
  81.     print(f"平均处理速度: {frame_count/processing_time:.2f} FPS")
  82.     print(f"输出视频已保存到: {output_path}")
  83. # 使用示例
  84. # ffmpeg_video_processing('input_video.mp4', 'output_ffmpeg.mp4')
复制代码

5. 实际应用案例

5.1 运动检测与跟踪
  1. import cv2
  2. import numpy as np
  3. import time
  4. class MotionDetector:
  5.     def __init__(self, video_path, output_path=None, min_contour_area=500):
  6.         self.video_path = video_path
  7.         self.output_path = output_path
  8.         self.min_contour_area = min_contour_area
  9.         
  10.         # 初始化背景减除器
  11.         self.back_sub = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)
  12.         
  13.         # 跟踪器字典
  14.         self.trackers = {}
  15.         self.next_id = 1
  16.         
  17.         # 跟踪历史
  18.         self.track_history = {}
  19.         
  20.     def detect_motion(self):
  21.         cap = cv2.VideoCapture(self.video_path)
  22.         
  23.         if not cap.isOpened():
  24.             print("无法打开视频文件")
  25.             return
  26.         
  27.         # 获取视频属性
  28.         frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  29.         frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  30.         fps = cap.get(cv2.CAP_PROP_FPS)
  31.         
  32.         # 创建视频写入对象(如果需要)
  33.         if self.output_path:
  34.             fourcc = cv2.VideoWriter_fourcc(*'XVID')
  35.             out = cv2.VideoWriter(self.output_path, fourcc, fps, (frame_width, frame_height))
  36.         
  37.         while True:
  38.             ret, frame = cap.read()
  39.             if not ret:
  40.                 break
  41.             
  42.             # 应用背景减除器
  43.             fg_mask = self.back_sub.apply(frame)
  44.             
  45.             # 对前景掩码进行形态学操作,去除噪声
  46.             kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
  47.             fg_mask = cv2.morphologyEx(fg_mask, cv2.MORPH_OPEN, kernel)
  48.             
  49.             # 查找轮廓
  50.             contours, _ = cv2.findContours(fg_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  51.             
  52.             # 更新跟踪器
  53.             self.update_trackers(frame)
  54.             
  55.             # 处理检测到的运动对象
  56.             for contour in contours:
  57.                 if cv2.contourArea(contour) > self.min_contour_area:
  58.                     (x, y, w, h) = cv2.boundingRect(contour)
  59.                     
  60.                     # 检查是否与现有跟踪器匹配
  61.                     matched = False
  62.                     for tracker_id, tracker in self.trackers.items():
  63.                         success, bbox = tracker.update(frame)
  64.                         if success:
  65.                             # 获取跟踪器的边界框
  66.                             tx, ty, tw, th = [int(v) for v in bbox]
  67.                            
  68.                             # 计算IoU(交并比)
  69.                             intersection_x1 = max(x, tx)
  70.                             intersection_y1 = max(y, ty)
  71.                             intersection_x2 = min(x + w, tx + tw)
  72.                             intersection_y2 = min(y + h, ty + th)
  73.                            
  74.                             intersection_area = max(0, intersection_x2 - intersection_x1) * max(0, intersection_y2 - intersection_y1)
  75.                             union_area = w * h + tw * th - intersection_area
  76.                            
  77.                             iou = intersection_area / union_area if union_area > 0 else 0
  78.                            
  79.                             # 如果IoU大于阈值,认为是同一个对象
  80.                             if iou > 0.5:
  81.                                 matched = True
  82.                                 break
  83.                     
  84.                     # 如果没有匹配的跟踪器,创建新的跟踪器
  85.                     if not matched:
  86.                         tracker = cv2.TrackerCSRT_create()
  87.                         tracker.init(frame, (x, y, w, h))
  88.                         self.trackers[self.next_id] = tracker
  89.                         self.track_history[self.next_id] = [(x + w/2, y + h/2)]
  90.                         self.next_id += 1
  91.             
  92.             # 绘制跟踪结果
  93.             for tracker_id, tracker in self.trackers.items():
  94.                 success, bbox = tracker.update(frame)
  95.                 if success:
  96.                     # 获取跟踪器的边界框
  97.                     x, y, w, h = [int(v) for v in bbox]
  98.                     
  99.                     # 绘制边界框
  100.                     cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
  101.                     
  102.                     # 绘制ID
  103.                     cv2.putText(frame, f"ID: {tracker_id}", (x, y-10),
  104.                                 cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
  105.                     
  106.                     # 更新跟踪历史
  107.                     center = (x + w/2, y + h/2)
  108.                     self.track_history[tracker_id].append(center)
  109.                     
  110.                     # 绘制跟踪轨迹
  111.                     if len(self.track_history[tracker_id]) > 1:
  112.                         points = np.array(self.track_history[tracker_id], dtype=np.int32)
  113.                         cv2.polylines(frame, [points], False, (0, 0, 255), 2)
  114.             
  115.             # 写入帧(如果需要)
  116.             if self.output_path:
  117.                 out.write(frame)
  118.             
  119.             # 显示结果
  120.             cv2.imshow("Motion Detection and Tracking", frame)
  121.             
  122.             # 按'q'键退出
  123.             if cv2.waitKey(25) & 0xFF == ord('q'):
  124.                 break
  125.         
  126.         # 释放资源
  127.         cap.release()
  128.         if self.output_path:
  129.             out.release()
  130.         cv2.destroyAllWindows()
  131.         
  132.         print(f"跟踪完成!共跟踪了 {len(self.trackers)} 个对象")
  133.    
  134.     def update_trackers(self, frame):
  135.         """更新所有跟踪器,移除失败的跟踪器"""
  136.         failed_trackers = []
  137.         
  138.         for tracker_id, tracker in self.trackers.items():
  139.             success, bbox = tracker.update(frame)
  140.             if not success:
  141.                 failed_trackers.append(tracker_id)
  142.         
  143.         # 移除失败的跟踪器
  144.         for tracker_id in failed_trackers:
  145.             del self.trackers[tracker_id]
  146.             del self.track_history[tracker_id]
  147. # 使用示例
  148. # detector = MotionDetector('input_video.mp4', 'motion_tracking.avi')
  149. # detector.detect_motion()
复制代码

5.2 视频稳定化

视频稳定化技术可以减少视频中的抖动,提高观看体验。
  1. import cv2
  2. import numpy as np
  3. class VideoStabilizer:
  4.     def __init__(self, video_path, output_path):
  5.         self.video_path = video_path
  6.         self.output_path = output_path
  7.         
  8.         # 特征检测器
  9.         self.feature_detector = cv2.ORB_create(1000)
  10.         
  11.         # 光流法参数
  12.         self.lk_params = dict(winSize=(15, 15),
  13.                              maxLevel=2,
  14.                              criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
  15.         
  16.         # 变换矩阵
  17.         self.transforms = []
  18.         
  19.     def stabilize(self):
  20.         # 打开视频
  21.         cap = cv2.VideoCapture(self.video_path)
  22.         
  23.         if not cap.isOpened():
  24.             print("无法打开视频文件")
  25.             return
  26.         
  27.         # 获取视频属性
  28.         frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
  29.         frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
  30.         fps = cap.get(cv2.CAP_PROP_FPS)
  31.         frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
  32.         
  33.         # 创建视频写入对象
  34.         fourcc = cv2.VideoWriter_fourcc(*'XVID')
  35.         out = cv2.VideoWriter(self.output_path, fourcc, fps, (frame_width, frame_height))
  36.         
  37.         # 读取第一帧
  38.         ret, prev_frame = cap.read()
  39.         if not ret:
  40.             print("无法读取视频帧")
  41.             return
  42.         
  43.         # 转换为灰度图
  44.         prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
  45.         
  46.         # 检测特征点
  47.         prev_pts = cv2.goodFeaturesToTrack(prev_gray, maxCorners=1000, qualityLevel=0.01, minDistance=10, blockSize=3)
  48.         
  49.         # 处理每一帧
  50.         frame_num = 0
  51.         while True:
  52.             ret, curr_frame = cap.read()
  53.             if not ret:
  54.                 break
  55.             
  56.             frame_num += 1
  57.             print(f"处理帧 {frame_num}/{frame_count}")
  58.             
  59.             # 转换为灰度图
  60.             curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)
  61.             
  62.             # 计算光流
  63.             curr_pts, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, None, **self.lk_params)
  64.             
  65.             # 选择成功的点
  66.             idx = np.where(status == 1)[0]
  67.             good_prev = prev_pts[idx]
  68.             good_curr = curr_pts[idx]
  69.             
  70.             # 计算变换矩阵
  71.             if len(good_prev) > 10:  # 确保有足够的点
  72.                 # 使用RANSAC方法计算仿射变换矩阵
  73.                 transform_matrix, inliers = cv2.estimateAffinePartial2D(good_prev, good_curr)
  74.                
  75.                 if transform_matrix is not None:
  76.                     self.transforms.append(transform_matrix)
  77.                 else:
  78.                     # 如果无法计算变换矩阵,使用单位矩阵
  79.                     self.transforms.append(np.eye(2, 3, dtype=np.float32))
  80.             else:
  81.                 # 如果点太少,使用单位矩阵
  82.                 self.transforms.append(np.eye(2, 3, dtype=np.float32))
  83.             
  84.             # 更新前一帧和点
  85.             prev_gray = curr_gray.copy()
  86.             
  87.             # 检测新的特征点(如果需要)
  88.             if len(good_curr) < 100:
  89.                 prev_pts = cv2.goodFeaturesToTrack(prev_gray, maxCorners=1000, qualityLevel=0.01, minDistance=10, blockSize=3)
  90.             else:
  91.                 prev_pts = good_curr.reshape(-1, 1, 2)
  92.         
  93.         # 计算平滑的变换路径
  94.         self.smooth_transforms()
  95.         
  96.         # 应用稳定化
  97.         cap.set(cv2.CAP_PROP_POS_FRAMES, 0)  # 重置到视频开头
  98.         
  99.         # 读取第一帧
  100.         ret, frame = cap.read()
  101.         if not ret:
  102.             print("无法读取视频帧")
  103.             return
  104.         
  105.         # 创建边界框用于后期处理
  106.         border_size = 50
  107.         stabilized_frame = cv2.copyMakeBorder(frame, border_size, border_size, border_size, border_size,
  108.                                             cv2.BORDER_CONSTANT, value=(0, 0, 0))
  109.         
  110.         # 写入第一帧
  111.         out.write(stabilized_frame)
  112.         
  113.         # 应用变换到每一帧
  114.         for i in range(len(self.transforms)):
  115.             ret, frame = cap.read()
  116.             if not ret:
  117.                 break
  118.             
  119.             # 应用变换
  120.             transform = self.transforms[i]
  121.             stabilized_frame = cv2.warpAffine(frame, transform, (frame_width + 2*border_size, frame_height + 2*border_size),
  122.                                              flags=cv2.INTER_LINEAR | cv2.WARP_INVERSE_MAP,
  123.                                              borderMode=cv2.BORDER_CONSTANT, borderValue=(0, 0, 0))
  124.             
  125.             # 裁剪边框
  126.             stabilized_frame = stabilized_frame[border_size:border_size+frame_height, border_size:border_size+frame_width]
  127.             
  128.             # 写入帧
  129.             out.write(stabilized_frame)
  130.             
  131.             # 显示进度
  132.             if i % 10 == 0:
  133.                 print(f"稳定化进度: {i}/{len(self.transforms)}")
  134.         
  135.         # 释放资源
  136.         cap.release()
  137.         out.release()
  138.         
  139.         print("视频稳定化完成!")
  140.    
  141.     def smooth_transforms(self):
  142.         """平滑变换矩阵以减少抖动"""
  143.         if not self.transforms:
  144.             return
  145.         
  146.         # 计算移动平均
  147.         window_size = 30
  148.         smoothed_transforms = []
  149.         
  150.         for i in range(len(self.transforms)):
  151.             start = max(0, i - window_size // 2)
  152.             end = min(len(self.transforms), i + window_size // 2 + 1)
  153.             
  154.             # 计算窗口内的平均变换
  155.             avg_transform = np.zeros((2, 3), dtype=np.float32)
  156.             for j in range(start, end):
  157.                 avg_transform += self.transforms[j]
  158.             avg_transform /= (end - start)
  159.             
  160.             smoothed_transforms.append(avg_transform)
  161.         
  162.         # 更新变换矩阵
  163.         self.transforms = smoothed_transforms
  164. # 使用示例
  165. # stabilizer = VideoStabilizer('input_video.mp4', 'stabilized_video.avi')
  166. # stabilizer.stabilize()
复制代码

5.3 实时视频流处理
  1. import cv2
  2. import numpy as np
  3. import time
  4. import threading
  5. import queue
  6. class RealTimeVideoProcessor:
  7.     def __init__(self, source=0, processing_function=None):
  8.         """
  9.         初始化实时视频处理器
  10.         :param source: 视频源,可以是摄像头索引或视频文件路径
  11.         :param processing_function: 自定义帧处理函数
  12.         """
  13.         self.source = source
  14.         self.processing_function = processing_function or self.default_processing
  15.         self.running = False
  16.         self.frame_queue = queue.Queue(maxsize=10)
  17.         self.result_queue = queue.Queue(maxsize=10)
  18.         
  19.         # 性能统计
  20.         self.frame_count = 0
  21.         self.start_time = None
  22.         self.fps = 0
  23.         
  24.     def default_processing(self, frame):
  25.         """默认帧处理函数"""
  26.         # 转换为灰度图
  27.         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  28.         
  29.         # 边缘检测
  30.         edges = cv2.Canny(gray, 100, 200)
  31.         
  32.         # 转换回BGR格式
  33.         result = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
  34.         
  35.         return result
  36.    
  37.     def capture_frames(self):
  38.         """捕获视频帧"""
  39.         cap = cv2.VideoCapture(self.source)
  40.         
  41.         if not cap.isOpened():
  42.             print("无法打开视频源")
  43.             self.running = False
  44.             return
  45.         
  46.         # 设置摄像头参数(如果是摄像头)
  47.         if isinstance(self.source, int):
  48.             cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
  49.             cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
  50.             cap.set(cv2.CAP_PROP_FPS, 30)
  51.         
  52.         while self.running:
  53.             ret, frame = cap.read()
  54.             if not ret:
  55.                 print("无法获取帧")
  56.                 break
  57.             
  58.             # 如果队列已满,丢弃最旧的帧
  59.             if self.frame_queue.full():
  60.                 try:
  61.                     self.frame_queue.get_nowait()
  62.                 except queue.Empty:
  63.                     pass
  64.             
  65.             # 将帧放入队列
  66.             self.frame_queue.put(frame)
  67.             
  68.             # 更新帧计数
  69.             self.frame_count += 1
  70.             
  71.             # 计算FPS
  72.             if self.frame_count % 30 == 0:
  73.                 if self.start_time is not None:
  74.                     elapsed_time = time.time() - self.start_time
  75.                     self.fps = self.frame_count / elapsed_time
  76.                     print(f"捕获FPS: {self.fps:.2f}")
  77.         
  78.         cap.release()
  79.         print("帧捕获线程结束")
  80.    
  81.     def process_frames(self):
  82.         """处理视频帧"""
  83.         while self.running or not self.frame_queue.empty():
  84.             try:
  85.                 # 从队列获取帧,设置超时以避免无限等待
  86.                 frame = self.frame_queue.get(timeout=0.1)
  87.                
  88.                 # 处理帧
  89.                 result = self.processing_function(frame)
  90.                
  91.                 # 如果结果队列已满,丢弃最旧的结果
  92.                 if self.result_queue.full():
  93.                     try:
  94.                         self.result_queue.get_nowait()
  95.                     except queue.Empty:
  96.                         pass
  97.                
  98.                 # 将结果放入队列
  99.                 self.result_queue.put(result)
  100.                
  101.             except queue.Empty:
  102.                 # 队列为空,继续等待
  103.                 continue
  104.             except Exception as e:
  105.                 print(f"处理帧时出错: {e}")
  106.         
  107.         print("帧处理线程结束")
  108.    
  109.     def display_frames(self):
  110.         """显示处理后的帧"""
  111.         cv2.namedWindow("Real-time Video Processing", cv2.WINDOW_NORMAL)
  112.         
  113.         while self.running or not self.result_queue.empty():
  114.             try:
  115.                 # 从队列获取结果,设置超时以避免无限等待
  116.                 result = self.result_queue.get(timeout=0.1)
  117.                
  118.                 # 在图像上显示FPS
  119.                 if self.fps > 0:
  120.                     cv2.putText(result, f"FPS: {self.fps:.2f}", (10, 30),
  121.                                 cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
  122.                
  123.                 # 显示结果
  124.                 cv2.imshow("Real-time Video Processing", result)
  125.                
  126.                 # 按'q'键退出
  127.                 if cv2.waitKey(1) & 0xFF == ord('q'):
  128.                     self.running = False
  129.                     break
  130.                     
  131.             except queue.Empty:
  132.                 # 队列为空,继续等待
  133.                 continue
  134.             except Exception as e:
  135.                 print(f"显示帧时出错: {e}")
  136.         
  137.         cv2.destroyAllWindows()
  138.         print("帧显示线程结束")
  139.    
  140.     def start(self):
  141.         """启动实时视频处理"""
  142.         self.running = True
  143.         self.start_time = time.time()
  144.         self.frame_count = 0
  145.         
  146.         # 创建并启动线程
  147.         capture_thread = threading.Thread(target=self.capture_frames)
  148.         process_thread = threading.Thread(target=self.process_frames)
  149.         display_thread = threading.Thread(target=self.display_frames)
  150.         
  151.         capture_thread.start()
  152.         process_thread.start()
  153.         display_thread.start()
  154.         
  155.         # 等待线程结束
  156.         capture_thread.join()
  157.         process_thread.join()
  158.         display_thread.join()
  159.         
  160.         print("实时视频处理结束")
  161. # 自定义处理函数示例
  162. def face_detection(frame):
  163.     """人脸检测处理函数"""
  164.     # 加载人脸检测器
  165.     face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
  166.    
  167.     # 转换为灰度图
  168.     gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  169.    
  170.     # 检测人脸
  171.     faces = face_cascade.detectMultiScale(gray, 1.1, 4)
  172.    
  173.     # 在检测到的人脸周围绘制矩形
  174.     for (x, y, w, h) in faces:
  175.         cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
  176.    
  177.     return frame
  178. # 使用示例
  179. # 使用默认处理函数
  180. # processor = RealTimeVideoProcessor(source=0)  # 0表示默认摄像头
  181. # processor.start()
  182. # 使用自定义处理函数
  183. # processor = RealTimeVideoProcessor(source=0, processing_function=face_detection)
  184. # processor.start()
复制代码

6. 总结与展望

本文详细介绍了如何使用OpenCV实现高效的视频输出,从基础配置到高级应用技巧。我们学习了如何安装和配置OpenCV,如何读取、处理和保存视频,以及如何应用各种视频处理技术,如运动检测、背景减除、视频增强和特效处理。此外,我们还探讨了性能优化技术,包括多线程处理、GPU加速和使用FFmpeg进行高效视频编码。最后,我们通过实际应用案例,如运动检测与跟踪、视频稳定化和实时视频流处理,展示了OpenCV在视频处理领域的强大能力。

随着计算机视觉技术的不断发展,OpenCV也在持续更新和改进。未来,我们可以期待更多高级功能和更好的性能优化。同时,深度学习技术与OpenCV的结合也将为视频处理带来更多可能性,如基于深度学习的目标检测、语义分割和视频生成等。

无论您是初学者还是有经验的开发者,希望本文能帮助您更好地掌握OpenCV视频处理技术,为您的项目和研究提供有力支持。继续探索和学习,您将能够利用OpenCV创建更加强大和高效的视频处理应用。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则