Skip to content

Instantly share code, notes, and snippets.

@iconara
Created June 29, 2016 13:17
Show Gist options
  • Save iconara/9558b9b1282deb14d2bf495b534432f7 to your computer and use it in GitHub Desktop.
Save iconara/9558b9b1282deb14d2bf495b534432f7 to your computer and use it in GitHub Desktop.
Timelapse deshaker
#!/usr/bin/env ruby
# brew install imagemagick
# brew install Caskroom/cask/hugin
require 'fileutils'
require 'thread'
require 'optparse'
ALIGN_COMMAND_PATH = '/usr/local/Caskroom/hugin/2014.0.0/HuginTools/align_image_stack'
reference_frame = nil
output_dir = 'aligned'
parallelism = 4
parser = OptionParser.new do |p|
p.on('--reference-frame PATH') { |s| reference_frame = s }
p.on('--output-dir PATH') { |s| output_dir = s }
p.on('--parallelism P') { |s| parallelism = s.to_i }
end
parser.parse!(ARGV)
if ARGV.empty?
abort('No frames')
elsif Dir.exist?(output_dir)
abort('Output directory exists')
end
class Aligner
def initialize(reference_frame, output_dir)
@reference_frame = reference_frame
@output_dir = output_dir
end
def align(frame)
file_name = File.basename(frame, '.*')
prefix = sprintf('%s/tmp-%s-', @output_dir, file_name)
command = [ALIGN_COMMAND_PATH, '-a', prefix, @reference_frame, frame]
Process.wait(spawn(*command, out: '/dev/null'))
output_frames = Dir["#{prefix}*"]
aligned_frame = sprintf('%s/%s.jpg', @output_dir, file_name)
command = ['convert', output_frames.last, '-shave', '16x9', aligned_frame]
Process.wait(spawn(*command, out: '/dev/null'))
output_frames.each { |path| FileUtils.rm(path) }
end
end
aligner = Aligner.new(reference_frame || ARGV.first, output_dir)
frames = Queue.new
ARGV.each { |path| frames << path }
FileUtils.mkdir(output_dir)
io_lock = Mutex.new
threads = Array.new(parallelism) do
Thread.start do
while (frame = frames.pop) != :die
aligner.align(frame)
io_lock.synchronize do
$stderr.puts("Created #{File.basename(frame)}")
end
end
end
end
threads.each do
frames << :die
end
begin
threads.each(&:value)
rescue => e
io_lock.synchronize do
$stderr.puts("#{e.message} (#{e.class.name})")
$stderr.puts(e.backtrace.join("\t\n"))
end
exit(1)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment