You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用multiprocessing与cv2时遇pickle错误及多进程实现咨询

问题分析与修复方案

错误原因

你遇到的TypeError: cannot pickle 'cv2.VideoCapture' object,本质是Python多进程启动时会序列化(pickle)传递给子进程的参数,但cv2.VideoCapture对象不支持序列化,无法跨进程传递。

代码中的其他问题

除了序列化错误,你的代码还有几处需要修正的地方:

  1. 创建filtered_process时,args参数格式错误,必须传入元组,否则会导致函数参数不匹配
  2. 子进程中的cv2.waitKey(1)无效,因为子进程没有OpenCV的GUI上下文
  3. 灰度图绘制用了plt.plot(画曲线),而非plt.imshow(显示图像),导致保存结果错误
  4. 锁的使用不够安全,未考虑异常场景下的释放问题
  5. saveFramesFiltered中currentFrame递增时机错误,可能导致重复处理或跳过帧

修复后的完整代码

import cv2
import os
import time
import matplotlib.image as pltim
from multiprocessing import Process, Lock
import matplotlib.pyplot as plt


def saveFramesUnfiltered(lock):
    # 子进程内部创建VideoCapture,避免跨进程传递不可序列化对象
    vid = cv2.VideoCapture("maxwell cat.mp4")
    currentFrame = 0

    while True:
        success, frame = vid.read()
        if not success:  # 视频读取完毕自动退出循环
            break
        
        # 使用with上下文管理器自动管理锁,避免异常导致锁无法释放
        with lock:
            cv2.imwrite(f"./framesBefore/frame{currentFrame}.jpg", frame)
        
        currentFrame += 1
        time.sleep(0.01)
    
    vid.release()


def saveFramesFiltered(lock):
    currentFrame = 0
    # 从视频获取总帧数,替代硬编码的215
    vid = cv2.VideoCapture("maxwell cat.mp4")
    framemax = int(vid.get(cv2.CAP_PROP_FRAME_COUNT))
    vid.release()

    while currentFrame < framemax:
        frame_path = f"./framesBefore/frame{currentFrame}.jpg"
        if os.path.exists(frame_path):
            with lock:
                image = pltim.imread(frame_path)
            
            # 计算灰度图
            r, g, b = image[:, :, 0], image[:, :, 1], image[:, :, 2]
            grayImage = 0.299 * r + 0.587 * g + 0.114 * b
            
            # 正确绘制灰度图像
            plt.imshow(grayImage, cmap="gray")
            plt.axis("off")
            
            with lock:
                plt.savefig(f"./framesAfter/grayImage{currentFrame}.jpg", bbox_inches='tight', pad_inches=0)
            
            plt.clf()  # 清除画布,避免后续帧重叠
            time.sleep(0.01)
            currentFrame += 1  # 处理完成后再递增帧序号
        else:
            # 帧未生成时短暂等待重试
            time.sleep(0.005)


def main():
    # 简化目录创建逻辑
    os.makedirs('framesBefore', exist_ok=True)
    os.makedirs('framesAfter', exist_ok=True)

    lock = Lock()

    # 修正args参数为元组格式
    unfiltered_process = Process(target=saveFramesUnfiltered, args=(lock,))
    filtered_process = Process(target=saveFramesFiltered, args=(lock,))

    unfiltered_process.start()
    filtered_process.start()

    unfiltered_process.join()
    filtered_process.join()

    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

关于多进程实现思路的说明

你的核心思路(一个进程提取原始帧,一个进程处理帧)是合理的,能利用多进程并行提升效率。但需要注意:

  1. 多进程间不能传递不可序列化的对象(如OpenCV的VideoCapture、窗口句柄等)
  2. 进程间同步可以用文件存在性判断,也可以用multiprocessing.Queue直接传递帧数据,效率更高
  3. 硬编码的帧数量建议改为从视频中动态获取,提升代码通用性

内容的提问来源于stack exchange,提问作者MR. potato35

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 21:35:18