lib/import/shake_script.rb in tracksperanto-1.1.1 vs lib/import/shake_script.rb in tracksperanto-1.2.0
- old
+ new
@@ -1,129 +1,215 @@
-require 'strscan'
+require File.dirname(__FILE__) + "/shake_grammar/lexer"
+require File.dirname(__FILE__) + "/shake_grammar/catcher"
class Tracksperanto::Import::ShakeScript < Tracksperanto::Import::Base
- # Allow literal strings instead of Regexps
- class SloppyParser < StringScanner
- def skip_until(pattern)
- pattern.is_a?(String) ? super(/#{Regexp.escape(pattern)}/m) : super(pattern)
- end
-
- def scan_until(pattern)
- pattern.is_a?(String) ? super(/#{Regexp.escape(pattern)}/m) : super(pattern)
- end
+ def self.human_name
+ "Shake .shk script file"
end
-
- class ValueAt
- attr_accessor :value, :frame
- def self.from_string(str)
- v = new
- val_s, frame_s = str.scan(/(.+)@(\d+)/).to_a.flatten
- v.value, v.frame = val_s.to_f, frame_s.to_i
- v
- end
+
+ def self.distinct_file_ext
+ ".shk"
end
-
- class CurveParser < SloppyParser
- BLOCK_ENDS = /\d,|\)/
+
+ class Traxtractor < Tracksperanto::ShakeGrammar::Catcher
+ include Tracksperanto::ZipTuples
- attr_reader :values
- def initialize(with_curve_arg)
- @values = []
-
- super(with_curve_arg.to_s)
-
- # Skip the interpolation name, we assume it to be linear anyway
- skip_until '('
-
- # Skip the first defining parameter whatever that might be
- skip_until ','
-
- loop do
- break unless (value_at = scan_until(BLOCK_ENDS))
- # Grab the value
- val = ValueAt.from_string(value_at)
-
- @values << val
+ class << self
+ attr_accessor :accumulator
+ attr_accessor :progress_block
+ end
+
+ self.accumulator = []
+
+ # For Linear() curve calls. If someone selected JSpline or Hermite it's his problem.
+ # We put the frame number at the beginning since it works witih oru tuple zipper
+ def linear(first_arg, *keyframes)
+ report_progress("Translating Linear animation")
+ keyframes.map do | kf |
+ [kf[1][1], kf[0][1]]
end
end
-
- end
-
- class TrackerParser < SloppyParser
- attr_reader :x_curve, :y_curve, :c_curve, :name
- def initialize(with_tracker_args)
- super(with_tracker_args)
-
- # Name me!
- @name = scan_until(/(\w+) /).strip
+ # image Tracker(
+ # image In,
+ # const char * trackRange,
+ # const char * subPixelRes,
+ # const char * matchSpace,
+ # float referenceTolerance,
+ # const char * referenceBehavior,
+ # float failureTolerance,
+ # const char * failureBehavior,
+ # int limitProcessing,
+ # float referencFrame
+ # ...
+ # );
+ def tracker(input, trackRange, subPixelRes, matchSpace,
+ referenceTolerance, referenceBehavior, failureTolerance, failureBehavior, limitProcessing, referencFrame, s1, s2,
+ s3, s4, s5, s6, *trackers)
- # All the tracker arguments
- 17.times { skip_until ',' } # input data
+ report_progress("Parsing Tracker node")
+ collect_trackers_from(get_variable_name, trackers)
+ true
+ end
+
+ # stabilize {
+ # image In,
+ # int applyTransform,
+ # int inverseTransform
+ # const char * trackType,
+ # float track1X,
+ # float track1Y,
+ # int stabilizeX,
+ # int stabilizeY,
+ # float track2X,
+ # float track2Y,
+ # int matchScale,
+ # int matchRotation,
+ # float track3X,
+ # float track3Y,
+ # float track4X,
+ # float track4Y,
+ # const char * xFilter,
+ # const char * yFilter,
+ # const char * transformationOrder,
+ # float motionBlur,
+ # float shutterTiming,
+ # float shutterOffset,
+ # float referenceFrame,
+ # float aspectRatio,
+ # ...
+ # };
+ def stabilize(imageIn, applyTransform, inverseTransform, trackType,
+ track1X, track1Y,
+ stabilizeX, stabilizeY,
+ track2X, track2Y,
+ matchScale,
+ matchRotation,
+ track3X, track3Y,
+ track4X, track4Y,
+ *useless_args)
- # Grab the curves
- @x_curve, @y_curve, @c_curve = (0..2).map{ CurveParser.new(scan_until('),')).values }
+ report_progress("Parsing Stabilize node")
+ node_name = get_variable_name
+ collect_stabilizer_tracker("#{node_name}_track1", track1X, track1Y)
+ collect_stabilizer_tracker("#{node_name}_track2", track2X, track2Y)
+ collect_stabilizer_tracker("#{node_name}_track3", track3X, track3Y)
+ collect_stabilizer_tracker("#{node_name}_track4", track4X, track4Y)
+ end
+
+ # image = MatchMove(
+ # Background,
+ # Foreground,
+ # applyTransform,
+ # "trackType",
+ # track1X,
+ # track1Y,
+ # matchX,
+ # matchY,
+ # track2X,
+ # track2Y,
+ # scale,
+ # rotation,
+ # track3X,
+ # track3Y,
+ # track4X,
+ # track4Y,
+ # x1,
+ # y1,
+ # x2,
+ # y2,
+ # x3,
+ # y3,
+ # x4,
+ # y4,
+ # "xFilter",
+ # "yFilter",
+ # motionBlur,
+ # shutterTiming,
+ # shutterOffset,
+ # referenceFrame,
+ # "compositeType",
+ # clipMode,
+ # "trackRange",
+ # "subPixelRes",
+ # "matchSpace",
+ # float referenceTolerance,
+ # "referenceBehavior",
+ # float failureTolerance,
+ # "failureBehavior",
+ # int limitProcessing,
+ # ...
+ # );
+ def matchmove(bgImage, fgImage, applyTransform,
+ trackType,
+ track1X,
+ track1Y,
+ matchX,
+ matchY,
+ track2X,
+ track2Y,
+ scale,
+ rotation,
+ track3X,
+ track3Y,
+ track4X,
+ track4Y, *others)
- # if the next argument is an integer, we reached the end of the tracks. If not - make a nested one.
+ report_progress("Parsing MatchMove node")
+ node_name = get_variable_name
+ collect_stabilizer_tracker("#{node_name}_track1", track1X, track1Y)
+ collect_stabilizer_tracker("#{node_name}_track2", track2X, track2Y)
+ collect_stabilizer_tracker("#{node_name}_track3", track3X, track3Y)
+ collect_stabilizer_tracker("#{node_name}_track4", track4X, track4Y)
+
end
- def curves
- [@x_curve, @y_curve, @c_curve]
+ private
+
+ def report_progress(with_message)
+ self.class.progress_block.call(with_message) if self.class.progress_block
end
- end
-
- class TrackParser < SloppyParser
- def initialize(with_tracker_block)
- # scan until the first " - name of the track
- skip_until ','
- # scan values
- # discard the 8 box determinators
- 7.times { skip_until ',' }
- # discard the box animation
- 2.times { skip_until ',' }
+
+ def collect_trackers_from(name, array)
+ parameters_per_node = 16
+ nb_trackers = array.length / parameters_per_node
+ nb_trackers.times do | idx |
+ from_index, to_index = (idx * parameters_per_node), (idx+1) * parameters_per_node
+ tracker_args = array[from_index...to_index]
+ tracker_args[0] = "#{name}_#{tracker_args[0]}"
+ collect_tracker(*tracker_args)
+ end
end
- end
-
- TRACKER_PATTERN = /((\w+) = Tracker\(([^;]+))/m
-
- def parse(sript_file_content)
- trackers = []
-
- sript_file_content.scan(TRACKER_PATTERN).each_with_index do | tracker_text_block, idx |
+ def collect_stabilizer_tracker(name, x_curve, y_curve)
+ return if (x_curve == :unknown || y_curve == :unknown)
- parser = TrackerParser.new(tracker_text_block.to_s)
+ keyframes = zip_curve_tuples(x_curve, y_curve).map do | (frame, x, y) |
+ Tracksperanto::Keyframe.new(:frame => frame - 1, :abs_x => x, :abs_y => y)
+ end
- tracker = Tracksperanto::Tracker.new{|t| t.name = parser.name }
-
- report_progress("Reading tracker #{tracker.name}")
-
- x_keyframes, y_keyframes, residual_keyframes = TrackerParser.new(tracker_text_block.to_s).curves
- x_keyframes.each_with_index do | value_at, kf_index |
-
- # Find the Y keyframe with the same frame
- matching_y = y_keyframes.find{|f| f.frame == value_at.frame }
-
- # Find the correlation keyframe with the same frame
- matching_residual = residual_keyframes.find{|f| f.frame == value_at.frame }
-
- # Skip frame if only one keyframe is present
- if !matching_y
- STDERR.puts "Cannot find matching Y for frame #{value_at.frame} in tracker #{parser.name}, skipping keyframe"
- next
- end
-
- tracker.keyframes << Tracksperanto::Keyframe.new do |k|
- k.frame = (value_at.frame - 1)
- k.abs_x = value_at.value
- k.abs_y = matching_y.value
- k.residual = 1 - (matching_residual.value rescue 1.0)
- end
+ t = Tracksperanto::Tracker.new(:name => name, :keyframes => keyframes )
+ self.class.accumulator.push(t)
+ end
+
+ def collect_tracker(name, x_curve, y_curve, corr_curve, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12)
+ report_progress("Scavenging tracker #{name}")
+ keyframes = zip_curve_tuples(x_curve, y_curve, corr_curve).map do | (frame, x, y, corr) |
+ Tracksperanto::Keyframe.new(:frame => frame - 1, :abs_x => x, :abs_y => y, :residual => (1 - corr))
end
- trackers << tracker
+ t = Tracksperanto::Tracker.new(:name => name, :keyframes => keyframes )
+ self.class.accumulator.push(t)
end
+ end
+
+ def parse(script_io)
+ trackers = []
+
+ Traxtractor.accumulator = trackers
+ Traxtractor.progress_block = lambda{|msg| report_progress(msg) }
+ Traxtractor.new(script_io)
trackers
end
end
\ No newline at end of file