Запускать несколько видео через многопроцессорную обработку с использованием одновременного будущего - PullRequest
1 голос
/ 03 апреля 2020

Я пытаюсь запустить код с использованием concurrent.futres.ProcessPoolExecuter, но при запуске видео в состоянии while true в class get_frames

concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.

встречается указанная ниже ошибка.

import cv2
import numpy as np
import imutils
import os
import threading
import concurrent.futures
import time

start = time.perf_counter()

class VideoCapture:

    def __init__(self, name):
        self.cap = cv2.VideoCapture(name)
        self.q = queue.Queue()
        t = threading.Thread(target=self._reader)
        # t.get_ident()
        t.start()
        t.daemon = True

    # read frames as soon as they are available, keeping only most recent one
    def _reader(self):
        while True:
            ret, frame = self.cap.read()
            if not ret:
                break
            if not self.q.empty():
                try:
                    self.q.get_nowait()  # discard previous (unprocessed) frame
                except Queue.Empty:
                    pass
            self.q.put(frame)

    @classmethod
    def read(cls):
        return cls(self.q.get())


names = ['test.mp4', 'test1.mp4']

frames = [None] * len(names);
#frame_in = [None] * len(names);
ret = [None] * len(names);

cap_list = [cv2.VideoCapture(k) for k in names]


# print(cap_list)

class get_frames:

    def __init__(self, cap, name):
        self.cap = cap
        self.name = name
        # print(self.cap)

    def display_frames(self):
        while True:
            ret, frames = self.cap.read()
            if ret is True:
                count += 1
                print(self.name)


with concurrent.futures.ProcessPoolExecutor(max_workers=3) as executor:
    for i, cap in enumerate(cap_list):
        g_f = get_frames(cap, i)
    results = executor.map(g_f.display_frames, cap_list)
    print(results)

Любое предложение по этому вопросу поможет вам

1 Ответ

0 голосов
/ 04 апреля 2020

Вы можете придерживаться примера ProcessPoolExecutor .

Пример выглядит следующим образом:

def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()
  • Вы должны использовать синтаксис if __name__ == '__main__':.
    Поместите код подготовки как cap_list = [cv2.VideoCapture(k) for k in names] в методе main() .
    Без этого весь скрипт выполняется несколько раз и застревает.
  • В примере используется метод, а не объект.
    Полагаю, вы можете отобразить методы объекта, но я не смог заставить его работать.
  • При использовании Python 3.6 я получаю сообщение об ошибке: "TypeError: can't pickle cv2.VideoCapture objects".
    Я передаю имя файла display_frames и выполняю cv2.VideoCapture в начале метода display_frames .
  • Код, который вы опубликовали, не использует class VideoCapture.

Для тестирования:

  • В моем примере создаются синтетические c видеофайлы ( чтобы сделать пример "самодостаточным").
  • В примере показаны видеокадры для тестирования.

Вот код:

import cv2
import numpy as np
import concurrent.futures

def display_frames(name):
    cap = cv2.VideoCapture(name)

    while True:
        ret, frames = cap.read()

        if ret is False:
            break

        # Show frames for testing:
        cv2.imshow(str(cap), frames)
        cv2.waitKey(100)

    cap.release()

    return name


def main():
    names = ['test2.mp4', 'test3.mp4']

    # Generate two synthetic video files to be used as input:
    ###############################################################################
    width, height, n_frames = 640, 480, 30  # 30 frames, resolution 640x480

    intput_filename1 = names[0]
    intput_filename2 = names[1]

    # Use MPEG4 codec (for testing)
    synthetic_out = cv2.VideoWriter(intput_filename1, cv2.VideoWriter_fourcc(*'mp4v'), 25, (width, height))

    for i in range(n_frames):
        img = np.full((height, width, 3), 60, np.uint8)
        cv2.putText(img, str(i+1), (width//2-100*len(str(i+1)), height//2+100), cv2.FONT_HERSHEY_DUPLEX, 10, (30, 255, 30), 20)  # Green number
        synthetic_out.write(img)

    synthetic_out.release()

    width, height, n_frames = 320, 240, 20 # 20 frames, resolution 320x240
    synthetic_out = cv2.VideoWriter(intput_filename2, cv2.VideoWriter_fourcc(*'mp4v'), 25, (width, height))

    for i in range(n_frames):
        img = np.full((height, width, 3), 60, np.uint8)
        cv2.putText(img, str(i+1), (width//2-50*len(str(i+1)), height//2+50), cv2.FONT_HERSHEY_DUPLEX, 5, (255, 30, 30), 10)  # Blue number
        synthetic_out.write(img)

    synthetic_out.release()
    ###############################################################################


    with concurrent.futures.ProcessPoolExecutor(max_workers=3) as executor:
        for name in executor.map(display_frames, names):
            print(name)

    cv2.destroyAllWindows() # For testing


# Using Python 3.6 there is an error: "TypeError: can't pickle cv2.VideoCapture objects"
if __name__ == '__main__':
    main()

Я действительно не знаю, отвечает ли он на ваш вопрос, потому что от вашего исходного кода осталось немногое.
Надеюсь это помогает ...

...