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

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 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮