Skip to content
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

Create movie from image series #81

Merged
merged 5 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ version = "0.5.10"
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
GeoParams = "e018b62d-d9de-4a26-8697-af89c310ae38"
Geodesy = "0ef565a4-170c-5f04-8de2-149903a85f3d"
Expand Down Expand Up @@ -37,6 +38,7 @@ GMT_utils = "GMT"
[compat]
Colors = "0.9 - 0.12"
Downloads = "1"
FFMPEG = "0.4"
FileIO = "1"
GLMakie = "0.8, 0.9"
GMT = "1"
Expand Down
3 changes: 2 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ makedocs(;
"Visualisation" => "man/visualise.md",
"Gravity code" => "man/gravity_code.md",
"LaMEM" => "man/lamem.md",
"Profile Processing" => "man/profile_processing.md"
"Profile Processing" => "man/profile_processing.md",
"Movies" => "man/movies.md"
],
"List of functions" => "man/listfunctions.md",
"Authors" => "man/authors.md",
Expand Down
12 changes: 12 additions & 0 deletions docs/src/man/movies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Create movies

We have two routines to help create movies from the results.
The first one takes `*.png` images generated with the `Save Animation` option in paraview and puts them together in compressed movies (either `mp4` or `mov`):
```@docs
movie_from_images
```

The other one creates `*.pvd` files that can be saved with the `pvd=...` optional option in `Write_Paraview`, such that you can animate temporal data in paraview (yif you're happy you can save the result as images and use `movies_from_pics`). See the corresponding tutorial on how to generate `*.pvd` files.
```@docs
Write_Paraview
```
1 change: 1 addition & 0 deletions src/GeophysicalModelGenerator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ include("stl.jl")
include("ProfileProcessing.jl")
include("IO.jl")
include("event_counts.jl")
include("movies_from_pics.jl")

# Add optional routines (only activated when the packages are loaded)

Expand Down
76 changes: 76 additions & 0 deletions src/movies_from_pics.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# This routines enables creating movies from a series of images
# That is perhaps not structly a GMG routine, but still part of the workflow
# as images, generated by Paraview, often need to be merged into a movie.
# that can be done with FFMPEG, but determining the optimal parameters can be oftentimes tricky
# (while ensuring that the movie works well on mac/windows etc)

using FFMPEG

export movie_from_images

"""
movie_from_images(; dir=pwd(), file=nothing, outfile=nothing, framerate=10, copy_to_current_dir=true, type=:mp4_default, collect=true)

The typical way to create animations with `Paraview` is to use the `Save Animation` option to save a series of `*.png` images.

This function combines these images to an `*.mp4` movie.

Optional options
===
- `dir`: directory where the images are stored.
- `file`: filename of the image series without extension and numbers. Required if >1 image series is stored in the same directory. By default we reconstruct this name from the available files.
- `outfile`: filename of the resulting movie without extension; if not specified, `file` is used.
- `framerate`: number of frames/second.
- `copy_to_current_dir`: copies the final movie to the current directory if `true` (default); otherwise it will be stored in `dir`.
- `type`: type of movie that is created; possible options are:
- `:mp4_default`: Default option that saves a well-compressed `mp4` movie that works well for us on ipad and embedded in a powerpoint presentation.
- `:mov_hires`: Higher-resolution quicktime movie (larger filesize & not compatible with windows)
- `collect`: suppresses output of `FFMPEG` if `true` (default).
"""
function movie_from_images(; dir=pwd(), file=nothing, outfile=nothing, framerate=10, copy_to_current_dir=true, type=:mp4_default)
curdir = pwd();
cd(dir)
files = split.(readdir(),".")
files = files[length.(files) .== 3] # names should be filename.0001.png or something like that

filenames = [f[1] for f in files]
fileext = files[1][3]
le = length(files[1][2])

# try to determine the filename automatically (works if we have only one name in the director)
if length(unique(filenames))>1 && isnothing(file)
error("you have more than one image series in the directory $dir; please specify the filename `file`.")

Check warning on line 42 in src/movies_from_pics.jl

View check run for this annotation

Codecov / codecov/patch

src/movies_from_pics.jl#L42

Added line #L42 was not covered by tests
elseif isnothing(file)
file = unique(filenames)[1]
end

if isnothing(outfile)
outfile = file; #use same name as images
end

if type==:mp4_default
# this produces an *.mp4 movie that looks good on an ipad
outfile_ext = outfile*".mp4"
cmd = `-y -framerate $framerate -f image2 -i $file.%0$(le)d.$fileext -vf pad="""width=ceil(iw/2)*2:height=ceil(ih/2)*2""" -f mp4 -vcodec libx264 -pix_fmt yuv420p $outfile_ext`
elseif type==:mov_hires
outfile_ext = outfile*".mov"
cmd = `-y -f image2 -framerate $framerate -i $file.%0$(le)d.$fileext -c:v prores_ks -profile:v 1 $outfile_ext`
else
error("unknown movie type $type")

Check warning on line 59 in src/movies_from_pics.jl

View check run for this annotation

Codecov / codecov/patch

src/movies_from_pics.jl#L59

Added line #L59 was not covered by tests
end

# run
FFMPEG.exe(cmd, collect = true)

result = joinpath(pwd(),outfile_ext)
if copy_to_current_dir
# copy result
result = joinpath(curdir,outfile_ext)
cp(outfile_ext, result, force=true)
end
println("created movie: $result")

cd(curdir) # return to original directory

return outfile_ext
end
4 changes: 3 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ end
@testset "Event counts" begin
include("test_event_counts.jl")
end

@testset "Create movie" begin
include("test_create_movie.jl")
end

# Cleanup
foreach(rm, filter(endswith(".vts"), readdir()))
Expand Down
21 changes: 21 additions & 0 deletions test/test_create_movie.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Test

dir = "test_files"
outname1 = movie_from_images(dir=dir)
@test outname1=="test_animation.mp4"

outname2 = movie_from_images(dir=dir, copy_to_current_dir=false)
@test outname2=="test_animation.mp4"

outname3 = movie_from_images(dir=dir, copy_to_current_dir=false, framerate=20, outfile="test_anim2")
@test outname3=="test_anim2.mp4"

outname4 = movie_from_images(dir=dir, copy_to_current_dir=false, framerate=20, outfile="test_anim3", type=:mov_hires)
@test outname4=="test_anim3.mov"

rm(outname1)
rm(joinpath(dir,outname2))
rm(joinpath(dir,outname3))
rm(joinpath(dir,outname4))


Binary file added test/test_files/test_animation.0000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/test_files/test_animation.0001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/test_files/test_animation.0002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading