PIL

PIL

PIL이란?

  • 파이썬 이미지 처리 라이브러리
  • 이미지 분석 및 처리를 쉽게 할 수 있는 라이브러리(Python Imaging Library, PIL)가 있는데 바로 pillow 모듈
    • 다양한 이미지 파일 형식을 지원하며 강력한 이미지 처리와 그래픽 기능을 제공하는 이미지 프로세싱 라이브러리의 한 종류

주요 기능

  • 픽셀 단위의 조작
  • 마스킹 및 투명도 제어
  • 흐림, 윤곽 보정, 윤곽 검출 등의 이미지 필터
  • 선명도, 밝기, 명암, 색 등의 화상 조정
  • 이미지에 텍스트 추가
  • 기타 여러 가지

이미지 출력

  • Image 클래스의 Image.open() 함수를 사용하면 이미지를 불러올 수 있음
    • show() 함수를 사용하면 기본 이미지를 보는 프로그램이 자동으로 실행
from PIL import Image

img = Image.open(sample)
img.show()

이미지 속성 확인

  • 이미지의 크기, 이름, 모드, 가로 & 세로 길이 등의 정보 확인 가능
from PIL import Image

img = Image.open(sample)
print(f'이미지 파일 이름: {img.filename}')
print(f'이미지 파일 형식: {img.format}')
print(f'이미지 용량: {img.size}')
print(f'이미지 색상 모드: {img.mode}')
print(f'이미지 너비: {img.width}')
print(f'이미지 높이: {img.height}')

이미지 크기 변경

  • 이미지 크기는 resize() 함수를 사용하여 변경
    • 인자값은 튜플 자료형
from PIL import Image

img = Image.open(sample)
resize_img = img.resize((800, 800))
resize_img.save(resize_sample)

# 원본 이미지의 절반(50%)으로 변경
img = Image.open(sample)
(width, height) = (img.width//2, img.height//2)
resize_img = img.resize((width, heith))
resize_img.save(resize_sample)

이미지 자르기

  • 이미지를 자르기 위해서는 crop() 함수를 사용
    • crop() 함수의 인자값은 튜플 자료형으로 4개이며 왼쪽, 위, 오른쪽, 아래 순으로 값을 대입
    • crop((left, upper, right, lower))
from PIL import Image

img = Image.open(sample)
cropped_img = img.crop((100, 100, 200, 200))
cropped_img.show()

이미지 회전

  • Image 클래스의 rotate() 함수를 사용하면 이미지를 원하는 각도만큼 회전 가능
from PIL import Image

img = Image.open(sample)
img.rotate(45).show()

OSError

  • OSError: image file is truncated

해결 방법

LOAD_TRUNCATED_IMAGES

  • 위 변수를 True로 바꿔주면 에러 없이 동작할 수 있음
    • PILImageFile.py를 들어가면 해당 변수가 default값이 False로 설정되어 있는데, True로 바꾸면 truncated image도 로드하겠다는 설정을 하는 것
from PIL import (
	Image, 
    ImageFile,
)

ImageFile.LOAD_TRUNCATED_IMAGES = True
try:
    image = Image.open(sample)
    image = image.convert('RGB')
    ...

finally:
    ImageFile.LOAD_TRUNCATED_IMAGES = False

try-except

  • 이미지를 로드에 성공했지만 해당 이미지가 잘린 이미지라는 것을 확인하려면 어떻게 해야 할까?
    • 로드를 하려면 이미지를 읽을 수 없는 부분을 무시하고 지나가는 것인데, 잘렸다는 것을 어떻게 확인할 수 있을까?
    • pillow를 통해 확인할 수 있는 방법은 try-except
  • 일단 에러를 내고 except에서 OSError를 캐치해서 처리
    • truncated imageopen시에는 에러가 발생하지 않기 때문에 에러가 생길 수 있는 부분부터 try-except에 넣어줌
from PIL import (
	Image, 
    ImageFile,
)

image = Image.open(sample)
try:
    image = image.convert('RGB')
    ...

except OSError as e:
    ...

이미지 파일의 구조를 이용

  • 이미지 파일의 구조를 이용truncated 여부를 찾는 방법
    • LOAD_TRUNCATED_IMAGES는 글로벌 변수이기 때문에 여러 스레드에서 해당 변수를 계속 True에서False로 바꿔줄 경우 thread-safe 하지 않음
  • JPG, JPEG, PNG 파일의 경우 파일의 구조가 정해져있고, 이미지 파일의 끝과 시작을 나타내는 바이트 값이 고정되어 있음
    • 이 고정된 값의 이름을 JPEG, JPG는 EOI (End Of Image), PNG는 IEND라고 함
      • 만약 이미지가 JPG(JPEG)면, EOI(0xff 0xd9)로 끝나야 함
      • 만약 이미지가 PNG면, IEND(49 45 4e 44 ae 42 60 82)로 끝나야 함
    • 그런데 truncated file의 경우 이 값이 고정된 값과 다르게 나타나게 됨
# JPG 파일인 경우
from PIL import Image
from io import BytesIO

# Create black image
image = Image.new("RGB",(64,48))

# Put into a BytesIO
bytes = BytesIO()

# if jpg, Check last 2 bytes
image.save(bytes, format="JPEG")

buff = bytes.getbuffer()
print(buff[-2:].hex())
>>> ffd9


# PNG 파일인 경우
from PIL import Image
from io import BytesIO

# Create black image
image = Image.new("RGB",(64,48))

# Put into a BytesIO
bytes = BytesIO()

# if png, Check last 8 bytes
image.save(bytes, format="PNG")

buff = bytes.getbuffer()
print(buff[-8:].hex())
>>> 49454e44ae426082
  • 기존에 있는 이미지를 가져와 검사하는 경우 truncated imagesave()하게 되면 에러 발생

좋은 웹페이지 즐겨찾기