def crop_centers
      logger.info 'cropping centers'
      scale_factor = @csv_file.split(/\n/).first.split(',').last.to_f
      percent = (scale_factor*100).round
      logger.debug "cropping to #{percent}%"
      unless @options[:without_cropping]
        images = Image.parse(@input_file)
        images.each do |image|
          width_offset = (image.w.to_f * (1 - scale_factor) / 2).round
          height_offset = (image.h.to_f * (1 - scale_factor) / 2).round
          logger.debug "cropping #{image.name}"
          `convert #{image.name} -crop "#{percent}%x#{percent}%+#{width_offset}+#{height_offset}" #{image.name}`
        end
      end

      # Since all images have been cropped, we need to change d,e params to move images based on how much was cropped
      # Re-run commands that have been run at this point
      logger.info 'rerunning commands'
      @new_input = 'project_converted_translation_cropped.pto'
      `match-n-shift --input #{@csv} -o project_cropped.pto`
      `pto_var --opt=TrX,TrY project_cropped.pto -o project_pto_var_cropped.pto`
      runner = Runner.new(@options.merge(input: 'project_pto_var_cropped.pto', output: @new_input))
      runner.run('convert_translation_parameters')
      `pano_modify -p 0 --fov=AUTO -o #{@new_input} #{@new_input}`

      logger.info "Read new #{@new_input}"
      # Read new input pto file
      @input_file = File.new(@new_input, 'r').read
      images = Image.parse(@input_file)
      ds = images.map(&:d).uniq.sort
      es = images.map(&:e).uniq.sort

      d_diffs = []
      ds.each_with_index do |_, i|
        next if i == 0
        d_diffs.push((ds[i] - ds[i-1]).abs * (1-scale_factor))
      end

      e_diffs = []
      es.each_with_index do |_, i|
        next if i == 0
        e_diffs.push((es[i] - es[i-1]).abs * (1-scale_factor))
      end

      d_map = Hash[ds.map.with_index { |d, i| i == 0 ? [d, d] : [d, d - d_diffs[0..(i-1)].reduce(:+)] }]
      e_map = Hash[es.map.with_index { |e, i|  i == 0 ? [e, e] : [e, e - e_diffs[0..(i-1)].reduce(:+)] }]

      d_min, d_max = d_map.values.minmax
      e_min, e_max = e_map.values.minmax
      d_offset = ((d_max - d_min) / 2.0) + d_min
      e_offset = ((e_max - e_min) / 2.0) + e_min

      logger.info 'saving new d,e values'
      @lines = @input_file.each_line.map do |line|
        image = images.find { |i| i.raw == line }
        if image
          image.d = (d_map[image.d] - d_offset).round(8).to_s
          image.e = (e_map[image.e] - e_offset).round(8).to_s
          image.to_s
        else
          next line
        end
      end.compact

      save_file
    end
def crop_centers
      logger.info 'cropping centers'
      scale_factor = @csv_file.split(/\n/).first.split(',').last.to_f
      percent = (scale_factor*100).round
      logger.debug "cropping to #{percent}%"
      unless @options[:without_cropping]
        images = Image.parse(@input_file)
        images.each do |image|
          width_offset = (image.w.to_f * (1 - scale_factor) / 2).round
          height_offset = (image.h.to_f * (1 - scale_factor) / 2).round
          logger.debug "cropping #{image.name}"
          `convert #{image.name} -crop "#{percent}%x#{percent}%+#{width_offset}+#{height_offset}" #{image.name}`
        end
      end

      # Since all images have been cropped, we need to change d,e params to move images based on how much was cropped
      # Re-run commands that have been run at this point
      logger.info 'rerunning commands'
      @new_input = 'project_converted_translation_cropped.pto'
      `match-n-shift --input #{@csv} -o project_cropped.pto`
      `pto_var --opt=TrX,TrY project_cropped.pto -o project_pto_var_cropped.pto`
      runner = Runner.new(@options.merge(input: 'project_pto_var_cropped.pto', output: @new_input))
      runner.run('convert_translation_parameters')
      `pano_modify -p 0 --fov=AUTO -o #{@new_input} #{@new_input}`

      logger.info "Read new #{@new_input}"
      # Read new input pto file
      @input_file = File.new(@new_input, 'r').read
      images = Image.parse(@input_file)
      ds = images.map(&:d).uniq.sort
      es = images.map(&:e).uniq.sort

      d_diffs = []
      ds.each_with_index do |_, i|
        next if i == 0
        d_diffs.push((ds[i] - ds[i-1]).abs * (1-scale_factor))
      end

      e_diffs = []
      es.each_with_index do |_, i|
        next if i == 0
        e_diffs.push((es[i] - es[i-1]).abs * (1-scale_factor))
      end

      d_map = Hash[ds.map.with_index { |d, i| i == 0 ? [d, d] : [d, d - d_diffs[0..(i-1)].reduce(:+)] }]
      e_map = Hash[es.map.with_index { |e, i|  i == 0 ? [e, e] : [e, e - e_diffs[0..(i-1)].reduce(:+)] }]

      d_min, d_max = d_map.values.minmax
      e_min, e_max = e_map.values.minmax
      d_offset = ((d_max - d_min) / 2.0) + d_min
      e_offset = ((e_max - e_min) / 2.0) + e_min

      logger.info 'saving new d,e values'
      @lines = @input_file.each_line.map do |line|
        image = images.find { |i| i.raw == line }
        if image
          image.d = (d_map[image.d] - d_offset).round(8).to_s
          image.e = (e_map[image.e] - e_offset).round(8).to_s
          image.to_s
        else
          next line
        end
      end.compact

      save_file
    end
Uses image magick to crop centers