|
#!/usr/bin/env ruby |
|
require 'fileutils' |
|
require 'find' |
|
|
|
unless ARGV.length == 2 |
|
STDERR.puts "This utility needs a source directory and destination directory" |
|
exit 1 |
|
end |
|
source, destination = ARGV |
|
|
|
FileUtils.mkdir_p destination |
|
|
|
source_images = [] |
|
Find.find(source) do |path| |
|
next unless File.file?(path) |
|
next unless path =~ /JPG$/ |
|
source_images << [ path, File.stat(path) ] |
|
end |
|
source_images = source_images.sort {|a,b| a[1].ctime <=> b[1].ctime} |
|
|
|
|
|
# This will walk over the source images, comparing their file creation times |
|
# and group them by files of a similar creation time. |
|
# After there is a gap longer than the average file delta, plus a fudge factor, |
|
# create the next group. |
|
fudge_factor = 10 |
|
clusters = [] |
|
total_deltas = 0 |
|
count = 1 |
|
average_delta = (source_images[0][1].ctime - source_images[1][1].ctime) |
|
current_cluster = [] |
|
(0 .. source_images.length-1).each do |index| |
|
previous_index = (index == 0 ? 0 : index - 1) |
|
this = source_images[index] |
|
previous = source_images[previous_index] |
|
|
|
delta = this[1].ctime - previous[1].ctime |
|
total_deltas += delta |
|
count += 1 |
|
average_delta = total_deltas / count |
|
|
|
if delta > (average_delta + fudge_factor) then # We've hit a boundary in out image sequence. Start a new cluster. |
|
total_deltas = 0 |
|
count = 1 |
|
clusters << current_cluster |
|
current_cluster = [] |
|
end |
|
|
|
current_cluster << this |
|
end |
|
unless current_cluster.empty? |
|
clusters << current_cluster |
|
end |
|
|
|
if clusters.length <= 0 |
|
STDERR.puts "Found no clusters of images?" |
|
exit 3 |
|
end |
|
|
|
puts "Building destination symlink directories for #{clusters.length} clusters." |
|
(0 .. clusters.length-1).each do |cluster_number| |
|
cluster_destination_dir = File.join(destination, "sequence_#{cluster_number}") |
|
if File.exist?(cluster_destination_dir) and Dir.entries(cluster_destination_dir).length > 2 then |
|
STDERR.puts "Destination directory #{cluster_destination_dir} already exists. Bailing out." |
|
exit 3 |
|
end |
|
FileUtils.mkdir_p cluster_destination_dir |
|
|
|
cluster = clusters[cluster_number] |
|
|
|
cluster.each_with_index do |entry, index| |
|
path, stat = entry |
|
destination_file = File.join(cluster_destination_dir, "image#{sprintf('%04d', index)}.jpg") |
|
path = File.expand_path(path) |
|
destination_file = File.expand_path(destination_file) |
|
File.symlink(path, destination_file) |
|
end |
|
|
|
puts "You can now call ffmpeg like: ffmpeg -i #{File.expand_path(cluster_destination_dir)}/image%04d.jpg sequence_#{cluster_number}.mp4" |
|
end |
using the script for the following case:
I have a directory with 162,616 images in it (45 hours of recording at about 1fps, or ~1.5hours of 24fps video, but it's compressed motion capture covering about 2 weeks in 2009 )
line 16 edited to use 'jpg', how do I easily replace line 16 with a case insensitive search for 'jpg' or 'Jpg'?
worked to make 2 sequences out of that huge archive.