Posted by Armin on Wednesday, June 08, 2011
A Python script that's using OpenCV to open a video, loop it, and trigger playback via a command coming from the serial port (where in my case an Arduino is connected) or a key press. Playback stops after a timer has run out and commences after another trigger event.
Trigger Quicktime video playback via Arduino
The script below is using OpenCV to open a video file, loop it, and then trigger playback when a command coming from the serial port (where in my case an Arduino is connected) is received, or when a key is pressed. Playback stops after a timer has run out and commences after another trigger event.
Aside: OpenCV with Python on a Mac
I'm in the learning phase of both Python and OpenCV (http://opencv.willowgarage.com/wiki/), and thought I'd post my successful scripts here for future reference.
After struggling for quite a while, I've finally managed to install OpenCV with bindings for Python 2.6 on my MacBook Pro. I installed opencv @2.2.0_0+python26 through MacPorts, and no problems were encountered. (When trying to add Python bindings for OpenCV to the Enthought Python Distribution I also have on my computer, all I got was frustration.) Now if I could only overcome the difficulties of installing wxpython via macports, I could just live with one single Python distribution... the 32 and 64 bit mess is going to drive me crazy one day.
The Python Script
This script opens an AVI file and displays it in a window.
#!/opt/local/bin/python # Script to play a video file in response to a button press event # Pressing "x" or receiving an 'x' over the serial port starts video playback # counter_dur defines for how long movie will play # video loops until "ESC" is pressed # # uses the openCV highgui for the moment. wxpython or pyqt would be better, probably # to get rid of window decorations # Armin Hinterwirth, June 2011 import cv import time import sys import serial curpos = 0 counter_dur = 1 counter_time = time.time() # initialize timer # Arduino object that deals with serial communication: class Arduino(): def __init__(self): self.connected = 0 def connect(self): try: serialport = "/dev/tty.usbserial-A7006xMg" # serialport needs to be set accordingly self.arduino = serial.Serial(serialport, 9600, timeout=0) self.connected = 1 print 'Connected to Arduino' except: print "Failed to connect on /dev/tty.usbserial-A7006xMg" print '(Arduino not connected)' self.connected = 0 def readSerial(self): if self.isConnected(): cmd = self.arduino.read() #read one byte return cmd else: print("SerialRead unsuccessful") def isConnected(self): if self.connected == 1: return True def counter_expired(counter_time): cur_time = time.time() # print "%.2f" % (cur_time - counter_time) # debug: print timer values if (cur_time - counter_time) > counter_dur: return True def showMovieFrame(cam1,frames): frame = cv.QueryFrame(cam1) if (frame==None): sys.exit(2); curpos = int(cv.GetCaptureProperty(cam1, cv.CV_CAP_PROP_POS_FRAMES)) # print "Frame: " + str(curpos) # show the image: cv.ShowImage("viewer", frame) # 'rewind' if end is reached: if (curpos > frames-2): cv.SetCaptureProperty(cam1,cv.CV_CAP_PROP_POS_FRAMES, 0) def main(): arduino = Arduino() arduino.connect() time.sleep(1) # give it some time cv.NamedWindow("viewer", 0) cv.MoveWindow("viewer", 300, -20 ); cam1 = cv.CaptureFromFile('movingStripe.avi') # cam1 = cv.CaptureFromFile('grating.avi') # get first frame and display it: frame = cv.QueryFrame(cam1) if (frame == None): sys.exit(2) curpos = int(cv.GetCaptureProperty(cam1, cv.CV_CAP_PROP_POS_FRAMES)) # print curpos cv.ShowImage("viewer", frame) frames = long(cv.GetCaptureProperty(cam1, cv.CV_CAP_PROP_FRAME_COUNT)) print "Movie length: " + str(frames) + " frames" outerloop = True # waiting for serial command innerloop = False # video playback loop while(outerloop): if arduino.isConnected(): cmd = arduino.readSerial() if (cmd == None): print("no serial received") if (cmd == 'x'): counter_time = time.time() # set the timer innerloop = True char = cv.WaitKey(1) # check which keys were pressed: if (char == 120): counter_time = time.time() # set the timer innerloop = True elif (char==102): showMovieFrame(cam1,frames) elif (char ==27): sys.exit(2) while(innerloop): showMovieFrame(cam1,frames) char = cv.WaitKey(1) # end the program if esc button is pressed: if (char == 27): sys.exit(2) # get out of the loop if counter is expired: if counter_expired(counter_time): print("timer expired") innerloop = False if __name__ == '__main__': main()
The Arduino Code
The Arduino is sending out a serial command ('x') every time the button is pressed. It also blinks for 200 ms to provide visual feedback and a sharp marker for measuring the delay between button press events and onset of playback.
/* * Button2Serial * * Button press leads to serial command * Armin Hinterwirth, June 2011 * */ const int buttonPin = 2; const int ledPin = 13; long debounce = 200; // debounce time for button in ms byte buttonState = LOW; void setup() { pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); Serial.begin(9600); // serial comm. for triggering } void loop() { // read the switch state: buttonState = digitalRead(buttonPin); // turn ledPin high if button is pressed (button drops to low, then) serialTalk(); digitalWrite(ledPin, HIGH); delay(200); digitalWrite(ledPin, LOW); } } void serialTalk() { Serial.print("x"); // print an 'x' when button is pressed }