-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Timelapse update #591
Timelapse update #591
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,12 +6,10 @@ | |
from matplotlib import pyplot as plt | ||
from warnings import warn | ||
|
||
from astropy import units as u | ||
from astropy.wcs import WCS | ||
from astropy.io.fits import open as open_fits | ||
from astropy.visualization import (PercentileInterval, LogStretch, ImageNormalize) | ||
|
||
from ffmpy import FFmpeg | ||
from glob import glob | ||
from copy import copy | ||
|
||
|
@@ -201,7 +199,14 @@ def _make_pretty_from_cr2(fname, timeout=15, **kwargs): # pragma: no cover | |
return fname.replace('cr2', 'jpg') | ||
|
||
|
||
def create_timelapse(directory, fn_out=None, file_type='jpg', **kwargs): | ||
def create_timelapse( | ||
directory, | ||
fn_out=None, | ||
file_type='jpg', | ||
overwrite=False, | ||
timeout=60, | ||
verbose=False, | ||
**kwargs): | ||
"""Create a timelapse | ||
|
||
A timelapse is created from all the jpg images in a given `directory` | ||
|
@@ -211,6 +216,9 @@ def create_timelapse(directory, fn_out=None, file_type='jpg', **kwargs): | |
fn_out (str, optional): Full path to output file name, if not provided, | ||
defaults to `directory` basename. | ||
file_type (str, optional): Type of file to search for, default 'jpg'. | ||
overwrite (bool, optional): Overwrite timelapse if exists, default False. | ||
timeout (int): Timeout for making movie, default 60 seconds. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious, how long does this take on the RPi? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I haven't tried. I changed it slightly so on PAN008 the observation directories are moved off the Pi, mostly for storage size issues. I'll try it out tonight when I still have an image sequence on the Pi. i actually thought it might be better to do this as a Cloud Function that responds the the PubSub notifications when images are uploaded. Then it could just make a movie and post it to youtube. |
||
verbose (bool, optional): Show output, default False. | ||
**kwargs (dict): Valid keywords: verbose | ||
|
||
Returns: | ||
|
@@ -224,29 +232,48 @@ def create_timelapse(directory, fn_out=None, file_type='jpg', **kwargs): | |
field_name = head.split('/')[-2] | ||
cam_name = head.split('/')[-1] | ||
fname = '{}_{}_{}.mp4'.format(field_name, cam_name, tail) | ||
fn_out = os.path.join(os.getenv('PANDIR'), 'images', 'timelapse', fname) | ||
fn_out = os.path.normpath(os.path.join(directory, fname)) | ||
|
||
fn_dir = os.path.dirname(fn_out) | ||
os.makedirs(fn_dir, exist_ok=True) | ||
if verbose: | ||
print("Timelapse file: {}".format(fn_out)) | ||
|
||
if os.path.exists(fn_out) and not overwrite: | ||
raise FileExistsError("Timelapse exists. Set overwrite=True if needed") | ||
|
||
ffmpeg = shutil.which('ffmpeg') | ||
wtgee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
inputs_glob = os.path.join(directory, '*.{}'.format(file_type)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is it that orders the files added to the video? Just the lexical order? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think ffmpeg is intelligent about ordering them but worth checking on. I usually sort after the glob but here we're just passing the glob. |
||
|
||
try: | ||
ff = FFmpeg( | ||
global_options='-r 3 -pattern_type glob', | ||
inputs={inputs_glob: None}, | ||
outputs={ | ||
fn_out: '-s hd1080 -vcodec libx264' | ||
}) | ||
|
||
if 'verbose' in kwargs: | ||
out = None | ||
err = None | ||
print("Timelapse command: ", ff.cmd) | ||
else: | ||
out = open(os.devnull, 'w') | ||
err = open(os.devnull, 'w') | ||
|
||
ff.run(stdout=out, stderr=err) | ||
ffmpeg_cmd = [ | ||
ffmpeg, | ||
'-r', '3', | ||
'-pattern_type', 'glob', | ||
'-i', inputs_glob, | ||
'-s', 'hd1080', | ||
'-vcodec', 'libx264', | ||
] | ||
|
||
if overwrite: | ||
ffmpeg_cmd.append('-y') | ||
|
||
ffmpeg_cmd.append(fn_out) | ||
|
||
if verbose: | ||
print(ffmpeg_cmd) | ||
|
||
proc = subprocess.Popen(ffmpeg_cmd, universal_newlines=True, | ||
stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
try: | ||
# Don't wait forever | ||
outs, errs = proc.communicate(timeout=timeout) | ||
except subprocess.TimeoutExpired: | ||
proc.kill() | ||
outs, errs = proc.communicate() | ||
finally: | ||
if verbose: | ||
print(outs) | ||
print(errs) | ||
fn_out = None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect this belongs in the except block above, along with the |
||
except Exception as e: | ||
warn("Problem creating timelapse in {}: {!r}".format(fn_out, e)) | ||
fn_out = None | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,6 @@ ccdproc | |
codecov | ||
coveralls | ||
dateparser | ||
ffmpy | ||
gcloud | ||
google-cloud-storage | ||
matplotlib >= 2.0.0 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jpg is the default type of file, but we allow for others. What other types would ffmpeg support? Probably gif and png. Speaking of which, I've wondered about using png in place of jpg to avoid lossy artifacts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jpgs come directly out of the CR2 without us having to create/convert anything so it's the easiest. Would be open to another solution if practical.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated docs to not be jpg specific.