微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法使用多处理 + cv2

如何解决无法使用多处理 + cv2

我有一个代码可以将视频分解成帧并编辑图像并将其放回视频中,但我意识到它真的很慢......所以我研究了多处理来加速代码,它作品!正如我所见,它处理图像的速度要快得多,但问题是,当我将这些帧添加到新视频时,它不起作用,视频仍然是空的!

这是我的代码

# Imports
import cv2,sys,time
import numpy as np

from scipy.ndimage import rotate
from PIL import Image,ImageDraw,ImageFont,ImageOps
import concurrent.futures
def function(fullimg):
    img = np.array(Image.fromarray(fullimg).crop((1700,930,1920-60,1080-80)))
    inpainTradius = 10
    inpaintMethod = cv2.INPAINT_TELEA
    textMask = cv2.imread('permanentmask.jpg',0)
    final_result = cv2.inpaint(img.copy(),textMask,inpainTradius,inpaintMethod)
    text = Image.fromarray(np.array([np.array(i) for i in final_result]).astype(np.uint8)).convert('RGBA')
    im = np.array([[tuple(x) for x in i] for i in np.zeros((70,160,4))])
    im[1:-1,1:-1] = (170,13,5,40)
    im[0,:] = (0,128)
    im[1:-1,[0,-1]] = (0,128)
    im[-1,128)
    im = Image.fromarray(im.astype(np.uint8))
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype('arialbd.ttf',57)
    draw.text((5,5),"TEXT",(255,255,128),font=font)
    text.paste(im,mask=im)
    text = np.array(text)
    fullimg = Image.fromarray(fullimg)
    fullimg.paste(Image.fromarray(text),(1700,1080-80))
    fullimg = cv2.cvtColor(np.array(fullimg),cv2.COLOR_BGR2RGB)
    return fullimg
cap = cv2.VideoCapture('before2.mp4')
_fourcc = cv2.VideoWriter_fourcc(*'MPEG')
out = cv2.VideoWriter('after.mp4',_fourcc,29.97,(1280,720))
frames = []
lst = []
while cap.isOpened():
    ret,fullimg = cap.read()
    if not ret:
        break
    frames.append(fullimg)
    
    if len(frames) >= 8:
        if __name__ == '__main__':
            with concurrent.futures.ProcesspoolExecutor() as executor:
                results = executor.map(function,frames)
                for i in results:
                    print(type(i))
                    out.write(i)
        frames.clear() 
cap.release()
out.release()
cv2.destroyAllWindows() # destroy all opened windows

我的代码使用 PIL 修复水印并添加一个水印。

如果我不使用 multiprocessing 代码有效。但如果我确实使用 multiprocessing,它会给出一个空视频。

解决方法

我对 OpenCV 不太熟悉,但您的代码中似乎有一些地方需要更正。首先,如果您在 Windows 下运行,因为您有 if __name__ == '__main__': 保护创建新进程的代码(顺便说一句,当您使用 multiprocessing 标记问题时,您还应该标记正在使用的平台的问题),那么全局范围内的任何代码都将由为实现您的池而创建的每个进程执行。这意味着您应该按如下方式移动 if __name__ == '__main__':

if __name__ == '__main__':
    cap = cv2.VideoCapture('before2.mp4')
    _fourcc = cv2.VideoWriter_fourcc(*'MPEG')
    out = cv2.VideoWriter('after.mp4',_fourcc,29.97,(1280,720))
    frames = []
    lst = []
    while cap.isOpened():
        ret,fullimg = cap.read()
        if not ret:
            break
        frames.append(fullimg)
        
        if len(frames) >= 8:
            with concurrent.futures.ProcessPoolExecutor() as executor:
                results = executor.map(function,frames)
                for i in results:
                    print(type(i))
                    out.write(i)
            frames.clear() 
    cap.release()
    out.release()
    cv2.destroyAllWindows() # destroy all opened windows

如果你不这样做,在我看来,池中的每个子进程都会首先尝试并行创建一个空视频(function 工作函数和 out.write 永远不会被调用由这些进程),只有这样主进程才能使用 function 调用 map 工作函数。这并不能完全解释为什么在所有这些浪费的尝试之后主进程没有成功。但是...

你还有:

while cap.isOpened():

文档指出,如果前一个 isOpened() 构造函数成功,则 True 返回 VideoCapture。那么如果它返回 True 一次,为什么它下次测试时不返回 True 并且最终无限循环?不应该将 while 更改为 if 吗?这是否意味着 isOpened() 可能正在返回 False 否则您将无限循环?或者如果 len(frames) < 8 怎么办?看来你最终也会得到一个空的输出文件。

我的建议是进行上述更改并重试。

更新

我更仔细地查看了代码,它似乎正在循环读取输入(before2.mp4),一次一帧,当它累积了 8 帧或更多帧时创建一个池并处理它积累的帧并将它们写出到输出 (after.mp4)。但这意味着,例如,如果还有 8 个帧,它将创建一个全新的处理池(非常浪费和昂贵),然后写出 8 个额外的处理帧。但是如果只有 7 个额外的帧,它们将永远不会被处理和写出。我建议使用以下代码(当然未经测试):

def main():
    import os

    cap = cv2.VideoCapture('before2.mp4')
    if not cap.isOpened():
        return

    _fourcc = cv2.VideoWriter_fourcc(*'MPEG')
    out = cv2.VideoWriter('after.mp4',720))

    FRAMES_AT_A_TIME = 8
    pool_size = min(FRAMES_AT_A_TIME,os.cpu_count())
    with concurrent.futures.ProcessPoolExecutor(max_workers=pool_size) as executor:
        more_frames = True

        while more_frames:
            frames = []
            for _ in range(FRAMES_AT_A_TIME):
                ret,fullimg = cap.read()
                if not ret:
                    more_frames = False
                    break
                frames.append(fullimg)

            if not frames:
                break # no frames        

            results = executor.map(function,frames)
            for i in results:
                print(type(i))
                out.write(i)

    cap.release()
    out.release()
    cv2.destroyAllWindows() # destroy all opened windows

if __name__ == '__main__':
    main()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。