動画のスライドを抽出する
動画の全スライドを抽出して PDF 化する
スライドの抽出処理
ffmpeg で画像切り出しをした所で下記の記事を発見した。
ありがたや〜早速動かしてみる。
必要なパッケージのインストール
brew install ffmpeg imagemagick
touch movie2slide.sh
movie2slide.sh
#!/bin/bash for command in ffmpeg convert diff do which command$ if [ $? != 0 ]; then echo "$command not found." exit 1 fi done PSNR_threadshold=30 SLIDE_PREFIX=slide RATE=1 isRATEdecimal=$( echo "$RATE > 1" | bc ) PHOTOFORMAT=jpg moviefile=$1 pathname_tmp=${moviefile// /_} pathname=${pathname_tmp%.*} workdirname="${pathname}.$( date +"slide_%Y%m%d_%H%M%S" )" mkdir $workdirname ffmpeg -i "$1" -map 0:1 -vn -ac 2 -acodec pcm_s16le -f wav ${workdirname}/audio.wav ffmpeg -i "$1" -map 0:1 -vn -ac 2 -acodec libmp3lame -f wav ${workdirname}/audio.mp3 ffmpeg -i "$1" -r ${RATE} ${workdirname}/${SLIDE_PREFIX}.%d.png cd ${workdirname} finalslide_number=$( ls | wc -l ) merge_and_delete_duplicated_photos() { local same_picture_begin=$1 local same_picture_end=$2 local j if [ "${same_picture_begin}" != "${same_picture_end}" ];then if [ "${SEQUENCE}" != "" ]; then convert -evaluate-sequence ${SEQUENCE} $( for j in $( seq ${same_picture_begin} ${same_picture_end} ) ; do echo ${SLIDE_PREFIX}.$j.png done ) zmedian.${PHOTOFORMAT} fi for j in $( seq $((same_picture_begin+1)) ${same_picture_end} ) ; do rm ${SLIDE_PREFIX}.$j.png done if [ -e zmedian.${PHOTOFORMAT} ]; then mv zmedian.${PHOTOFORMAT} ${SLIDE_PREFIX}.${same_picture_begin}.${PHOTOFORMAT} fi fi if [ "${PHOTOFORMAT}" != "png" ]; then convert ${SLIDE_PREFIX}.${same_picture_begin}.png ${SLIDE_PREFIX}.${same_picture_begin}.${PHOTOFORMAT} rm ${SLIDE_PREFIX}.${same_picture_begin}.png else pngquant ${SLIDE_PREFIX}.${same_picture_begin}.png mv ${SLIDE_PREFIX}.${same_picture_begin}-fs8.png ${SLIDE_PREFIX}.${same_picture_begin}.png fi } detect_duplicated_photos() { local same_picture_begin=1 local same_picture_end=1 local i for i in $( seq 1 ${finalslide_number} ); do filename_current=${SLIDE_PREFIX}.$i.png filename_next=${SLIDE_PREFIX}.$((i+1)).png filename_start=${SLIDE_PREFIX}.${same_picture_begin}.png if [ -e $filename_current ] && [ -e $filename_next ]; then diff -b $filename_start $filename_next > /dev/null if [ $? -eq 0 ]; then PSNR=0 else PSNR=$( compare -metric PSNR $filename_start $filename_next zdiff.png 2>&1 ) rm zdiff.png PSNR=${PSNR%.*} fi echo -en "$filename_start -> $filename_next : PSNR = " $PSNR if [ $PSNR -eq 0 ] || [ $PSNR -ge $PSNR_threadshold ]; then echo -n " : delete" same_picture_end=$((i+1)) else echo -n " : convert to ${PHOTOFORMAT}" merge_and_delete_duplicated_photos $same_picture_begin $same_picture_end same_picture_begin=$((i+1)) same_picture_end=$((i+1)) fi echo "" fi done merge_and_delete_duplicated_photos $same_picture_begin $same_picture_end } rename_filename_with_timestamped() { for file in $( ls ${SLIDE_PREFIX}.*.${PHOTOFORMAT} ) do filename_tmp=${file%%.${PHOTOFORMAT}} number=${filename_tmp##${SLIDE_PREFIX}.} number=$(( number + 0 )) raw_seconds=$( echo "scale=2; $number/$RATE" | bc ) hour=$( echo "scale=0; $raw_seconds/3600" | bc ) minute=$( echo "scale=0;($raw_seconds -$hour*3600)/60" | bc ) second=$( echo "scale=0;($raw_seconds -$hour*3600 -$minute*60)*2/2" | bc ) if [ $isRATEdecimal == 1 ]; then millisecond=$( echo "scale=0; ($raw_seconds -$hour*3600 -$minute*60 -$second)*100" | bc ) timestamp=$(printf "%02d.%02d.%02d.%02d" ${hour%.*} ${minute%.*} ${second%.*} ${millisecond%.*} ) else timestamp=$(printf "%02d.%02d.%02d" $hour $minute $second ) fi mv $file ${SLIDE_PREFIX}.$timestamp.${PHOTOFORMAT} done for file in $( ls ${SLIDE_PREFIX}.*.${PHOTOFORMAT} ) ; do touch $file ; done } detect_duplicated_photos rename_filename_with_timestamped
実行
zsh ./movie2slide.sh {xxxxx}.mp4
僕の環境で 1 時間の動画を変換するのに 20 分ほどかかった。 また、途中ディレクトリの容量を観察してみると 10GB を超えていたので容量には注意。 最初に出来上がった PNG ファイル 4200 枚が 重複分を削除し、614 枚まで減った。 最終的に 43.8MB に落ち着いた。
PDF 化処理
こちらの記事に大枠はありました。
ありがたや〜。
必要なパッケージのインストール
pip3 install img2pdf
pip3 install natsort
touch convert2pdf.py
img2pdf が brew パッケージにあれば 1 つのシェルスクリプトファイルだけで完結するのだが、仕方なし。 記事では出力された画像がソートされていないのでパッケージを追加して PDF を作成。
convert2pdf.py
import os import img2pdf from PIL import Image if __name__ == '__main__': pdf_FileName = "./output.pdf" # Export PDF filename png_Folder = "./jpg/" # Input Images Directory extension = ".jpg" # convert only jpg files with open(pdf_FileName,"wb") as f: f.write(img2pdf.convert([Image.open(jpg_Folder+j).filename for j in natsorted(os.listdir(jpg_Folder))if j.endswith(extension)]))