class Tracksperanto::Export::FlameStabilizer2014

Constants

COLOR
DATETIME_FORMAT

Public Class Methods

desc_and_extension() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 6
def self.desc_and_extension
  "flamesmoke2014.stabilizer"
end
human_name() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 10
def self.human_name
  "Flame/Smoke 2D Stabilizer setup (v. 2014 and above)"
end

Public Instance Methods

end_export() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 22
def end_export
  # Now make another writer, this time for our main IO
  @writer = FlameChannelParser::Builder.new(@io)
  
  # Now we know how many trackers we have so we can write the header
  # data along with NbTrackers
  write_header_with_number_of_trackers(@counter)
  
  # Now write everything that we accumulated earlier into the base IO
  @temp.rewind
  @io.write(@temp.read) until @temp.eof?
  @temp.close!
  
  # Send the ChannelEnd command and list the trackers
  @writer.channel_end
  @first_ref_frames.each_with_index do | ref_frame, i|
    @writer.write_unterminated_block!("tracker", i) do |t|
      t.active true
      t.color_hash!("colour", 0, 100, 0)
      t.fixed_ref true
      t.fixed_x false
      t.fixed_y false
      t.tolerance 100
      t.offsets_x 0
      t.offsets_y 0
      t.first_ref_frame ref_frame
    end
  end
  
  # Write the finalizing "End"
  @writer.write_loose!("end")
end
end_tracker_segment() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 72
def end_tracker_segment
  # We write these at tracker end since we need to know in advance
  # how many keyframes they should contain
  write_shift_channel("shift/x", @x_shift_values)
  write_shift_channel("shift/y", @y_shift_values)
  
  # And finish with the offset channels. The order of channels is important!
  # (otherwise the last tracker's shift animation is not imported by Flame)
  # https://github.com/guerilla-di/tracksperanto/issues/1
  write_offset_channels
end
export_point(frame, abs_float_x, abs_float_y, float_residual) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 60
def export_point(frame, abs_float_x, abs_float_y, float_residual)
  flame_frame = frame + 1
  if @write_first_frame
    export_first_point(flame_frame, abs_float_x, abs_float_y)
    # Record the first ref frame for this tracker
    @first_ref_frames << flame_frame
    @write_first_frame = false
  else
    export_remaining_point(flame_frame, abs_float_x, abs_float_y)
  end
end
start_export( img_width, img_height) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 14
def start_export( img_width, img_height)
  @counter = 0
  @first_ref_frames = []
  @width, @height = img_width, img_height
  @temp = Tracksperanto::BufferIO.new
  @writer = FlameChannelParser::Builder.new(@temp)
end
start_tracker_segment(tracker_name) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 55
def start_tracker_segment(tracker_name)
  @counter += 1
  @write_first_frame = true
end

Private Instance Methods

export_first_point(flame_frame, abs_float_x, abs_float_y) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 93
def export_first_point(flame_frame, abs_float_x, abs_float_y)
  @base_x, @base_y = abs_float_x, abs_float_y
  write_first_frame(abs_float_x, abs_float_y)
  # For Flame to recognize the reference frame of the Shift channel
  # we need it to contain zero as an int, not as a float. The shift proceeds
  # from there.
  @x_shift_values = [[flame_frame, 0]]
  @y_shift_values = [[flame_frame, 0]]
end
export_remaining_point(flame_frame, abs_float_x, abs_float_y) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 86
def export_remaining_point(flame_frame, abs_float_x, abs_float_y)
  # Just continue buffering the upcoming shift keyframes and flush them in the end
  shift_x, shift_y = @base_x - abs_float_x, @base_y - abs_float_y
  @x_shift_values.push([flame_frame, shift_x])
  @y_shift_values.push([flame_frame, shift_y])
end
prefix(tracker_channel) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 126
def prefix(tracker_channel)
  "tracker%d/%s" % [@counter, tracker_channel]
end
write_deltax_and_deltay_channels() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 221
def write_deltax_and_deltay_channels
  # This is used for deltax and deltay (offset tracking).
  # We set it to zero and lock
  %w( ref/dx ref/dy).map(&method(:prefix)).each do | chan, v |
    @writer.channel(chan) do | c |
      c.extrapolation("constant")
      c.value 0
      c.colour(COLOR)
      c.size 2
      c.key_version 1
      c.key(0) do | k |
        k.frame 0
        k.value 0
        k.value_lock true
        k.delete_lock true
        k.interpolation :constant
      end
      c.key(1) do | k |
        k.frame 1
        k.value 0
        k.value_lock true
        k.delete_lock true
        k.interpolation :constant
      end
    end # Chan block
  end
end
write_first_frame(x, y) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 154
def write_first_frame(x, y)
  write_track_channels
  write_track_width_and_height
  write_ref_width_and_height
  write_ref_channels(x, y)
  write_deltax_and_deltay_channels
end
write_header_with_number_of_trackers(number_of_trackers) click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 130
def write_header_with_number_of_trackers(number_of_trackers)
  @writer.stabilizer_file_version "6.0"
  @writer.creation_date(Time.now.strftime(DATETIME_FORMAT))
  @writer.linebreak!(2)
  
  @writer.nb_trackers number_of_trackers
  @writer.selected 0
  @writer.frame_width @width
  @writer.frame_height @height
  @writer.auto_key true
  @writer.motion_path true
  @writer.icons true
  @writer.auto_pan false # hate it!
  @writer.edit_mode 0
  @writer.format 0
  @writer.color_hash!("padding", 0, 100, 0)
  @writer.oversampling false
  @writer.opacity 50
  @writer.zoom 3
  @writer.field false
  @writer.backward false
  @writer.anim
end
write_offset_channels() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 249
def write_offset_channels
  %w(offset/x offset/y).map(&method(:prefix)).each do | c |
    @writer.channel(c) do | chan |
      chan.extrapolation :constant
      chan.value 0
    end
  end
end
write_ref_channels(ref_x, ref_y) click to toggle source

The Ref channel contains the reference for the shift channel in absolute coordinates, and is set as float. Since we do not “snap” the tracker in the process it's enough for us to make one keyframe in the ref channels at the same frame as the first shift keyframe

# File lib/export/flame_stabilizer_2014.rb, line 202
def write_ref_channels(ref_x, ref_y)
  %w( ref/x ref/y).map(&method(:prefix)).zip([ref_x, ref_y]).each do | cname, default |
    @writer.channel(cname) do | c |
      c.extrapolation("constant")
      c.value(default)
      c.colour(COLOR)
      c.key_version 1
      c.size 1
      c.key(0) do | k |
        k.frame 1
        k.value default
        k.interpolation :constant
        k.left_slope 2.4
        k.right_slope 2.4
      end
    end
  end
end
write_ref_width_and_height() click to toggle source

The size of the reference area

# File lib/export/flame_stabilizer_2014.rb, line 188
def write_ref_width_and_height
  %w( ref/width ref/height).map(&method(:prefix)).each do | channel_name |
    @writer.channel(channel_name) do | c |
      c.extrapolation :linear
      c.value 10
      c.colour COLOR
    end
  end
end
write_shift_channel(name_without_prefix, values) click to toggle source

The shift channel is what determines how the tracking point moves.

# File lib/export/flame_stabilizer_2014.rb, line 104
def write_shift_channel(name_without_prefix, values)
  @writer.channel(prefix(name_without_prefix)) do | c |
    c.extrapolation :constant
    c.value values[0][1]
    c.key_version 1
    c.size values.length
    values.each_with_index do | (f, v), i |
      c.key(i) do | k |
        k.frame f
        k.value v
        # Omit:
        # RHandle_dX 0.333333343
        # RHandle_dY -5.7284646
        # LHandle_dX -0.333333343
        # LHandle_dY 5.7284646
        k.curve_mode :hermite
        k.curve_order :linear
      end
    end
  end
end
write_track_channels() click to toggle source
# File lib/export/flame_stabilizer_2014.rb, line 162
def write_track_channels
  ctr_x, ctr_y = @width / 2, @height / 2
  
  # track determines where the tracking box is, and should be in the center
  # of the image for Flame to compute all other shifts properly
  %w( track/x track/y).map(&method(:prefix)).zip([ctr_x, ctr_y]).each do | cname, default |
    @writer.channel(cname) do | c |
      c.extrapolation("constant")
      c.value(default.to_i)
      c.colour(COLOR)
    end
  end
end
write_track_width_and_height() click to toggle source

The size of the tracking area

# File lib/export/flame_stabilizer_2014.rb, line 177
def write_track_width_and_height
  %w( track/width track/height ).map(&method(:prefix)).each do | channel_name |
    @writer.channel(channel_name) do | c |
      c.extrapolation :linear
      c.value 15
      c.colour COLOR
    end
  end
end