Hình thu nhỏ có ý nghĩa cho Video bằng FFmpeg


80

FFmpeg có thể chụp ảnh từ video có thể được sử dụng làm hình thu nhỏ để thể hiện video. Các cách làm phổ biến nhất được ghi lại trong FFmpeg Wiki .

Nhưng, tôi không muốn chọn các khung ngẫu nhiên trong một số khoảng thời gian. Tôi đã tìm thấy một số tùy chọn sử dụng các bộ lọc trên FFmpeg để ghi lại các thay đổi cảnh:

Bộ lọc thumbnailcố gắng tìm các khung đại diện nhất trong video:

ffmpeg -i input.mp4 -vf  "thumbnail,scale=640:360" -frames:v 1 thumb.png

và lệnh sau chỉ chọn các khung có hơn 40% thay đổi so với trước đó (và có lẽ là thay đổi cảnh) và tạo ra một chuỗi 5 PNG.

ffmpeg -i input.mp4 -vf  "select=gt(scene\,0.4),scale=640:360" -frames:v 5 thumb%03d.png

Thông tin tín dụng cho các lệnh trên cho Fabio Sonnati . Cái thứ hai có vẻ tốt hơn khi tôi có thể lấy n hình ảnh và chọn thứ tốt nhất. Tôi đã thử nó và nó tạo ra cùng một hình ảnh 5 lần.

Một số điều tra thêm dẫn tôi đến:

ffmpeg -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr  out%02d.png

-vsync vfrđảm bảo rằng bạn có được hình ảnh khác nhau. Điều này vẫn luôn chọn khung đầu tiên của video, trong hầu hết các trường hợp, khung đầu tiên là tín dụng / logo và không có ý nghĩa, vì vậy tôi đã thêm -ss3 để loại bỏ 3 giây đầu tiên của video.

Lệnh cuối cùng của tôi trông như thế này:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg

Đây là điều tốt nhất tôi có thể làm. Tôi đã nhận thấy rằng vì tôi chỉ chọn 5 video, tất cả chúng hầu hết là từ đầu video và có thể bỏ lỡ những cảnh quan trọng xảy ra sau đó trong video

Tôi muốn chọn bộ não của bạn cho bất kỳ lựa chọn tốt hơn khác.


Ví dụ lệnh tốt đẹp. FWIW, tôi đã không gặp phải bất kỳ vấn đề nào với các hình ảnh JPEG do FFmpeg tạo trên OS X (10.8, FFmpeg 1.1 trở xuống). Lệnh thứ hai đến lệnh cuối cùng của bạn hoạt động tốt đối với tôi, vì vậy, lệnh cuối cùng và không có kết quả nào trong các tệp JPG trống. Tôi đã biên dịch với libopenjpeg.. không chắc chắn nếu điều đó làm cho một sự khác biệt.
slhck

Cảm ơn slhck. Chỉnh sửa câu hỏi với chi tiết cấu hình / phiên bản ffmpeg. Tôi chưa nâng cấp lên 1.1 trên máy này. Tôi sẽ làm điều đó và xem nếu nó thay đổi bất kỳ kết quả.
d33pika

1
Vậy bạn đang dùng Ubuntu? Bạn có thể thử phiên bản Git Master mới nhất từ ​​bản dựng tĩnh hoặc tự biên dịch và chạy lại không? Hoặc ổn định mới nhất. Tôi vừa kiểm tra, nó cũng sử dụng mjpegbộ mã hóa cho tôi và tôi cũng đã kiểm tra jpegoptimexiv2cả hai đều hoạt động tốt với tôi với tất cả các kết quả JPG từ các lệnh ví dụ của bạn.
slhck

1
Tôi đã cập nhật, và nó hoạt động ngay bây giờ! Tôi đoán phiên bản trước có một số lỗi.
d33pika

Bạn có thể tiếp tục và đăng giải pháp - phiên bản mới, tốt nhất là có liên kết đến thay đổi hiển thị lỗi bạn gặp phải và sau đó đã sửa với phiên bản mới?
Lizz

Câu trả lời:


29

Cách tìm kiếm, lý tưởng nhất là khung trao đổi> 40% đầu tiên trong mỗi khoảng thời gian 5 lần, trong đó khoảng thời gian là 20% thứ 1, 2, 3, 4 và 5% của video.

Bạn cũng có thể chia nó thành 6 khoảng thời gian và bỏ qua lần đầu tiên để tránh các khoản tín dụng.

Trong thực tế, điều này có nghĩa là đặt fps ở mức thấp trong khi áp dụng kiểm tra thay đổi cảnh và đối số của bạn để loại bỏ bit đầu tiên của video.

...cái gì đó như:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr -vf fps=fps=1/600 out%02d.jpg

1
Hình ảnh hoàn toàn đen hoặc trắng được chọn. Làm thế nào để tôi tránh những hình ảnh đó?
d33pika

1
Có các bộ lọc để phát hiện các khung và chuỗi màu đen của chúng ( ffmpeg.org/ffmpeg-filters.html#blackframe hoặc ffmpeg.org/ffmpeg-filters.html#blackdetect ). Bạn không thể làm việc một trong số chúng trong một lớp lót đang phát triển của mình, nhưng bạn chắc chắn sẽ có thể loại bỏ các khung màu đen (bước riêng biệt) và trích xuất hình thu nhỏ từ video kết quả.
AM

5
Đối với khung màu trắng, hiện tại nó đang trở nên phức tạp, nhưng có vẻ như vẫn có một cách: 1. loại bỏ khung màu đen 2. phủ định (màu trắng chuyển sang màu đen) 3. loại bỏ khung màu trắng 4. phủ nhận lại 5. trích xuất hình thu nhỏ (Nếu bạn quản lý để loại bỏ các khung màu đen hoặc trắng, đặc biệt là trên một dòng, bạn có thể đăng lại ở đây không? Tôi có thể thêm nó vào câu trả lời cho độc giả trong tương lai. ... hoặc thực sự bạn có thể tạo một câu hỏi và câu trả lời mới nó. Tôi chắc chắn sẽ nâng cấp nó.)
AM

3
Để tránh những hình ảnh nhàm chán như đen trắng đơn giản: tạo nhiều hình thu nhỏ hơn mức bạn cần, hãy nén chúng bằng jpeg và chọn những hình ảnh có kích thước tệp lớn hơn. Điều này hoạt động tốt đáng ngạc nhiên của chính nó để có được hình thu nhỏ phong nha.
Sam Watkins

2
Lệnh này không hoạt động, tôi đã gặp lỗi Unable to find a suitable output format for 'fps=fps=1/600'. Giải pháp là thêm -vftrước đối số đó (xem stackoverflow.com/questions/28519403/ffmpeg-command- phát hành )
John Wiseman

7

Xác định ý nghĩa là khó nhưng nếu bạn muốn tạo N hình thu nhỏ bao trùm toàn bộ tệp video thì đây là những gì tôi sử dụng để tạo hình thu nhỏ khi sản xuất với nội dung do người dùng tải lên.

Mã giả

for X in 1..N
  T = integer( (X - 0.5) * D / N )  
  run `ffmpeg -ss <T> -i <movie>
              -vf select="eq(pict_type\,I)" -vframes 1 image<X>.jpg`

Ở đâu:

  • D - thời lượng video được đọc từ ffmpeg -i <movie>một mình hoặc ffprobecó trình soạn thảo đầu ra JSON đẹp btw
  • N - tổng số hình thu nhỏ bạn muốn
  • X - số hình thu nhỏ, từ 1 đến N
  • T - thời điểm cho tumbnail

Đơn giản chỉ cần ghi ở trên khung trung tâm của mỗi phân vùng của bộ phim. Ví dụ: nếu phim dài 300 giây và bạn muốn có 3 hình thu nhỏ thì phải mất một khung hình chính sau 50, 150 và 250. Đối với 5 hình thu nhỏ sẽ là 30, 90, 150, 210, 270. Bạn có thể điều chỉnh N tùy thuộc vào thời lượng phim D, ví dụ: phim 5 phút sẽ có 3 hình thu nhỏ nhưng trên 1 giờ sẽ có 20 hình thu nhỏ.

Hiệu suất

Mỗi ffmpeglệnh gọi ở trên mất một phần giây (!) Cho ~ 1GB H.264. Đó là bởi vì nó ngay lập tức nhảy đến <time>vị trí (tâm trí -sstrước -i) và lấy khung hình chính đầu tiên thực sự hoàn thành JPEG. Không có thời gian lãng phí để kết xuất phim để phù hợp với vị trí thời gian chính xác.

Hậu xử lý

Bạn có thể trộn ở trên với scalehoặc bất kỳ phương pháp thay đổi kích thước nào khác. Bạn cũng có thể loại bỏ các khung màu rắn hoặc thử trộn nó với các bộ lọc khác như thumbnail.


2
wow di chuyển -ss Nđến trước -ilà một mẹo tuyệt vời. cảm ơn bạn!
apinstein 18/03/2016

2

Tôi đã từng làm một cái gì đó tương tự, nhưng tôi đã xuất tất cả các khung hình của video (trong 1 khung hình / giây) và so sánh chúng với một tiện ích perl tôi tìm thấy để tính toán sự khác biệt giữa các hình ảnh. Tôi đã so sánh từng khung hình với các hình thu nhỏ trước đó và nếu nó khác với tất cả các hình thu nhỏ, tôi đã thêm nó vào bộ sưu tập hình thu nhỏ. Ưu điểm ở đây là nếu video của bạn chuyển từ cảnh A sang B và chúng quay lại A, ffmpeg sẽ xuất 2 khung hình A.


Những yếu tố bạn đã sử dụng để so sánh 2 hình ảnh?
d33pika

Thật không may, tôi không nhớ, nó đã khá lâu rồi. Trước tiên, bạn cần quyết định sử dụng phương pháp so sánh nào, sau đó thực hiện một số thử nghiệm để tìm ra yếu tố chính xác. Điều này không nên mất nhiều thời gian.
Eran Ben-Natan 18/03/13

Tôi chỉ nghĩ lớn tiếng ở đây nhưng đây không phải là lựa chọn tồi tệ hơn sao? Khi bạn so sánh 2 hình ảnh được xuất từ ​​video, bạn đã mất một số thông tin từ nó. Ý tôi là, việc tính toán độ tương tự từ thông tin codec dễ dàng hơn so với 2 hình ảnh, phải không? Gần đây tôi đã xem xét một số thuật toán / thư viện để so sánh hình ảnh và chúng không hoạt động tốt như người ta có thể yêu cầu.
Samuel

Chà, với ffmpeg, bạn có thể trích xuất các khung mà không giảm chất lượng bằng cách sử dụng cờ same_quality. Nếu bạn sử dụng thông tin codec, bạn cần kiểm tra xem bạn không chỉ lấy Iframes. Dù sao thì tiện ích perl chỉ hoạt động tốt với tôi và rất cấu hình. Nhìn vào đây: search.cpan.org/~avif/Image-Compare-0.3/Compare.pm
Eran Ben-Natan

2

Thử đi

 ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png

Sử dụng lệnh này, tôi có thể tạo số lượng hình thu nhỏ được yêu cầu đại diện cho toàn bộ video.


Sẽ không phải là công thức chính xác cho fpsđược (no_of_frames_req * fps_of_vid) / total_video_frames?
flolilo

Tôi đang tìm kiếm một giải pháp ngược lại: chọn nhiều khung hình hơn từ các khoảng thời gian mà camera ổn định hơn và không di chuyển? (trong đó sự khác biệt giữa các khung liên tiếp là ít hơn, không cao hơn). Có cách nào làm được việc này không?
Tina J

1

Đây là những gì tôi làm để tạo một hình thu nhỏ định kỳ cho các luồng m3u8 trực tiếp để sử dụng làm poster. Tôi thấy việc chạy một tác vụ ffmpeg liên tục chỉ để tạo hình thu nhỏ ăn hết CPU của mình, vì vậy thay vào đó tôi chạy một cronjob cứ sau 60 giây tạo ra tất cả các hình thu nhỏ cho luồng của tôi.

#!/usr/bin/env bash

## this is slow but gives better thumbnails (takes about 1+ minutes for 20 files)
#-vf thumbnail,scale=640:360 -frames:v 1 poster.png

## this is faster but thumbnails are random (takes about 8 seconds for 20 files)
#-vf scale=640:360 -frames:v 1 poster.png
cd ~/path/to/streams

find . -type f \
  -name "*.m3u8" \
  -execdir sh -c 'ffmpeg -y -i "$0" -vf scale=640:360 -frames:v 1 "poster.png"' \
  {} \;

Nếu bạn cần thực hiện thường xuyên hơn 60 giây (giới hạn của cronjob), thì bạn có thể thực hiện một whilevòng lặp trong tập lệnh của mình và nó sẽ thực thi mãi mãi. Chỉ cần thêm a sleep 30để thay đổi tần số thành 30 giây. Tuy nhiên, tôi không khuyên bạn nên làm điều này với số lượng lớn video, vì lần chạy trước có thể không hoàn thành trước khi video tiếp theo bắt đầu.

Lý tưởng nhất với cronjob tôi chỉ chạy nó cứ sau 5 phút.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.