Demons_皮 2021-11-24 17:03 采纳率: 50%
浏览 318
已结题

opencv库分别封装了拍照和录像函数,调用threading库多线程运行实现一边拍照一边录像时报错

一:问题描述:使用opencv库分别封装了拍照和录像函数,然后想实现一边拍照一边录像的效果,调用threading库来多线程运行时报错cv2.imwrite()为空

二:代码如下

import cv2
import threading
import time
import json
from datetime import datetime


with open("calibration.json", "r", encoding="utf-8") as load_f:
    load = json.load(load_f)


def picture_shoot(image_name, image_path=r"E:\report") -> None:
    '''
    调用摄像头拍照并保存图片到本地
    :param image_name: 图片名
    :param image_path: 图片保存路径
    :return: None
    '''
    cap = cv2.VideoCapture(0)
    while (cap.isOpened()):
        ret, frame = cap.read()
        # cv2.imshow("Capture_Paizhao", frame) # 显示相机窗口
        # k = cv2.waitKey(1) & 0xFF #通过键盘获取值并赋值给k
        # if k == ord('s'):  # 按下s键,进入下面的保存图片操作
        # cv2.imwrite(image_path + '\\' + image_name + ".jpg", frame)
        cv2.imwrite(image_path + '\\' + image_name, frame)
        # print(cap.get(3))
        # print(cap.get(4))
        print("保存" + image_name + "成功!")
        # elif k == ord('q'):  # 按下q键,程序退出
        break
    cap.release()
    cv2.destroyAllWindows()


def video_record(video_path) -> None:
    '''
    调用摄像头录制视频并保存到本地
    :param video_path: 视频保存路径
    :return: None
    '''
    FPS = 24.0
    # 必须指定CAP_DSHOW(Direct Show)参数初始化摄像头,否则无法使用更高分辨率
    cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    # 视频写入的图像尺寸与画布尺寸不对应会导致视频无法播放,需要实时获取
    WIDTH = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    HEIGHT = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    # 设置摄像头设备分辨率
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
    # 设置摄像头设备帧率,如不指定,默认600
    cap.set(cv2.CAP_PROP_FPS, 24)
    # 建议使用XVID编码,图像质量和文件大小比较都兼顾的方案
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    out = cv2.VideoWriter(video_path, fourcc, FPS, (WIDTH, HEIGHT))
    start_time = datetime.now()
    while (cap.isOpened()):
        ret, frame = cap.read()
        if ret:
            out.write(frame)
            # 显示预览窗口
            # cv2.imshow('Preview_Window', frame) # 显示相机窗口
            # 录制5秒后停止
            if (datetime.now() - start_time).seconds == load['record_duration']:
                cap.release()
                print('视频录制成功!')
                break
    out.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    path = r'E:\report' + '\\' + 'video.avi'
    thread = threading.Thread(target=video_record, args=(path,))
    thread.start()

    picture_shoot(image_name='1.png', image_path=r'E:/report/AI2_reverse/standard_camera')

三:运行结果

D:\Python3.8.6\python.exe D:/PythonWorkSpace/Auto_test/Camera_Invoke.py
[ WARN:0] global D:\a\opencv-python\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (376) `anonymous-namespace'::SourceReaderCB::OnReadSample videoio(MSMF): OnReadSample() is called with error status: -1072875772
[ WARN:0] global D:\a\opencv-python\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (388) `anonymous-namespace'::SourceReaderCB::OnReadSample videoio(MSMF): async ReadSample() call is failed with error status: -1072875772
[ WARN:1] global D:\a\opencv-python\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (1022) CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -1072875772
Traceback (most recent call last):
  File "D:/PythonWorkSpace/Auto_test/Camera_Invoke.py", line 77, in <module>
    picture_shoot(image_name='1.png', image_path=r'E:/report/AI2_reverse/standard_camera')
  File "D:/PythonWorkSpace/Auto_test/Camera_Invoke.py", line 26, in picture_shoot
    cv2.imwrite(image_path + '\\' + image_name, frame)
cv2.error: OpenCV(4.5.4) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:799: error: (-215:Assertion failed) !_img.empty() in function 'cv::imwrite'

视频录制成功!
[ WARN:1] global D:\a\opencv-python\opencv-python\opencv\modules\videoio\src\cap_msmf.cpp (438) `anonymous-namespace'::SourceReaderCB::~SourceReaderCB terminating async callback

Process finished with exit code 1

四:尝试过的方法
1、观察发现两个函数都实例化了cap对象,并发运行时可能会产生冲突,把其中一个函数的cap改成了cap_2,运行后仍然报同样的错误
2、两个函数都是通过cv2下的方法来实现拍照或者录像,但是cv2是三方库的内置函数,改不了名字

五:我想要达到的效果
能够一边录制视频一边拍照,并且可以控制视频什么时候结束

  • 写回答

3条回答 默认 最新

  • Demons_皮 2021-11-30 15:46
    关注

    1、因为两个函数要用到想用的对象,所以尝试封装类,把共用的属性作为类属性

    import cv2
    import threading
    import json
    from datetime import datetime
    
    with open("calibration.json", "r", encoding="utf-8") as load_f:
        load = json.load(load_f)
    
    
    class Camera_invoke(object):
        cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
        ret, frame = cap.read()
    
        def picture_shoot(self, image_name, image_path=r"E:\report") -> None:
            '''
            调用摄像头拍照并保存图片到本地
            :param image_name: 图片名
            :param image_path: 图片保存路径
            :return: None
            '''
            self.image_name = image_name
            self.image_path = image_path
            cv2.imwrite(self.image_path + '\\' + self.image_name, self.frame)
            print("保存" + self.image_name + "成功!")
    
        def video_record(self, video_path) -> None:
            '''
            调用摄像头录制视频并保存到本地
            :param video_path: 视频保存路径
            :return: None
            '''
            self.video_path = video_path
            FPS = 24.0
            # 视频写入的图像尺寸与画布尺寸不对应会导致视频无法播放,需要实时获取
            WIDTH = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            HEIGHT = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            # 设置摄像头设备分辨率
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
            # 设置摄像头设备帧率,如不指定,默认600
            self.cap.set(cv2.CAP_PROP_FPS, 24)
            # 建议使用XVID编码,图像质量和文件大小比较都兼顾的方案
            fourcc = cv2.VideoWriter_fourcc(*'XVID')
            out = cv2.VideoWriter(self.video_path, fourcc, FPS, (WIDTH, HEIGHT))
            start_time = datetime.now()
            while (self.cap.isOpened()):
                ret, frame = self.cap.read()
                if ret:
                    #加时间戳
                    font = cv2.FONT_HERSHEY_SIMPLEX
                    datet = str(datetime.now())
                    frame = cv2.putText(frame, datet, (10, 50), font, 1,
                                        (0, 255, 255), 2, cv2.LINE_AA)
                    out.write(frame)
                    # 录制5秒后停止
                    if (datetime.now() - start_time).seconds == load['record_duration']:
                        self.cap.release()
                        print('视频录制成功!')
                        break
            out.release()
            cv2.destroyAllWindows()
    
    
    if __name__ == '__main__':
        path = r'E:\report' + '\\' + 'video16.avi'
        camera = Camera_invoke()
        thread = threading.Thread(target=camera.video_record, args=(path,))
        thread.start()
    
        camera.picture_shoot(image_name='16.png', image_path=r'E:/report/AI2_reverse/standard_camera')
    
    
    

    封装成类后,能够同时录像和拍照,解决问题

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 12月29日
  • 已采纳回答 12月21日
  • 创建了问题 11月24日

悬赏问题

  • ¥50 关于#微信小程序#的问题:微信小程序支持h5实现webrtc h264 h265低延迟传输渲染,能付费帮我们解决一下吗
  • ¥20 请问ansys License manager 这个问题如何解决
  • ¥15 memory.limit()' is no longer supported
  • ¥15 基于stm32f4产生两路pwm信号并可由串口通信调节
  • ¥15 C++/QT设置函数调用条件(多个功能调用同一,且各自调用条件不同)
  • ¥15 UE5样条线生成的网格UV问题
  • ¥15 如何用最短的时间大致看懂springboot+vue的项目
  • ¥15 (有偿)懂数值分析和含时变参数微分方程的来
  • ¥15 abaqus随机生成二维颗粒
  • ¥15 安装ansys许可证管理器时出现了这个问题,如何解决?