FFMPEG Определяет средний цвет области видео - PullRequest
2 голосов
/ 09 ноября 2019

У меня есть сценарий использования, в котором я хочу вставить один из двух водяных знаков - один предназначен для темного фона, другой - для светлого фона в видео. Допустим, я бы хотел сделать это в правом верхнем углу видео.

Как определить средний цвет верхней правой части видео? Опубликуйте это, как определить, какой водяной знак использовать, посмотрев на средний цвет?

У меня сейчас есть решение, где я делаю скриншоты с равным интервалом, а затем измеряю средний цвет, но это мучительно медленно, особенно для длинных видео.

# 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_distance и average_white_distance, чтобы определить, какой водяной знак использовать.

1 Ответ

0 голосов
/ 12 ноября 2019

Мне удалось сделать это быстрее, выполнив следующие действия:

  1. Делая снимки экрана с помощью одной команды ffmpeg, вместо того, чтобы перебирать ролики по длине фильма и снимать отдельные кадры каждые 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, :+) положительное, захваченная область видео находится на более яркой стороне. Благодаря @ Эфирус!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...