Python opencv 无法从视频中裁剪帧

Python opencv having trouble cropping frames from a video

描述

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

代码

导入包

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。然后,它为我提供了裁剪图像的预览。如果图像看起来不错,脚本 returns 坐标。

主要功能

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 中所做的相同方式裁剪它们。然而,它只是给我一个错误

来自终端的错误消息

回溯(最近调用最后): 文件“/Data/Dropbox/coding/functions/imageProcessing/June11.py”,第 71 行,位于 cv2.imshow('test cropping', 裁剪) cv2.error: OpenCV(4.5.2) /builddir/build/BUILD/opencv-4.5.2/modules/highgui/src/window.cpp:412: 错误: (-215:断言失败) size.width>0 && size.height>0 函数 'imshow'

调试

我试着不裁剪地打印出图像,它看起来很正常。然而,一旦我裁剪它,它 returns 一个空数组 [].

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

我无法测试它,但我想我看到了问题 - 你弄乱了坐标。

get_cropped() returns

return [x1, y1, x2, y2] 

但是你把它分配给了

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

所以你以错误的顺序分配它们 - 你将 x2 替换为 y1

应该是

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