JPG(Joint Photographic Experts Group)
디지털 이미지 규격은 GIF, JPG(JPEG), PNG, BMP, TIFF, RAW 등이 있다. 여기서 일반적으로 많이 쓰이는 이미지 규격은 GIF, JPG(JPEG), PNG이다. 일반적으로 화질이 좋으면 용량은 커진다. 파일의 크기순대로 이미지 파일 포맷을 나열하면 아래와 같다.
GIF < JPG(JPEG) < PNG < BMP < TIFF < RAW
그중 JPG(Joint Photographic Experts Group)는 압축 손실 방식이지만 이미지 손상을 최소화하며 효율적으로 압축하여 용량을 줄이는 방식이다. 이 과정에서 DCT(discrete cosine transform)라는 이산 코사인 변환을 수행한 후 데이터를 줄이기 위해 Quantization(양자화)를 한다.
여기서 양자화란 자연스러운 색상을 단순화시키는 역할을 의미한다. 양자화를 통해 색의 수가 줄어들게 되고 이때 데이터의 손실이 발생하게 된다. 이미지 편집 프로그램에서 압축률을 조절할 수가 있는데 압축률이 높으면 용량은 작아지지만 이미지 손상이 커진다. 문자, 선, 세밀한 격자 등이 있는 이미지라면 품질 저하가 눈에 띄게 커진다.
이런 JPG의 단점을 보완해 주는 파일 포맷이 PNG(Portable Network Graphics)이다. JPG 보다 용량은 크지만 비손실 압축 방식으로 품질 저하가 없고 알파 채널을 이용한 투명층을 지원해서 이미지 합성 등에 많이 사용된다. 모니터는 빛의 3원색(Red, Green, Blue)을 섞어 이미지를 보여 준다. 이런 빨간색, 녹색, 파란색을 줄여서 RGB라 하는데 일반적인 화면은 RGB 3개의 채널을 가지고 있고 이 3가지 채널 외에 편집용 정보를 취급하는 보조 채널을 알파 채널이라고 한다. 이 알파 채널을 이용해 흔히들 말하는 누끼를 따거나 하는 것이 가능해지며 배경이 투명한 이미지들을 만들어낼 수도 있다.
참고로 png 파일 용량은 (width * height * 3channel)KB가 된다.
따라서 일반적으로 글자가 많은 이미지일 경우 폰트에 약간의 블러(Blur) 현상 때문에 PNG 파일을 사용한다. 반대로 이미지 파일 용량을 줄이기 위해 BMP나 PNG보다 JPG 포맷을 이용해 전송 효율에서 이득을 취할 수 있다.
다만 png도 확대하면 aliasing 현상이 발생하는데 이러한 단점을 보완하기 위해 SVG(Scalable Vector Graphics) 파일 포맷을 사용할 수 있다. JPG, PNG와 같은 Raster Image와 달리 SVG는 Vector Image이므로 확대시에도 이미지가 깨지지 않고 반응형으로 함께 커진다.
요즘 디자이너들은 단순한 회사 로고나 아이콘을 만들 때 SVG를 사용한다고 한다. PNG처럼 투명한 배경도 가능하지만, 용량은 더 작은 장점이 있다. 또한, PNG에 비해서 용량도 작으며, 출력도 빠르고, 애니메이션도 가능하다. 하지만 이미지가 복잡해지면 용량도 커지고 속도 저하를 일으킨다. 또한 SVG로 표현하기 어려운 이미지들도 존재한다. 따라서 아직까지는 단순하고 심플한 이미지에 주로 SVG를 사용한다.
다시 돌아와 png 파일을 python을 이용해 jpg 파일 포맷으로 변환시켜본다. 일반적으로 Pillow나 opencv 라이브러리를 이용해 변환을 수행한다.
Pillow
우선 Pillow를 이용한 방법이다.
from PIL import Image
img = Image.open('test.png')
img.save('result.jpg')
또는 아래와 같이 사용할 수도 있다.
from PIL import Image
img = Image.open('test.png').convert('RGB')
img.save('result.jpg', 'jpeg')
반대로 jpg를 png로 바꿀 수 있다.
from PIL import Image
img = Image.open('test.jpg').convert('RGB')
img.save('result.png', 'png')
이미 손실 압축한 것을 비손실 압축인 png로 변환하는 것이 무슨 의미가 있겠냐 싶겠지만 jpg와 png는 file format이다. 따라서 파일 내부의 헤더 구조 등이 변경되므로 결과적으로 의미가 있다. 또한 나중에 고화질의 재편집을 해야 한다면 PNG로 저장해 놓는 것이 낫다. JPEG를 사용할 때는 저장을 하면 할수록 계속 손실이 누적될 수 있기 때문이다.
OpenCV
다음은 OpenCV를 이용한 변환 방법이다. 먼저 png를 jpg로 바꾸는 방식이다.
import cv2
img = cv2.imread("test.png")
cv2.imwrite("result.jpg", img)
압축률과 품질 또한 조절할 수 있다. 파일 포맷은 bmp, png, jpg 등으로 지정하면 그 포맷에 맞게 파일을 저장한다.
import cv2
img = cv2.imread("test.jpg")
cv2.imwrite('result.bmp', img)
cv2.imwrite('result.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 9]) #0 ~9, 압축율
cv2.imwrite('result.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 10]) #0~100 품질
추가적으로 openCV는 BGR 방식으로 이미지 색상을 표현한다. 따라서 matplotlib에서 이미지를 그리게 될 때는 RGB로 변경해야 하는데, OpenCV 개발 당시 카메라 제조사 등이 BGR포맷을 선호해서 그랬다고 한다.
import cv2
img = cv2.imread('test.jpg')
B, G, R = cv2.split(img)
result = cv2.merge([B,G,R])
이외에도 HSV, YUV, YCbCr와 RGB에 Alpha 채널을 더한 색 표현 방식인 RGBA 등의 여러 색상 표현 방식이 존재한다.
참고 자료
https://blogchannel.tistory.com/269