2011-02-03 4 views
10

私は、MacBook Proに組み込まれているApple iSightカメラからPython(バージョン2.7または2.6)とPyObjC(バージョン2.2)を使用して単一のフレームをキャプチャしようとしています。PythonとPyObjCを使用してApple iSightからフレームをキャプチャする方法は?

出発点として、this old StackOverflow質問を使用しました。それが意味をなさないことを確認するために、私はApple's MyRecorderの例とクロスリファレンスしています。残念ながら、私のスクリプトは動作しません。

私の大きな疑問は、次のとおりです。

  • 私はカメラを正しく初期化するだろうか?
  • イベントループを正しく開始していますか?
  • 私がやるべき他の設定はありましたか?

以下に貼り付けられたスクリプトの例では、startImageCapture()を呼び出した後、CaptureDelegateから「Got a frame ...」というメッセージが表示されます。ただし、カメラのライトがオンになることはなく、デリゲートのコールバックは決して実行されません。

また、startImageCapture()中にエラーは発生せず、すべての関数が成功すると主張し、正常にiSightデバイスを検出します。 pdbのセッションオブジェクトを分析すると、有効な入出力オブジェクトがあり、出力には代理人が割り当てられ、別のプロセスではデバイスは使用されておらず、startRunning()が呼び出された後にセッションは実行中とマークされます。あなたが提供することができます任意の助け

#!/usr/bin/env python2.7 

import sys 
import os 
import time 
import objc 
import QTKit 
import AppKit 
from Foundation import NSObject 
from Foundation import NSTimer 
from PyObjCTools import AppHelper 
objc.setVerbose(True) 

class CaptureDelegate(NSObject): 
    def captureOutput_didOutputVideoFrame_withSampleBuffer_fromConnection_(self, captureOutput, 
                      videoFrame, sampleBuffer, 
                      connection): 
     # This should get called for every captured frame 
     print "Got a frame: %s" % videoFrame 

class QuitClass(NSObject): 
    def quitMainLoop_(self, aTimer): 
     # Just stop the main loop. 
     print "Quitting main loop." 
     AppHelper.stopEventLoop() 


def startImageCapture(): 
    error = None 

    # Create a QT Capture session 
    session = QTKit.QTCaptureSession.alloc().init() 

    # Find iSight device and open it 
    dev = QTKit.QTCaptureDevice.defaultInputDeviceWithMediaType_(QTKit.QTMediaTypeVideo) 
    print "Device: %s" % dev 
    if not dev.open_(error): 
     print "Couldn't open capture device." 
     return 

    # Create an input instance with the device we found and add to session 
    input = QTKit.QTCaptureDeviceInput.alloc().initWithDevice_(dev) 
    if not session.addInput_error_(input, error): 
     print "Couldn't add input device." 
     return 

    # Create an output instance with a delegate for callbacks and add to session 
    output = QTKit.QTCaptureDecompressedVideoOutput.alloc().init() 
    delegate = CaptureDelegate.alloc().init() 
    output.setDelegate_(delegate) 
    if not session.addOutput_error_(output, error): 
     print "Failed to add output delegate." 
     return 

    # Start the capture 
    print "Initiating capture..." 
    session.startRunning() 


def main(): 
    # Open camera and start capturing frames 
    startImageCapture() 

    # Setup a timer to quit in 10 seconds (hack for now) 
    quitInst = QuitClass.alloc().init() 
    NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(10.0, 
                      quitInst, 
                      'quitMainLoop:', 
                      None, 
                      False) 
    # Start Cocoa's main event loop 
    AppHelper.runConsoleEventLoop(installInterrupt=True) 

    print "After event loop" 


if __name__ == "__main__": 
    main() 

ありがとう:

は、ここでは、コードです!

答えて

15

OK、私はPyObjCの深みで一日を過ごし、それを働かせました。

将来の記録のために、問題のコードが機能しなかった理由:可変スコープとガベージコレクションセッション変数は、スコープ外になったときに削除されました。これは、イベントプロセッサが実行される前に発生しました。それを保持するために何かをしなければならないので、実行する前に解放されません。

すべてをクラスに移動し、セッションにクラス変数を設定すると、コールバックが機能し始めます。さらに、以下のコードは、フレームのピクセルデータをビットマップ形式にして、Cocoaの呼び出しで保存する方法と、バッファや文字列としてPythonのワールドビューにコピーする方法を示しています。

以下のスクリプトは

#!/usr/bin/env python2.7 
# 
# camera.py -- by Trevor Bentley (02/04/2011) 
# 
# This work is licensed under a Creative Commons Attribution 3.0 Unported License. 
# 
# Run from the command line on an Apple laptop running OS X 10.6, this script will 
# take a single frame capture using the built-in iSight camera and save it to disk 
# using three methods. 
# 

import sys 
import os 
import time 
import objc 
import QTKit 
from AppKit import * 
from Foundation import NSObject 
from Foundation import NSTimer 
from PyObjCTools import AppHelper 

class NSImageTest(NSObject): 
    def init(self): 
     self = super(NSImageTest, self).init() 
     if self is None: 
      return None 

     self.session = None 
     self.running = True 

     return self 

    def captureOutput_didOutputVideoFrame_withSampleBuffer_fromConnection_(self, captureOutput, 
                      videoFrame, sampleBuffer, 
                      connection): 
     self.session.stopRunning() # I just want one frame 

     # Get a bitmap representation of the frame using CoreImage and Cocoa calls 
     ciimage = CIImage.imageWithCVImageBuffer_(videoFrame) 
     rep = NSCIImageRep.imageRepWithCIImage_(ciimage) 
     bitrep = NSBitmapImageRep.alloc().initWithCIImage_(ciimage) 
     bitdata = bitrep.representationUsingType_properties_(NSBMPFileType, objc.NULL) 

     # Save image to disk using Cocoa 
     t0 = time.time() 
     bitdata.writeToFile_atomically_("grab.bmp", False) 
     t1 = time.time() 
     print "Cocoa saved in %.5f seconds" % (t1-t0) 

     # Save a read-only buffer of image to disk using Python 
     t0 = time.time() 
     bitbuf = bitdata.bytes() 
     f = open("python.bmp", "w") 
     f.write(bitbuf) 
     f.close() 
     t1 = time.time() 
     print "Python saved buffer in %.5f seconds" % (t1-t0) 

     # Save a string-copy of the buffer to disk using Python 
     t0 = time.time() 
     bitbufstr = str(bitbuf) 
     f = open("python2.bmp", "w") 
     f.write(bitbufstr) 
     f.close() 
     t1 = time.time() 
     print "Python saved string in %.5f seconds" % (t1-t0) 

     # Will exit on next execution of quitMainLoop_() 
     self.running = False 

    def quitMainLoop_(self, aTimer): 
     # Stop the main loop after one frame is captured. Call rapidly from timer. 
     if not self.running: 
      AppHelper.stopEventLoop() 

    def startImageCapture(self, aTimer): 
     error = None 
     print "Finding camera" 

     # Create a QT Capture session 
     self.session = QTKit.QTCaptureSession.alloc().init() 

     # Find iSight device and open it 
     dev = QTKit.QTCaptureDevice.defaultInputDeviceWithMediaType_(QTKit.QTMediaTypeVideo) 
     print "Device: %s" % dev 
     if not dev.open_(error): 
      print "Couldn't open capture device." 
      return 

     # Create an input instance with the device we found and add to session 
     input = QTKit.QTCaptureDeviceInput.alloc().initWithDevice_(dev) 
     if not self.session.addInput_error_(input, error): 
      print "Couldn't add input device." 
      return 

     # Create an output instance with a delegate for callbacks and add to session 
     output = QTKit.QTCaptureDecompressedVideoOutput.alloc().init() 
     output.setDelegate_(self) 
     if not self.session.addOutput_error_(output, error): 
      print "Failed to add output delegate." 
      return 

     # Start the capture 
     print "Initiating capture..." 
     self.session.startRunning() 


    def main(self): 
     # Callback that quits after a frame is captured 
     NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.1, 
                       self, 
                       'quitMainLoop:', 
                       None, 
                       True) 

     # Turn on the camera and start the capture 
     self.startImageCapture(None) 

     # Start Cocoa's main event loop 
     AppHelper.runConsoleEventLoop(installInterrupt=True) 

     print "Frame capture completed." 

if __name__ == "__main__": 
    test = NSImageTest.alloc().init() 
    test.main() 
+0

クールマン、btwあなたは自分自身を「受け入れた」とマークする必要があります:) –

+0

このスクリプトはうまくいきますが、バイトファイルを書くときには失敗します。バイトモードでファイルを開くには、open( 'filename'、 'w')をopen( 'filename'、 'wb')に変更する必要があります。 – andli

0

QTKitは非推奨とPyObjCは大きな依存である(そして、あなたが自作でそれをしたい場合は構築するのが難しいように思われる)単一のフレームをキャプチャします。プラスPyObjCAVFoundationの大部分を持っていませんでしたので、AVFoundationを使ってビデオを録画したり画像をスナップしたりするのに、a simple camera extension for Pythonを作成しました。依存関係は必要ありません(Cythonの中間ファイルはほとんどのユーザーにとってCythonを必要としません)。

このようにそれを構築することが可能なはずである:この質問に関連していない

import pyavfcam 

# Open the default video source 
cam = pyavfcam.AVFCam(sinks='image') 
frame = cam.snap_picture('test.jpg') # frame is a memory buffer np.asarray(frame) can retrieve 

が、AVFCamクラスがサブである場合:

pip install -e git+https://github.com/dashesy/pyavfcam.git 

その後、我々はtake a pictureにそれを使用することができますオーバーライドされたメソッドが結果とともに呼び出されます。

+0

pipインストールが失敗します: '' pip install -e git + https://github.com/dashesy/pyavfcam.git --editable = git + https://github.com/dashesy/pyavfcam。 gitは正しい形式ではありません。それは#egg = Package''でなければなりません – DanHickstein

関連する問題