FFMPEG确定视频区域的平均颜色

时间:2019-11-09 01:37:36

标签: ruby ffmpeg

我有一个用例,我想在视频中插入两个水印之一-一个用于深色背景,另一个用于浅色背景。假设我要在视频的右上角执行此操作。

如何确定视频右上部分的平均颜色?发布此信息后,如何通过查看平均颜色确定要使用的水印?

我现在有一个解决方案,我要等距地截取屏幕截图,然后测量平均颜色,但是速度太慢了,特别是对于较长的视频。

# Calculate average color
    black_distances = []
    white_distances = []

    movie = FFMPEG::Movie.new(video_file)
    (0..movie.duration / 10).each do |second|

      # extract a frame
      filename = "tmp/watermark/#{SecureRandom.uuid}.jpg"
      movie.screenshot filename.to_s, seek_time: second

      # analyse frame for color distance
      frame = MiniMagick::Image.open(filename)
      frame.crop('20%x20%+80%+0')
      frame.resize('1x1')
      pixel = frame.get_pixels.flatten

      distance_from_black = Math.sqrt(((black[0] - pixel[0])**2 + (black[1] - pixel[1])**2 + (black[2] - pixel[2])**2))
      distance_from_white = Math.sqrt(((white[0] - pixel[0])**2 + (white[1] - pixel[1])**2 + (white[2] - pixel[2])**2))

      black_distances.push distance_from_black
      white_distances.push distance_from_white

      File.delete(filename) if File.exist?(filename)
    end

    average_black_distance = black_distances.reduce(:+).to_f / black_distances.size
    average_white_distance = white_distances.reduce(:+).to_f / white_distances.size

对于如何使用结果的average_black_distanceaverage_white_distance来确定要使用哪个水印,我也感到困惑。

1 个答案:

答案 0 :(得分:0)

通过执行以下操作,我可以使其更快:

  1. 使用单个ffmpeg命令获取屏幕截图,而不是遍历movie.length并每x秒拍摄一张照片。
  2. 使用相同的ffmpeg命令裁剪和缩放屏幕截图,而不是使用MiniMagick进行操作。
  3. 使用rm_rf删除而不是在循环内删除。
    # Create folder for screenshots
    foldername = "tmp/watermark/screenshots/#{medium.id}/"
    FileUtils.mkdir_p foldername

    # Take screenshots
    movie = FFMPEG::Movie.new(video_file)
    `ffmpeg -i  #{video_file} -f image2 -vf fps=fps=0.2,crop=in_w/6:in_h/14:0:0,scale=1:1 #{foldername}/out%d.png`

    # Calculate distances
    white = Color .new('#ffffff')
    black = Color .new('#000000')
    distances = []
    Dir.foreach foldername do |f|

      next if %w[. .. .DS_Store].include? f

      f = MiniMagick::Image.open(foldername + f)
      color = f.get_pixels.flatten

      distance_from_black = Color.new(color).color_distance(white)
      distance_from_white = Color.new(color).color_distance(black)

      distances.push distance_from_white - distance_from_black
    end

如果distances.inject(0, :+)的值为正,则捕获的视频区域位于较亮的一侧。感谢@Aetherus!