如何在常规Python中的内存视图对象上使用ctypes.memmove

问题描述 投票:0回答:1

首先我要说明一下这个问题的背景。我正在使用 PySide6 捕获屏幕,我想截取视频源并使用 opencv 对帧执行一些图像处理。我能够收集 QVideoFrame,转换为 QImage,然后将其转换为 numpy 数组并进行图像处理。但是,我还希望能够将该 numpy 数组传递回输出视频流,以便我可以看到图像处理的结果。

我可以使用此代码将 numpy 数组转换为 QImage;

arr = cv2.cvtColor(arr, cv2.COLOR_BGR2RGBA)
image = QImage(arr.data, arr.shape[1], arr.shape[0], QImage.Format.Format_RGBA8888)

然后我可以开始像这样创建一个 QVideoFrame ;

format_ = QVideoFrameFormat(
    image.size(),
    QVideoFrameFormat.pixelFormatFromImageFormat(image.format())
)
frame2 = QVideoFrame(format_)
frame2.map(QVideoFrame.ReadWrite)

到目前为止一切顺利...但下一步是将字节从 QImage 复制到为 QVideoFrame 保留的内存中。有这个示例展示了如何在 C++ 中做到这一点。我尝试使用这样的 ctypes 库在 python 中工作;

ctypes.memmove(
    frame2.bits(0)[0],
    image.bits()[0],
    image.sizeInBytes()
)

这就是我陷入困境的地方。基本上

QImage.bits()
QVideoFrame.bits()
都返回一个 memoryview 对象,我假设它包含我需要复制的实际数据(以字节为单位)。上面代码片段的问题是
bits()[0]
总是返回零,这会因尝试访问越界内存而引发错误。我认为它需要以整数形式返回该内存的指针。我已经看到了各种建议,在 CPython 中
id(object)
将给出对象的指针,但是我没有使用 CPython - 所以问题是如何在常规 python 中执行此操作?

仅供参考,我的项目在 Windows 11 家庭版 23H2 上使用 python 3.9.10。

python ctypes pyside6
1个回答
0
投票

感谢@ekhumoro 帮助我解决了这个问题。给定一个 numpy 数组,您可以将其转换回 QVideoFrame,如下所示;

arr = cv2.cvtColor(arr, cv2.COLOR_BGR2RGBA)
image = QImage(arr.data, arr.shape[1], arr.shape[0], QImage.Format.Format_RGBA8888)

# convert back to QVideoFrame
format_ = QVideoFrameFormat(
    image.size(),
    QVideoFrameFormat.pixelFormatFromImageFormat(image.format())
)
frame2 = QVideoFrame(format_)
frame2.map(QVideoFrame.ReadWrite)

# instead of using ctypes, we can cast the memoryview of the QImage
# back on to the new QVideoFrame as long as we find the right end index.
end = len(image.bits().tobytes())
frame2.bits(0)[:end] = image.bits()

frame2.unmap()
© www.soinside.com 2019 - 2024. All rights reserved.