FFmpeg로 동영상이 필요없는 장면 삭제 ~ 장면 검출 및 썸네일 이미지 출력 ~

하고 싶은 일



FFmpeg를 사용하여 동영상에서 필요하지 않은 장면을 삭제합니다.
자신은 스포츠의 동영상 편집을 하는 경우가 많습니다만, 플레이에 관계없는 장면은, 작업전에 삭제해 두면 그 후의 편집이 편해집니다.

FFmpeg란?



동영상이나 음성을 변환·편집할 수 있는 프리의 오픈 소스 툴입니다.
커맨드 라인에서 사용하는 도구로 인해 어려울 수 있지만, 다기능 및 실행 속도가 빠르고 매우 강력한 동영상 편집 도구로 사용할 수 있습니다.

이번에는 FFmpeg의 다음 기능을 사용했습니다.
  • 장면 감지
  • 썸네일 이미지 출력
  • 동영상 잘라내기
  • 동영상 병합

  • 사용한 동영상



    NHK 크리에이티브 라이브러리 당구 동영상 을(를) 다운로드하여 가공했습니다. 비영리 목적이라면 편집하여 공개 가능한 동영상이 되고 있습니다.

    장면 변화를 감지하여 썸네일 이미지 출력



    커맨드 라인에서 다음 명령을 실행하면 동영상의 장면 변화를 감지하여 각 장면의 첫 번째 이미지를 축소판 이미지로 출력합니다. 장면 변화의 정도를 0~1.0까지로 설정할 수 있습니다만, 0.1로 변화가 작아도 검출할 수 있도록 설정했습니다. 또한 ffout이라는 파일명으로 처리 정보가 기재된 파일을 출력합니다.
    $ ffmpeg -i billiards.mp4 -vf  "select=gt(scene\,0.1), scale=640:360,showinfo" -vsync vfr output/%04d.jpg -f null - 2>ffout
    

    출력한 파일 목록은 ↓입니다.


    폴더의 축소판 이미지를 삭제하여 불필요한 장면 삭제



    불필요한 장면이라고 생각하는 썸네일 이미지를 삭제합니다.
    이번에는 당구 공의 확대 화상만 남기고 싶기 때문에, 그 이외의 화상을 삭제했습니다.
    002.jpg 003.jpg 004.jpg
    삭제 중입니다.



    ffout 파일의 내용으로부터 장면 검출한 시간을 배열에 저장한다



    Python 스크립트에서 ffout 파일에서 각 장면의 시작 시간을 추출합니다.
    시작 시간은 pts_time:〇〇.〇〇의 형태로 기재되어 있습니다.
    import re
    from datetime import datetime
    
    
    def loadData(file):
        f = open(file)
        data = f.read()
        f.close()
        return data
    
    
    def getEndTime(data):
        date_pattern = re.compile(r'time=(\d{2}:\d{2}:\d{2})')
        match = re.findall(date_pattern, data)
        dt = datetime.strptime(match[0], '%H:%M:%S')
        endTime = dt.hour * 60 * 60 + dt.minute * 60 + dt.second
        return endTime
    
    
    def getTimes(data):
        pattern = r'pts_time:([0-9]+\.[0-9]+)'  # pts_timeの数値を抽出する
        timeList = re.findall(pattern, data)
        timeList = [float(n) for n in timeList]  # str型をfloat型に変換
        return timeList
    
    
    if __name__ == '__main__':
        data = loadData('ffout')
        endTime = getEndTime(data)
        timeList = getTimes(data)
        timeList.append(endTime)
        print(timeList)
    
    

    결과
    [1.7017, 5.9059, 13.8472, 17.0504, 19.8198, 21.6883, 23.7237, 25.7257, 34]
    

    폴더의 이미지에 남아있는 축소판 이미지의 번호를 인덱스 배열에 저장


    import os
    
    
    def getFIleList(path):
        fileList = os.listdir(path)
        return fileList
    
    
    def getTimeIndex(fileList):
        pattern = r'([1-9]+[0-9]*).jpg'
        index = []
        for i, fl in enumerate(fileList):
            temp = re.findall(pattern, fl)
            if(temp != None):
                index.append(temp[0])
        index = [int(n) - 1 for n in index]  # str型をfloat型に変換
        return index
    
    
    if __name__ == '__main__':
        path = "./output"
        fileList = getFIleList(path)
        index = getTimeIndex(fileList)
        print(index)
    
    

    결과
    [0, 4, 5, 6, 7]
    

    폴더에 남은 썸네일 이미지에서 동영상 파일 생성 (동영상 잘라내기)


    import subprocess
    
    
    def writeFile(fileName, text):
        f = open(fileName, 'w')  # 書き込みモードで開く
        f.write(text)  # 引数の文字列をファイルに書き込む
        f.close()  # ファイルを閉じる
    
    
    def generateCommand(index):
        text = ''
        for i, ii in enumerate(index):
            delta = timeList[ii + 1] - timeList[ii]
            cmd = 'ffmpeg -ss %s' % timeList[ii] + \
                ' -i billiards.mp4 -t %g' % delta + ' output/output%s.mp4' % i
            print(cmd)
            subprocess.call(cmd, shell=True)
            text += 'file output/output' + str(i) + '.mp4\n'
        return text
    
    
    if __name__ == '__main__':
    
        text = generateCommand(index)
        writeFile('mylist.txt', text)
    
    

    위의 스크립트를 실행하면 ffmpeg로 다음 명령을 실행하게 되어 5개의 mp4 파일이 생성됩니다.
    ffmpeg -ss 1.7017 -i billiards.mp4 -t 4.2042 output/output0.mp4
    ffmpeg -ss 19.8198 -i billiards.mp4 -t 1.8685 output/output1.mp4
    ffmpeg -ss 21.6883 -i billiards.mp4 -t 2.0354 output/output2.mp4
    ffmpeg -ss 23.7237 -i billiards.mp4 -t 2.002 output/output3.mp4
    ffmpeg -ss 25.7257 -i billiards.mp4 -t 5.2743 output/output4.mp4
    

    각 동영상 파일 연결



    ffmpeg에서 파일을 나열하고 동영상을 연결하는 방법 를 참고했습니다.
    ↑의 파이썬 스크립트에서 mylist.txt
    file output/output0.mp4
    file output/output1.mp4
    file output/output2.mp4
    file output/output3.mp4
    file output/output4.mp4
    

    라고 기재되어 있습니다.
    아래 명령을 실행하면 mylist 파일에 나열된 동영상 파일을 모두 연결하여 output.mp4 파일로 출력합니다.
    $ ffmpeg -f concat -i mylist.txt -c copy output.mp4
    

    이제 불필요한 장면이 삭제된 동영상이 완성됩니다.

    좋은 웹페이지 즐겨찾기