Python opencv 无法从视频中裁剪帧

Posted

技术标签:

【中文标题】Python opencv 无法从视频中裁剪帧【英文标题】:Python opencv having trouble cropping frames from a video 【发布时间】:2021-08-28 21:05:03 【问题描述】:

说明

我对 Python 和 opencv 还很陌生,我想使用 opencv 从视频中裁剪帧。工作流程如下:我打开了一个图像并从鼠标回调函数中获取了一些坐标值。由于视频是用三脚架上的手机拍摄的,我希望感兴趣的区域应该在空间中固定。因此,我可以使用坐标来批量处理其他帧。第一个裁剪的图像已按预期完成并保存,但我在处理其他帧时遇到问题。

代码

导入的包

import cv2

鼠标回调

def get_retval(event, x, y, flags, param):
    global ix, iy
    if event == cv2.EVENT_LBUTTONDBLCLK:
        ix, iy = x, y

获取坐标

def get_cropped():
    while True:
        count = 1
        while count < 4:
            cv2.imshow('get reference', img)
            k = cv2.waitKey(20) & 0xFF
            if k == 27:
                break
            elif k == ord('a'):
                if count == 1:
                    # upperleft
                    x1, y1 = ix, iy
                elif count == 2:
                    # upperright
                    x2, _ = ix, iy
                    # bottom
                elif count == 3:
                    _, y2 = ix, iy
                count += 1
        cropped_img = img[y1:y2, x1:x2]
        cv2.imshow("cropped", cropped_img)
        k = cv2.waitKey(0) & 0xFF
        if k == ord('g'):
            cv2.imwrite(data_out + "frame_0.png", cropped_img)
            return [x1, y1, x2, y2]
            cv2.destroyWindow("cropped")
            break
        else:
            cv2.destroyWindow("cropped")

每当双击左侧按钮时,坐标就会被记录下来,我按'a'键记录将值分配给$x_i$和$y_i$,因为i = 1和2。然后,它给我一个裁剪图像的预览。如果图像看起来不错,脚本会返回坐标。

主函数

try:
    base_dir = 'xxx'
    vid_dir = base_dir + 'yyy'
    processing_vid = 'zzz'
    data_out = '/Data/Work/'
    vidcap = cv2.VideoCapture(vid_dir + processing_vid)

    frame_count = 0
    while vidcap.isOpened() is True:
        retval, image = vidcap.read()
        totalFrames = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT))
        if retval is True and frame_count == 0:
            cv2.imwrite('/tmp/ref.png', image)
            img = cv2.imread('/tmp/ref.png')
            cv2.namedWindow('get reference')
            img = cv2.resize(img, (960, 540))
            cv2.setMouseCallback('get reference', get_retval)
            x1, x2, y1, y2 = get_cropped()

        if retval is True and frame_count != 0:
            cv2.namedWindow('test cropping')
            image = cv2.resize(image, (960, 540))
            cropped = image[y1:y2, x1:x2]
            cv2.imshow('test cropping', cropped) 
        if frame_count == 10:
            break
        frame_count += 1


except KeyboardInterrupt:
    cv2.destroyAllWindows()

我使用第一帧作为参考来获取坐标。这工作得很好。然后,对于另一帧,我将它们调整为与参考帧相同的大小,并以与函数get_cropped 相同的方式裁剪它们。但是,它只是给我一个错误

来自终端的错误信息

Traceback(最近一次调用最后一次): 文件“/Data/Dropbox/coding/functions/imageProcessing/June11.py”,第 71 行,在 cv2.imshow('测试裁剪', 裁剪) cv2.error: OpenCV(4.5.2) /builddir/build/BUILD/opencv-4.5.2/modules/highgui/src/window.cpp:412: error: (-215:Assertion failed) size.width>0 && size.height>0 在函数“imshow”中

调试

我尝试在不裁剪的情况下打印出图像,它看起来很正常。但是,一旦我裁剪它,它就会返回一个空数组 []。

谁能帮我找出我做错了什么?抱歉我的描述太长了!非常感谢!

【问题讨论】:

message size.width&gt;0 &amp;&amp; size.height&gt;0 可以表示您有空数组。也许首先使用print() 来查看变量中的内容,也许你有错误的坐标并且它无法裁剪它。或者您的顺序错误 - 它可能需要x1 &lt; x2y1 &lt; y2 @furas 是的,我打印了图像,它看起来像一个普通的 numpy 数组。而且,正如您所提到的,一旦我裁剪了图像,它只会输出一个空数组。我认为 x_i 和 y_i 的顺序正确,因为第一帧按照我的预期进行了裁剪 错误在cv2.imshow('test cropping', ...) 行显示问题,但我在您的代码中没有看到这一行。也许你运行不同的代码。 @furas 你是对的!我正在运行一个略有差异的代码。请参阅我更新的问题。非常感谢! 我想我看到了问题——你把坐标弄乱了。 get_cropped() 返回 return [x1, y1, x2, y2] 但您将其分配给 x1, x2, y1, y2 = get_cropped(...) - 因此您以错误的顺序分配它们。 【参考方案1】:

我无法测试它,但我认为我发现了问题 - 你把坐标弄乱了。

get_cropped() 返回

return [x1, y1, x2, y2] 

但你把它分配给

x1, x2, y1, y2 = get_cropped(...) 

因此您以错误的顺序分配它们 - 您将 x2 替换为 y1

应该是

x1, y1, x2, y2 = get_cropped(...) 

【讨论】:

如果这解决了您的问题,那么您可以将我的答案标记为已接受,几分钟后您可以投票。

以上是关于Python opencv 无法从视频中裁剪帧的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenCV 仅在视频文件开头几秒钟提取帧

使用 Opencv 加速从摄像头读取视频帧

无法使用 C++ 和 OpenCV 从视频中提取帧

如何通过 OpenCV 和 Python 通过索引从视频中获取帧?

如何使用 python 和 openCV 从 .yuv 视频文件 (YUV420) 中提取帧?

OpenCV-Python:如何从实时视频流中获取最新帧或跳过旧帧