본문 바로가기
코딩/Python

[파이썬 활용] 사진(jpg 파일), 동영상(mp4 파일) 용량 줄이기/pillow, ffmpeg 사용

by 나홀로코더 2022. 7. 17.
반응형

목차

1. 주제 소개

2. 사진(.jpg) 파일 용량 줄이기

3. 동영상(.mp4) 파일 용량 줄이기


 

1. 주제 소개

 

일상에서 소소하게 파이썬을 활용하는 시리즈, 그 세 번째 주제로 사진이나 동영상 파일을 줄이는 방법을 소개한다.

 

스마트폰 하나 없는 사람을 찾기 힘든 요즘, 어딜 가나 고품질의 사진과 동영상을 찍을 수 있어 여행 다니기가 편하고 즐겁다.

 

근래에 출시되는 스마트폰을 보면 어느샌가 카메라 성능 경쟁에 가까워 졌고, 그에 따라 사진이나 동영상의 품질이 높아지면서, 동시에 그 파일의 용량도 커졌다. 그래서 여행 몇 번 다녀 오면 스마트폰의 용량이 부족해서 파일들을 어찌하면 좋을지 고민이 된다.

 

어딘가에 백업을 하고 지우자니 사진이나 동영상을 늘 스마트폰에 두고 언제든 찾아 볼 수가 없어 아쉽다. 클라우드 저장소에 저장해 두는 방법의 경우, 용량이 제한적이거나, 사진의 품질을 유지할 수 없는 등 제약점이 많다.

 

그래서 필자는 사진과 동영상의 원본을 USB 메모리 등 별도의 외부 저장소에 보관하고, 스마트폰에는 용량을 줄인 파일을 넣어두고 보는 방법을 택했다. 필자는 이 방법으로 여행 중에 촬영한 사진과 동영상 80기가바이트 정도를 30기기가바이트로 줄였다.

 

반응형

 

2. 사진(.jpg) 파일 용량 줄이기

 

사진 파일의 용량을 줄이는 방법은 동영상에 비해 간단하다. 이미를 다루는 파이썬 라이브러리인 Pillow를 활용한다.

 

먼저 아래 커맨드를 이용해 Pillow를  설치한다.

 

pip install Pillow

 

Pillow를 이용해 이미지를 변환하는 기본적인 방법은 아래와 같다.

 

먼저 Pillow 라이브러리의 Image 클래스를 불러온다.

 

from PIL import Image

 

그런 다음 .open 메서드로 이미지 파일을 열어 이미지 객체를 생성한다.

 

image = Image.open('myfile.jpg')

 

그러고 나서 .save 메서드를 이용해 파일을 저장하는데, 이 때 이미지의 품질 변수를 함께 넘겨 주면 이미지가 변환되어 저장된다. 이미지의 품질 변수(quality)는 0부터 95까지의 숫자 또는 문자열 'keep'을 넘겨줄 수 있다. 숫자가 높을수록 고품질이다. 예제에서는 품질 변수를 50으로 두고 변환해 본다.

 

image.save('resized.jpg', quality=50)

 

품질 변수에 관한 설명은 아래 페이지에 나와 있다.

 

 

Image file formats

The Python Imaging Library supports a wide variety of raster file formats. Over 30 different file formats can be identified and read by the library. Write support is less extensive, but most common...

pillow.readthedocs.io

 

os 라이브러리를 이용해서 변환 전과 후의 파일 크기를 비교해보니 2,072,435바이트에서 522,710바이트로 줄어들었다. 약 4분의 1 크기이다.

 

이미지 파일 변환 전후 크기 비교

 

꽤나 많이 줄어들었지만 이렇게 건건이 변환을 할 것이라면 굳이 복잡하게 파이썬을 사용할 이유가 없다. 이번에는 스크립트를 작성해서 폴더 내의 모든 사진을 한번에 변환해 보자. 

 

from PIL import Image

import os

files = os.listdir() 
# 폴더 내의 파일 목록을 불러온다.

jpgs = [file for file in files if file[-3:] == "jpg"]
# 파일 목록 중에서 확장자가 jpg인 파일만 골라 리스트에 담는다.

for jpg in jpgs:

    image = Image.open(jpg)

    image.save(jpg, quality=50)
    
# jpg 파일 목록 내의 파일을 순회하면서 모두 변환한다.
# 이때 변환 전후의 파일명을 같게 설정했으므로 기존의 파일은 사라진다.

 

jpg 파일 리스트를 만드는 데 사용한 리스트 컴프리헨션에 관해서는 아래 게시글을 참조하기 바란다.

 

 

파이썬에서 코드 한줄로 리스트(딕셔너리, 집합, 제너레이터) 만들기/리스트컴프리헨션, list compr

서론 파이썬의 기초를 배우고 있는 사람이라면 아래와 같은 코드를 한번쯤 보았을 것이다. 반복문을 이용해 리스트를 만드는 방법으로, 대부분의 튜토리얼에서 이 방법을 먼저 선보이고 있는

codealone.tistory.com

 

위 스크립트를 실행하면 파일의 개수에 상관 없이 간편하게 변환이 완료된다. 

 

다만 원본 파일에 담긴 사진 촬영 시간, 장소 등의 정보는 모두 사라지며, 일부 사진은 옆으로 눕거나 반전되는 경우도 있으니 실행 전에 주의할 필요가 있다.

 

반응형

 

 

3. 동영상(.mp4) 파일 용량 줄이기

 

동영상의 경우는 위에 소개한 사진의 경우보다는 조금 더 복잡하다. 리눅스 환경을 기준으로 설명한다. 필자는 스마트폰에 termux를 설치해 리눅스 터미널을 사용 중이다.

 

termux에 대해서는 아래 글을 비롯해서 여러 게시글을 올려두었으니 궁금하면 읽어보기 바란다.

 

 

 

스마트폰에서 파이썬(Python) 코딩 및 주피터노트북 사용하는 방법/termux, 태블릿, 안드로이드

목차 1. 주제 소개 2. termux에서 파이썬 사용하기 3. termux에서 주피터노트북 사용하기 1. 주제 소개 필자는 앞서 Pydroid3 앱을 설치해 안드로이드 스마트폰에서 파이썬과 주피터노트북을 사용하는

codealone.tistory.com

 

동영상 변환 작업에는 음성과 동영상 파일 편집 프로그램인 ffmpeg과 파이썬에서 ffmpeg을 사용할 수 있도록 해주는 ffmpeg-python 라이브러리를 사용한다.

 

아래 커맨드를 이용해 필요한 도구들을 설치한다.

 

pkg install ffmpeg
pip install ffmpeg-python

 

ffmpeg을 설치했다면 커맨드라인에서 바로 사용할 수도 있다. 기본적인 사용법은 다음과 같다. -i 는 입력 파일을 표시하는 것이고, -crf는 품질에 관련된 것이다. 맨 끝에는 변환된 파일의 이름이다.

 

ffmpeg -i 'myfile.mp4' -crf 30 'resized.mp4'

 

품질 변수인 crf에 관해서는 아래의 페이지를 참조하기 바란다. 0부터 51까지의 숫자를 넘겨 주면 되는데, 숫자가 높을수록 저품질이다.

 

 

CBR, CRF, and Changing Resolution using FFmpeg - OTTVerse

In this article, we learn to produce CBR-encoded video, CRF-encoded video, and changing the resolution of a file using FFmpeg.

ottverse.com

 

사진을 변환할 때에 비해서 시간이 꽤 걸린다.

 

동영상 변환 중인 모습

 

필자가 영상을 몇개 변환해 보니, 영상마다 다르지만 대체로 4분의 1 정도로 줄어드는 것을 확인할 수 있었다.

 

이번에는 파이썬을 이용해서 ffmpeg을 사용해 보자.

 

먼저 ffmpeg 라이브러리를 불러온다.

 

import ffmpeg

 

위에서 본 것과 동일한 코드를 파이썬 버전으로 작성하면 다음과 같다.

 

ffmpeg.input('myfile.mp4').output('resized.mp4', crf=30).run()

 

변환 작업을 스크립트로 만들면 다음과 같다. ffmpeg은 변환 중 오류가 꽤 발생하기 때문에 스크립트가 사진 파일 변환할 때보다 조금 더 복잡하다.

 

import ffmpeg

import os

os.mkdir("resized")
# ffmpeg으로 변환할 때는 기존 파일에 덮어쓰기가 안 되므로 변환된 파일들을 저장할 폴더를 생성한다.

files = os.listdir()
# 폴더 내의 파일 목록을 모두 가져온다.

mp4s = [file for file in files if file[-3:] == "mp4"]
# 파일 목록 중에 mp4 파일만 추린다.

err = []
# 변환 중 에러가 발생하는 경우가 있어 에러 처리를 위한 리스트를 만든다.

for mp4 in mp4s:

    try:

        ffmpeg.input(mp4).output("resized/"+mp4, crf=45, vsync="vfr").run()

    except:

        os.remove("resized/"+mp4)

        err.append(mp4)
        
# 파일 변환을 시도한다.(try) 에러가 날 경우 변환 중이던 파일을 지우고 파일명을 err리스트에 추가한다.(except)

    if mp4 in os.listdir("resized"):

        os.remove(mp4)

# 파일이 resized 폴더 내에 있다면(에러가 나지 않고 변환되어 옮겨져 있다면) 원래 폴더에서 파일을 삭제한다.

for mp4 in mp4s:

    if mp4 in err:

        pass

    else:

        os.replace("resized/"+mp4, mp4)

# mp4 파일 목록을 순회하면서 오류 났던 파일(err 리스트)을 제외한 나머지 파일을 원래 폴더로 모두 옮긴다.

os.rmdir("resized")
# resized 폴더를 삭제한다.

print("실패한 목록: \n", err)
# 변환에 실패한 파일 목록을 출력한다.

 

위 스크립트를 사용하면 변환되지 않고 에러가 발생하는 파일이 꽤 된다. 원인을 아직 찾지 못했으나,  mp4 파일이 아닌 avi 파일로 변환을 하면 에러가 발생하지 않는다.

 

avi 파일로 변환하는 스크립트는 다음과 같다. 파일명을 바꾸기 위한 코드 일부와 동영상의 품질 변수(crf 대신 q 사용)만 조금 다르다.

 

import ffmpeg

import os

os.mkdir("resized")

files = os.listdir()

mp4s = [file for file in files if file[-3:] == "mp4"]

err = []

for mp4 in mp4s:

    try:

        ffmpeg.input(mp4).output("resized/"+mp4[:-4]+".avi", q=30).run()

# 확장자를 달리 하기 위해 문자열 슬라이싱([:-4])을 사용했고, 품질 변수로 q를 사용했다.

    except:

        os.remove("resized/"+mp4[:-4]+".avi")

        err.append(mp4)

    if mp4[:-4]+".avi" in os.listdir("resized"):

        os.remove(mp4)

for mp4 in mp4s:

    if mp4 in err:

        pass

    else:

        os.replace("resized/"+mp4[:-4]+".avi", mp4[:-4]+".avi")

os.rmdir("resized")

print("실패한 목록: \n", err)

 

반응형

댓글