17

OSX でウェブカメラを読み込んでいますが、これは次の単純なスクリプトで正常に動作します。

import cv2
camera = cv2.VideoCapture(0)

while True:
    try:
        (grabbed, frame) = camera.read()  # grab the current frame
        frame = cv2.resize(frame, (640, 480))  # resize the frame
        cv2.imshow("Frame", frame)  # show the frame to our screen
        cv2.waitKey(1)  # Display it at least one ms before going to the next frame
    except KeyboardInterrupt:
        # cleanup the camera and close any open windows
        camera.release()
        cv2.destroyAllWindows()
        print "\n\nBye bye\n"
        break

私は今、ビデオを別のプロセスで読みたいと思っています。スクリプトははるかに長く、Linux の別のプロセスでビデオを正しく読み込んでいます。

import numpy as np
import time
import ctypes
import argparse

from multiprocessing import Array, Value, Process
import cv2


class VideoCapture:
    """
    Class that handles video capture from device or video file
    """
    def __init__(self, device=0, delay=0.):
        """
        :param device: device index or video filename
        :param delay: delay between frame captures in seconds(floating point is allowed)
        """
        self._cap = cv2.VideoCapture(device)
        self._delay = delay

    def _proper_frame(self, delay=None):
        """
        :param delay: delay between frames capture(in seconds)
        :param finished: synchronized wrapper for int(see multiprocessing.Value)
        :return: frame
        """
        snapshot = None
        correct_img = False
        fail_counter = -1
        while not correct_img:
            # Capture the frame
            correct_img, snapshot = self._cap.read()
            fail_counter += 1
            # Raise exception if there's no output from the device
            if fail_counter > 10:
                raise Exception("Capture: exceeded number of tries to capture the frame.")
            # Delay before we get a new frame
            time.sleep(delay)
        return snapshot

    def get_size(self):
        """
        :return: size of the captured image
        """
        return (int(self._cap.get(int(cv2.CAP_PROP_FRAME_HEIGHT))),
                int(self._cap.get(int(cv2.CAP_PROP_FRAME_WIDTH))), 3)

    def get_stream_function(self):
        """
        Returns stream_function object function
        """

        def stream_function(image, finished):
            """
            Function keeps capturing frames until finished = 1
            :param image: shared numpy array for multiprocessing(see multiprocessing.Array)
            :param finished: synchronized wrapper for int(see multiprocessing.Value)
            :return: nothing
            """
            # Incorrect input array
            if image.shape != self.get_size():
                raise Exception("Capture: improper size of the input image")
            print("Capture: start streaming")
            # Capture frame until we get finished flag set to True
            while not finished.value:
                image[:, :, :] = self._proper_frame(self._delay)
            # Release the device
            self.release()

        return stream_function

    def release(self):
        self._cap.release()


def main():
    # Add program arguments
    parser = argparse.ArgumentParser(description='Captures the video from the webcamera and \nwrites it into the output file with predefined fps.', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-output', dest="output",  default="output.avi", help='name of the output video file')
    parser.add_argument('-log', dest="log",  default="frames.log", help='name of the log file')
    parser.add_argument('-fps', dest="fps",  default=25., help='frames per second value')

    # Read the arguments if any
    result = parser.parse_args()
    fps = float(result.fps)
    output = result.output
    log = result.log

    # Initialize VideoCapture object and auxilary objects
    cap = VideoCapture()
    shape = cap.get_size()
    stream = cap.get_stream_function()

    # Define shared variables(which are synchronised so race condition is excluded)
    shared_array_base = Array(ctypes.c_uint8, shape[0] * shape[1] * shape[2])
    frame = np.ctypeslib.as_array(shared_array_base.get_obj())
    frame = frame.reshape(shape[0], shape[1], shape[2])
    finished = Value('i', 0)

    # Start processes which run in parallel
    video_process = Process(target=stream, args=(frame, finished))
    video_process.start()  # Launch capture process

    # Sleep for some time to allow videocapture start working first
    time.sleep(2)

    # Termination function
    def terminate():
        print("Main: termination")
        finished.value = True
        # Wait for all processes to finish
        time.sleep(1)
        # Terminate working processes
        video_process.terminate()

    # The capturing works until keyboard interrupt is pressed.
    while True:
        try:
            # Display the resulting frame
            cv2.imshow('frame', frame)
            cv2.waitKey(1)  # Display it at least one ms before going to the next frame
            time.sleep(0.1)

        except KeyboardInterrupt:
            cv2.destroyAllWindows()
            terminate()
            break

if __name__ == '__main__':
    main()

.read()これは Linux では問題なく動作しますが、OSX では、作成されたcv2.VideoCapture(device)オブジェクト ( var に格納されている)に対して実行できないように見えるため、問題が発生していますself._cap

いくつかの検索の後、私はこの SO answerを見つけました。これは、おそらくいくつかの非常に有用な改善があると思われる pythons multiprocessing の代替であるBilliardを使用することを提案しています。したがって、ファイルの先頭で、以前のマルチプロセッシング インポートの後にインポートを追加しただけです (効果的にオーバーライドしますmultiprocessing.Process)。

from billiard import Process, forking_enable

video_process変数のインスタンス化の直前に、次のように使用forking_enableします。

forking_enable(0)  # Supposedly this is all I need for billiard to do it's magic
video_process = Process(target=stream, args=(frame, finished))

したがって、このバージョン(ここでは Pastebin)でファイルを再度実行すると、次のエラーが発生します。

pickle.PicklingError: ピクルできません:メインの.stream_functionとして見つかりません

そのエラーを検索すると、答えの長いリストを含む SO の質問にたどり着きました。そのうちの 1 つは、これを解決するためにdill シリアライゼーション ライブラリを使用することを提案しました。ただし、その lib はPathos マルチプロセッシング フォークで使用する必要があります。だから私は単純にマルチプロセッシングのインポート行を

from multiprocessing import Array, Value, Process

from pathos.multiprocessing import Array, Value, Process

しかし、Array、 、ValueおよびはパッケージProcessに存在しないようです。pathos.multiprocessing

そして、この時点から、私は完全に迷っています。私はほとんど十分な知識を持っていないものを探しています。また、どの方向に検索またはデバッグする必要があるかさえわかりません。

では、私よりも明るい魂が、別のプロセスでビデオをキャプチャするのを手伝ってくれるでしょうか? すべてのヒントは大歓迎です!

4

2 に答える 2