numpy 在OpenCV中使用VideoWriter时无法播放文件

zdwk9cvp  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(135)

当我尝试播放.mp4文件时,VideoWriter创建的.mp4文件会出现错误,说“此文件不可播放。这可能是因为文件类型不受支持,文件扩展名不正确,或者文件已损坏。
我试着将我的VideoWriter设置移动到我的其他文件,只是为了看看,我有同样的结果。我是OpenCV和Numpy的新手,所以我不知道该怎么做。
这是我的main.py文件中的代码:

import cv2 as cv
import numpy as np
from time import time
import datetime

from windowcapture import WindowCapture

wincap = WindowCapture('Geometry Dash')

time_stamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
fourcc = cv.VideoWriter_fourcc('m', 'p', '4', 'v')
file_name = f'{time_stamp}.mp4'
captured_video = cv.VideoWriter(file_name, fourcc, 60.0, (800, 600))

loop_time = time()
while True:

    screenshot = wincap.get_screenshot()

    # prints the video fps
    print('FPS {:.2f}'.format(1 / (time() - loop_time)))
    loop_time = time()
    
    cv.imshow('Screen Capture', screenshot)
    captured_video.write(screenshot)

    # press 'q' with output window focused to close window
    # waits 1ms every loop to process if q is pressed
    if cv.waitKey(1) == ord('q'):
        cv.destroyAllWindows()
        break

print('q pressed // window closing')

这是我的windowcapture.py文件中的代码:

import numpy as np
import win32gui, win32ui, win32con

class WindowCapture:

    # properties
    w = 0
    h = 0
    hwnd = None
    cropped_x = 0
    cropped_y = 0
    offset_x = 0
    offset_y = 0

    # constructor
    def __init__(self, window_name):

        self.hwnd = win32gui.FindWindow(None, window_name)
        if not self.hwnd:
            raise Exception('Window not found "{}"'.format(window_name))
        
        # get window size
        window_rect = win32gui.GetWindowRect(self.hwnd)
        self.w = window_rect[2] - window_rect[0]
        self.h = window_rect[3] - window_rect[1]

        # account for window border and titlebar and cut them off
        border_pixels = 8
        titlebar_pixels = 30
        self.w = self.w - (border_pixels * 2)
        self.h = self.h - titlebar_pixels - border_pixels
        self.cropped_x = border_pixels
        self.cropped_y = titlebar_pixels

        # set the cropped coordinates offset so we can translate screenshot
        # images into actual screen positions
        self.offset_x = window_rect[0] + self.cropped_x
        self.offset_y = window_rect[1] + self.cropped_y

    def get_screenshot(self):
        
        # get the window image data
        wDC = win32gui.GetWindowDC(self.hwnd)
        dcObj = win32ui.CreateDCFromHandle(wDC)
        cDC = dcObj.CreateCompatibleDC()
        dataBitMap = win32ui.CreateBitmap()
        dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
        cDC.SelectObject(dataBitMap)
        cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)

        # saves the screenshot
        #dataBitMap.SaveBitmapFile(cDC, 'debug.bmp')
        
        signedIntsArray = dataBitMap.GetBitmapBits(True)
        img = np.frombuffer(signedIntsArray, dtype='uint8')
        img.shape = (self.h, self.w, 4)

        # Free Resources
        dcObj.DeleteDC()
        cDC.DeleteDC()
        win32gui.ReleaseDC(self.hwnd, wDC)
        win32gui.DeleteObject(dataBitMap.GetHandle())

        # make image C_CONTIGUOUS to avoid errors like:
        #   File ... in draw_rectangles
        #   TypeError: an integer is required (got type tuple)
        # github discussion:
        # https://github.com/opencv/opencv/issues/14866#issuecomment-580207109 
        img = np.array(img)
        return img
    
    # find the name of the window you're interested in.
    # once you have it, update window_capture()
    # https://stackoverflow.com/questions/55547940/how-to-get-a-list-of-the-name-of-every-open-window
    def list_window_names(self):
        def winEnumHandler(hwnd, ctx):
            if win32gui.IsWindowVisible(hwnd):
                print(hex(hwnd), win32gui.GetWindowText(hwnd))
        win32gui.EnumWindows(winEnumHandler, None)

    #list_window_names()

    # translate a pixel position on a screenshot image to a pixel position on the screen.
    # pos = (x,y)
    # WARNING: if you move the window being captured after execution is started, this will
    # return incorrect coordinates, because the window position is only calculated in
    # the __init__ constructor.
    def get_screen_position(self, pos):
        return (pos[0] + self.offset_x, pos[1] + self.offset_y)
'''
I have no problem viewing my video when I have my game open it plays perfectly fine in the window that pops up from opencv but when I try to save this video to mp4 the video does not work.
gc0ot86w

gc0ot86w1#

这可能是对我的问题的一个暂时的回答,因为这并不是真正感觉到解决这个问题的“正确”方法,但这就是我所做的。
在我的main.py我改变了

time_stamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
fourcc = cv.VideoWriter_fourcc('m', 'p', '4', 'v')
file_name = f'{time_stamp}.mp4'
captured_video = cv.VideoWriter(file_name, fourcc, 60.0, (800, 600))

我已经将此代码更改为

time_stamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
fourcc = cv.VideoWriter_fourcc(*'mp4v')
file_name = f'{time_stamp}.mp4'
captured_video = cv.VideoWriter(file_name, fourcc, 60.0, (1600,900))

然后在我的windowcapture.py文件中,

img = np.array(img)
return img

现在我把它改成了

img_np = np.array(img)
img_bgr = cv.cvtColor(img_np, cv.COLOR_RGB2BGR)
img_rgb = cv.cvtColor(img_bgr, cv.COLOR_BGR2RGB)
return img_rgb

剩下的代码我已经离开了,我现在得到我的mp4文件播放。第一个变化,我注意到从我做的测试是我需要设置我的VideoWriter正确的屏幕大小,因为我有它在800,600时,窗口是1600,900。第二个变化是颜色转换如果我只转换到BGR的代码工作,但显然我不希望它在BGR我希望它在RGB,所以我必须转换回来,但如果我不这样做至少一个转换的mp4将无法播放。

相关问题