Exporting experiment to a .mov or mp4 file

I’ve created some images using PsychoPy that I would like to save as a movie. Is there a possible way to export the experiment to a “movie”?

Thank you very much!

Insert a code component and put it beneath all of your stimulus components. In the Every frame tab, put this:

# store an image of every upcoming screen refresh:
win.getMovieFrame(buffer='back') 

In the End routine tab, put something like this:

# combine all of those frames in a single movie file:
win.saveMovieFrames(fileName='some file.mp4')

You probably want to comment out those lines when collecting data, as it could cause delays. i.e. just use this once to produce your demo movie, and then disable it when running actual subjects in your experiment

Regards,

Michael

1 Like

Wow, so wonderful to receive a reply so soon! I will try and update with a (hopefully) working solution/confirmation. @m-macaskill

Hello again,

Below is the code created by the Builder. This is just a quick troubleshooting version; I simply inserted one polygon on the screen. I’m attempting to use the bits of code you provided in your answer, but I’m not sure I’m placing them in the right places. I think there might also be issues due to the .mov? @m-macaskill

MovieDemoV1.py (5.7 K

It’s generally much easier for us to see the Builder .psyexp file than the generated .py file, but it does look like you put the win.getMovieFrame(buffer='back') line in the Begin routine tab rather than the Every frame tab.

Doing it like that will just get you one screenshot per trial rather than one per screen refresh, and that screenshot would be from before any of your stimuli were actually drawn.

But having said that, you don’t really mention what problem(s) you encountered. You should describe the issues and paste in any error messages.

MovieDemoV1.psyexp (3.4 KB)

Sorry about that. Hopefully, this file is more helpful to you. Would you be able to point out which line number is the Every Frame tab? Perhaps my tired eyes are just missing it all together. @m-macaskill

Error when using .mp4 extension:
Traceback (most recent call last):
File “/Users/michaeladebolt/Documents/MovieDemoV1.py”, line 140, in
win.saveMovieFrames(fileName=‘some file.mp4’)
File “/Applications/PsychoPy2.app/Contents/Resources/lib/python2.7/psychopy/visual/window.py”, line 960, in saveMovieFrames
self.movieFrames[0].save(fileName)
File “/Applications/PsychoPy2.app/Contents/Resources/lib/python2.7/PIL/Image.py”, line 1672, in save
format = EXTENSION[ext]
KeyError: ‘.mp4’

Error when using the .mov extension:
File “/Applications/PsychoPy2.app/Contents/Resources/lib/python2.7/psychopy/visual/window.py”, line 958, in saveMovieFrames
raise NotImplementedError(msg)
NotImplementedError: Support for Quicktime movies has been removed (at least for now). You need to export your frames as images (e.g. png files) and combine them yourself (e.g. with ffmpeg)

Ahh, OK, much clearer now when seeing the Builder file. You missed this bit of the instructions:[quote=“m-macaskill, post:2, topic:936”]
Insert a code component and put it beneath all of your stimulus components
[/quote]

See the right hand “Components” pane in Builder? Click on “Custom” to reveal the Code Component button. You need to put the code in the relevant tabs in the resulting dialog box there. Don’t attempt to edit the generated .py file:

(1) Builder regenerates it all the time, overwriting any changes you make. If you want to use an edited .py file, you have to save it separately and then can’t edit it via the graphical Builder interface anymore.
(2) It’s hard to know where to put code so it gets executed at the right time. That is what the code component does for you automatically: placing code at the beginning of the experiment, routine, every frame, etc.

Re the movie errors, see what happens when you actually have more than one image to save. But as per the documentation here: http://www.psychopy.org/api/visual/window.html I don’t think .mov generally works. On a Mac, you might have more luck saving to a series of still .png images and combining those into a movie or animated gif in other software.

Regards,

Michael

@m-macaskill Wow, that is such a cool feature! Thank you for pointing that out to me. I will try this tomorrow morning (when I’m more coherent!) and report back!

Best,
Michaela

I’m not actually sure that saving directly to mp4 movie files is possible at the moment (although we should be able to make that possible again using moviepy to save the frames). I think you might need to save the files using something like

win.saveMovieFrames(fileName='frames/frame.png')

which will generate a series of png files in the frames folder and these can then be combined using ffmpeg from the command line.

OR (and this is the solution we need to add within psychopy):

#at begin experiment
from moviepy.editor import ImageSequenceClip

#to save movie
clip = ImageSequenceClip(win.movieFrames, fps=60)
clip.write_videofile('movieName.mp4')

There are more options to the write_videofile() function here:
https://zulko.github.io/moviepy/ref/VideoClip/VideoClip.html#moviepy.video.VideoClip.VideoClip.write_videofile

Hello again,

Thank you for taking the time to help me, @jon

I have put this piece of code in the Begin Experiment section in the builder:[quote=“jon, post:10, topic:936”]
#at begin experiment
from moviepy.editor import ImageSequenceClip
[/quote]

I have put the second piece in the _End Experiment section in the builder: [quote=“jon, post:10, topic:936”]
#to save movie
clip = ImageSequenceClip(win.movieFrames, fps=60)
clip.write_videofile(‘movieName.mp4’)
[/quote]

Here is a copy of my file: MovieDemo.psyexp (5.6 KB) I am using version v1.84.0 on a Mac OS X El Capitan; 10.11.6

It doesn’t appear to be working. Any help with this would be very much appreciated. Thank you very much.

The following is the error:

############# Running: /Users/mdebolt/Desktop/MovieDemo_lastrun.py #############
pyo version 0.8.0 (uses single precision)
2016-08-23 11:56:02.977 python[9282:2595821] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/pp/fbltn3bd1hq9hxzqr_hbkpx8tssfg_/T/org.psychopy.PsychoPy2.savedState
2016-08-23 11:56:09.328 python[9282:2595821] _createMenuRef called with existing principal MenuRef already associated with menu
2016-08-23 11:56:09.365 python[9282:2595821] (
0 CoreFoundation 0x00007fff9c2bd4f2 __exceptionPreprocess + 178
1 libobjc.A.dylib 0x00007fff8a155f7e objc_exception_throw + 48
2 CoreFoundation 0x00007fff9c3244bd +[NSException raise:format:] + 205
3 AppKit 0x00007fff9ec87c86 -[NSCarbonMenuImpl _createMenuRef] + 62
4 AppKit 0x00007fff9ec875c5 -[NSCarbonMenuImpl _instantiateCarbonMenu] + 140
5 AppKit 0x00007fff9ec85270 -[NSApplication finishLaunching] + 856
6 sdlmain_osx.so 0x0000000117339035 initsdlmain_osx + 1653
7 Python 0x00000001000c68da PyEval_EvalFrameEx + 33818
8 Python 0x00000001000c9d23 PyEval_EvalCodeEx + 2115
9 Python 0x000000010003ef30 PyClassMethod_New + 800
10 Python 0x000000010000cd72 PyObject_Call + 98
11 Python 0x0000000100011262 PyObject_CallMethod + 242
12 base.so 0x000000010509de1d initbase + 2477
13 base.so 0x000000010509fbd3 initbase + 10083
14 Python 0x00000001000c62c6 PyEval_EvalFrameEx + 32262
15 Python 0x00000001000c9d23 PyEval_EvalCodeEx + 2115
16 Python 0x00000001000c9e46 PyEval_EvalCode + 54
17 Python 0x00000001000dfe3c PyImport_ExecCodeModuleEx + 284
18 Python 0x00000001000e0502 PyImport_ImportFrozenModule + 1426
19 Python 0x00000001000e179b PyImport_ReloadModule + 1355
20 Python 0x00000001000e1c4a PyImport_ReloadModule + 2554
21 Python 0x00000001000e1f8c PyImport_ImportModuleLevel + 412
22 Python 0x00000001000bc023 _PyBuiltin_Init + 17603
23 Python 0x000000010000cd72 PyObject_Call + 98
24 Python 0x00000001000bd207 PyEval_CallObjectWithKeywords + 87
25 Python 0x00000001000c4786 PyEval_EvalFrameEx + 25286
26 Python 0x00000001000c9d23 PyEval_EvalCodeEx + 2115
27 Python 0x00000001000c9e46 PyEval_EvalCode + 54
28 Python 0x00000001000dfe3c PyImport_ExecCodeModuleEx + 284
29 Python 0x00000001000e0502 PyImport_ImportFrozenModule + 1426
30 Python 0x00000001000e179b PyImport_ReloadModule + 1355
31 Python 0x00000001000e1c4a PyImport_ReloadModule + 2554
32 Python 0x00000001000e1f8c PyImport_ImportModuleLevel + 412
33 Python 0x00000001000bc023 _PyBuiltin_Init + 17603
34 Python 0x000000010000cd72 PyObject_Call + 98
35 Python 0x00000001000bd207 PyEval_CallObjectWithKeywords + 87
36 Python 0x00000001000c4786 PyEval_EvalFrameEx + 25286
37 Python 0x00000001000c9d23 PyEval_EvalCodeEx + 2115
38 Python 0x00000001000c9e46 PyEval_EvalCode + 54
39 Python 0x00000001000eecde PyRun_FileExFlags + 174
40 Python 0x00000001000eef7a PyRun_SimpleFileExFlags + 458
41 Python 0x000000010010614d Py_Main + 3101
42 python 0x0000000100000f14 python + 3860
)
2016-08-23 11:56:09.550 python[9282:2595821] 11:56:09.549 WARNING: 140: This application, or a library it uses, is using the deprecated Carbon Component Manager for hosting Audio Units. Support for this will be removed in a future release. Also, this makes the host incompatible with version 3 audio units. Please transition to the API’s in AudioComponent.h.
Traceback (most recent call last):
File “/Users/mdebolt/Desktop/MovieDemo_lastrun.py”, line 153, in
clip = ImageSequenceClip(win.movieFrames, fps=60)
File “/Applications/PsychoPy2.app/Contents/Resources/lib/python2.7/moviepy/video/io/ImageSequenceClip.py”, line 61, in init
if isinstance(sequence[0], str):
IndexError: list index out of range

You’d failed to add the line to the every frame section:
win.getMovieFrame()

but it turns out there was another problem too, which is that the frames come back in the wrong format for the movie-making library (PIL images rather than bumpy arrays) so the end experiment code needed two more lines as well resulting in this:

for n, frame in enumerate(win.movieFrames):
    win.movieFrames[n] = np.array(frame)
clip = ImageSequenceClip(win.movieFrames, fps=60)
clip.write_videofile('movieName.mp4’)

Now, bear in mind when you code anything here (I’ve made your boxes move in the demo that I’ll attached again) that you should use nFrames rather than t for timing in your movie. While you’re saving frames from the window you’ll probably not keep up with rendering etc so your time will be off. Then when you save the movie the way that nFrames relates to time is also determined by the fps value that you put in that code at endExperiment. So you could run your movie at 30fps and then set the stimulus to last for 15frames (=0.5s in your movie). Make sense?

Here’s the working demo:
MovieDemo.psyexp (5.7 KB)

Hi,

I’ve used a much more inelegant solution, which may be somewhat easier. Quicktime on OS X allows you to record part of the screen, so just run your experiment in a window, and select that part of the screen for quicktime to record. Works great if you just want to record a few trials to use as a demo in presentations etc.

Matt.

@MichaelaDeBolt, did any of these posts solve your problem? Then tick “solved” if a post was particularly helpful. Otherwise let us know!

I usually run the experiment in windowed mode with a screen recorder for that window recording at 60 frames/sec. This is for quite informal use - sending to collaborators etc.

FYI saving movies to gif, mov or mp4 now works seamlessly in v1.84.1:

New release: 1.84.1

e.g. you can now just do win.saveMovieFrames('myMovie.mp4') after running your win.getMovieFrame() commands

Hi OP, and anyone else reading this,

Jon suggested using ffmpeg. So, in the interest of sharing, if you haven’t already figured out how to save a series of images to a .mp4 or .mov file, I have a documented ipython notebook to share which uses only the python modules, shutil, os, and the program ffmpeg to create a video sequence from a set of images.

Things the script does.
Displays a fixation cross for a user defined interval, displays image for a user defined interval, saves and ends.
Things it currently doesn’t do, but could do with some tweaking
Displays the images in a random order. It currently displays the images in a user defined order.

I create this to demo an experiment.

I am happy to share just PM me and I can email it to you.

@jon You are THE BEST! Thank you so much. I just tried your demo you posted earlier with the new update and it works beautifully.

Seriously, thank you. I’m using this to create stimuli and appreciate the clarity and accuracy of the direct export as compared to the screen recording solution I used.

Michaela DeBolt

1 Like

Hi @Michael,

I used this code because I would like to have a recording of my experiment. It didn’t give me an error but the recording file was empty.

Is there something I’m missing?

Thank you in advance for your guidance. I look forward to hearing from you.

Best,

Rubina