2

I'm running OpenCV 2.4.5 via the cv2 python bindings, using OS X (10.8.4). I'm trying to capture images from a USB webcam in a separate process via the multiprocessing module. Everything seems to work if I use my laptop's (2011 macbook air) internal webcam, but when I attempt to read from a usb webcam (Logitech C920), I get a crash (no crash when I use the USB cam without the multiprocessing encapsulation). The crash log is here. Code I'm using that will reliably reproduce the crash is below. Getting this working is pretty mission-critical for me, so any help would be greatly appreciated!

import multiprocessing
import cv2 #doesn't matter if you import here or in cam()

def cam():
    vc = cv2.VideoCapture(0) #modify 0/1 to toggle between USB and internal camera
    while True:
        junk,image = vc.read()

camProcess = multiprocessing.Process( target=cam )
camProcess.start()

while True:
    pass
Mike Lawrence
  • 1,641
  • 5
  • 20
  • 40
  • Is the USB cam working if used without the multiprocessing encapsulation? – Robert Caspary Aug 22 '13 at 13:30
  • @RobertCaspary: Yup, the USB cam is working without the multiprocessing encapsulation. (edited question to clarify) – Mike Lawrence Aug 22 '13 at 13:46
  • Ok, I'm out...your code runs fine on Win7 with Python 2.6. Since I can't read/understand the crash log, I would try to create a "real" Process object and try the [different start]methods(http://docs.python.org/dev/library/multiprocessing.html#start-methods) – Robert Caspary Aug 22 '13 at 14:29
  • @RobertCaspary: The ability to specify start methods seems to be new to the python 3.4 version of the multiprocessing module. Maybe I'll install python 3.4 and try that out. – Mike Lawrence Aug 22 '13 at 14:39
  • Try to use different API, maybe there is a bug in some of libraries/drivers - http://stackoverflow.com/questions/14187866/opencv-on-mac-not-opening-usb-web-camera/14188280#14188280 (it's for c++, but can be easily translated to Python) – cyriel Aug 22 '13 at 22:50
  • @cyriel: Thanks for the advice, but no luck. Without using multiprocessing, the only one that works is 500, CV_CAP_QT, all others return None when I later attempt to read an image from the camera. All others similarly return None when I try to read while inside a forked multiprocessing process, and 500 reproduces the crash. – Mike Lawrence Aug 23 '13 at 01:39

1 Answers1

6

Your problem stems from the way python spans its subprocess using os.fork. The OpenCV video backend on Mac uses QTKit which uses CoreFoundation these parts of MacOS are not save to run in a forked subprocess, sometimes they just complain, sometimes they crash.

You need to create the subprocess without using os.fork. This can be achieved with python 2.7.

You need to use billiard (https://github.com/celery/billiard/tree/master/billiard) It serves as a replacement for pythons multiprocessing and has some very useful improvements.

from billiard import Process, forking_enable
import cv2 #does matter where this happens when you don't use fork

def cam():
    vc = cv2.VideoCapture(0) #modify 0/1 to toggle between USB and internal camera
    while True:
        junk,image = vc.read()

forking_enable(0) # Is all you need!
camProcess = Process( target=cam )
camProcess.start()

while True:
    pass

alright, lets add a more complete example:

from billiard import Process, forking_enable

def cam(cam_id):
    import cv2 #doesn't matter if you import here or in cam()
    vc = cv2.VideoCapture(cam_id) #modify 0/1 to toggle between USB and internal camera
    while True:
        junk,image = vc.read()
        cv2.imshow("test",image)
        k = cv2.waitKey(33)
        if k==27:    # Esc key to stop
            break

def start():

    forking_enable(0) # Is all you need!
    camProcess = Process(target=cam, args=(0,))
    camProcess.start()


if __name__ == '__main__':
    start()
    cam(1)

You need two cameras attached for this:It should open a window and run each camera in a separate process (one on the main process one in a spawned one). I use this strategy to stream images form multiple cameras at once each in its own python process.

mkassner
  • 96
  • 1
  • 5
  • Ah, I spoke too soon; while your code makes the crash not happen, what happens instead is that all my cpus max out and the cam process seemingly hangs. If you try to do anything with the image (ex. `cv2.imwrite('temp.png',image)` python crashes. – Mike Lawrence Nov 16 '13 at 14:48
  • 1
    do the cv import inside the process, basically treat the separate process as completely separate and use Pipes/Queues/Events/Shared Variable passed as arguments as IPC. – mkassner Nov 18 '13 at 12:36