waifu2x-caffeとffmpegで動画を拡大するPowerShellスクリプト

どういうものか

waifu2xという、機械学習の結果を利用して、画像をきれいに拡大したり、圧縮時のノイズを除去したりするソフトウェアが公開されています。
そのWindows向けビルドがwaifu2x-caffeで、動画変換ソフトのFFmpegと組み合わせることで動画をきれいに拡大することができるため、PowerShellスクリプトで自動的に処理を流せるようにしました。

※waifu2xの処理は動画向けではないため、元々大きいサイズの動画があれば、もちろんそちらのほうが良いです。

各コマンドは「RICOH THETA Sの動画機能を4k相当に拡張する(waifu 2x で) – izm_11’s blog」を参考にさせていただきました。

対象フォルダに入れた動画を以下の流れで変換します。

  1. ffprobe(FFmpegに付属)で対象の動画情報を取得
  2. ffmpegで音声を分離
  3. ffmpegで動画を1コマずつ画像に分離
  4. waifu2x-caffeによる画像の拡大とノイズ除去
  5. ffmpegにより拡大済み画像と音声を結合してmp4(H264)の動画に変換
  6. 次の動画があれば1から処理

作った理由

古いMVをwaifu2x-caffeとffmpegで4Kにして見るのが最近の個人的トレンドなのですが、とてもとてもとても処理に時間がかかる。
それなりに高くて新しいグラフィックボード(GTX1080)で3分の動画を4Kに変換すると2時間20分かかりました。
で、PCに張り付いて手動でコマンドを打つのは大変なので、自動化することにしました。

ホントはスクリプト作り込むなら慣れてるLinuxでやりたかったけど、それなりのグラボを積んだPCはWindows10で、理由があり別OSを入れられない状況。
プラスして、Windows 10のデフォルトシェルがPowerShellになるという話を見たばかりなのでPowerShellで作りました。

必要ソフトウェアと動作確認バージョン

スクリプト

本スクリプトで損害が発生しても当方は責任を負いません。(おやくそく)

###
# 設定

$movieWidth = 3840 # 変換後の横サイズ
$movieHeight = 2160 # 変換後の縦サイズ

$ffmpegPath = 'C:\ffmpeg\bin\ffmpeg.exe' # ffmpeg.exeのパス
$ffprobePath = 'C:\ffmpeg\bin\ffprobe.exe' # ffprobe.exeのパス
$waifu2xCaffeCui = 'C:\waifu2x-caffe\waifu2x-caffe-cui.exe' # waifu2x-caffe-cui.exeのパス

$inputFolder = 'D:\INPUT' # 入力ディレクトリ
$outputFolder = 'D:\OUTPUT' # 出力ディレクトリ
$fileType = ('*.mp4','*.avi') # 処理対象の拡張子
$tmpFolder = 'D:\tmp' # 作業用フォルダ(一時的に画像等を展開するため、それなりの容量が必要)

# Waifu2xCaffeのオプション
# オプションについては公開元をご参照ください
# https://github.com/lltcggie/waifu2x-caffe
$noiseScaleMode = 'noise_scale'
$noiseLevel = 1
$processType = 'gpu'
$cropSize = 512
$modelDir = 'models/upconv_7_anime_style_art_rgb'

##
# 以下処理

$tmpSourceImageFolder = $tmpFolder + '\movie2x\img_s'
$tmpSourceImageFiles = $tmpSourceImageFolder + '\img_%07d.jpg'
$tmpConvertImageFolder = $tmpFolder + '\movie2x\img_c'
$tmpConvertImageFiles = $tmpConvertImageFolder + '\img_%07d.png'
$tmpSourceWaveFile = $tmpFolder + '\movie2x\base.wav'

function RunProcess($exePathe, $argObj){
  $pinfo = New-Object System.Diagnostics.ProcessStartInfo
  $pinfo.RedirectStandardOutput = $true
  $pinfo.UseShellExecute = $false
  $p = New-Object System.Diagnostics.Process

  $pinfo.FileName = $exePathe
  $pinfo.Arguments = $argObj
  $p.StartInfo = $pinfo
  $p.Start() | Out-Null

  Write-Output $p
}

Remove-Item $tmpSourceImageFolder -recurse 2> $null
Remove-Item $tmpConvertImageFolder -recurse 2> $null
Remove-Item $tmpSourceWaveFile 2> $null

Get-ChildItem -Path $inputFolder -Recurse -Include $fileType | ForEach-Object {
  $date = Get-Date -Format "yyyy/MM/dd HH:mm"
  Write-Host "$date ファイル : $_ の処理を開始しました。" 

  ###
  # 動画の情報をffprobeで取得
  $expArg = '"' + $_.Fullname + '" -show_entries format -show_streams -print_format json'
  $process = RunProcess $ffprobePath $expArg

  $stdout = $process.StandardOutput.ReadToEnd()
  $json = $stdout | ConvertFrom-Json

  $fpsStrings = $json.streams[0].avg_frame_rate -split '/'
  $fps = $fpsStrings[0] / $fpsStrings[1]
  $sourceMovieWidth = $json.streams[0].width
  $sourceMovieHeight = $json.streams[0].height

  ##
  # 作業ディレクトリの作成
  New-Item $tmpSourceImageFolder -type directory -Force | Out-Null
  New-Item $tmpConvertImageFolder -type directory -Force | Out-Null

  ##
  #ffmpegにより音声/画像の分離
  $expArg = ' -i "' + $_.Fullname + '" -vn "' + $tmpSourceWaveFile

  $process = RunProcess $ffmpegPath $expArg
  $process.WaitForExit()

  $expArg = ' -i "' + $_.Fullname + '" -f image2 -vcodec mjpeg -qscale 1 -qmin 1 -qmax 1 "' + $tmpSourceImageFiles

  $process = RunProcess $ffmpegPath $expArg
  $process.WaitForExit()

  ##
  #widthとheightのどちらに合わせるべきか判定
  if($movieWidth / $sourceMovieWidth -lt $movieHeight / $sourceMovieHeight){
    $scaleString = ' --scale_width ' + $movieWidth
  }else{
    $scaleString = ' --scale_height ' + $movieHeight
  }

  ##
  # waifu2x-caffeによる画像の拡大とノイズ除去
  $expArg = ' -i ' + $tmpSourceImageFolder + ' -o ' + $tmpConvertImageFolder + ' --model_dir ' + $modelDir + ' -m ' + $noiseScaleMode + $scaleString +' --noise_level ' + $noiseLevel + ' -p ' + $processType + ' -c ' + $cropSize

  $process = RunProcess $waifu2xCaffeCui $expArg
  $process.WaitForExit()

  ##
  # ffmpegにより画像と音声を結合してmp4(H264)の動画に変換
  $expArg = ' -r ' + $fps + ' -i "' + $tmpConvertImageFiles + '" -i "' + $tmpSourceWaveFile + '" -f mp4 -vcodec libx264 -bufsize 20000k -maxrate 25000k -s ' + $movieWidth + 'x' + $movieHeight + ' -aspect ' + $sourceMovieWidth + ':' + $sourceMovieHeight + ' -pix_fmt yuv420p "' + $outputFolder + '\' + $_.Name + '"'

  $process = RunProcess $ffmpegPath $expArg
  $process.WaitForExit()

  Remove-Item $tmpSourceImageFolder -recurse 2> $null
  Remove-Item $tmpConvertImageFolder -recurse 2> $null
  Remove-Item $tmpSourceWaveFile 2> $null

  $date = Get-Date -Format "yyyy/MM/dd HH:mm"
  Write-Host "$date ファイル : $_ の処理が完了しました。" 
}

コメント

  1. みみ より:

    waifu2x-caffe-cui.exeが動作を停止してしまいます。
    GTX1060なのでスペック的には大丈夫だと思ったのですが

  2. 匿名 より:

    AniZipも使えば高速化もできそうですね