프로젝트 도중에 파이썬으로 이미지를 다루는 법을 깨달은 것을 정리해서 적어본다.
보통 구글에 파이썬으로 이미지 다루기나 opencv, Pillow(PIL)에 대해서 검색해보면, imwrite나 save같은 함수를 사용해서 이미지를 파일로 저장하는 것 위주의 내용만 나온다.
그래서 이미지를 어떻게 byte로 다룰수 있을까에 대해서 내 나름대로 생각한 결과가 이 글이라고 보면 된다.
나중에 나도 생각나지 않으면 다시 볼 겸...
이 글은 StyleGAN3 모델을 이용해서 생성된 이미지(bytes형태)를 어떻게 Azure blob storage에 업로드할까를 생각하다 작성하게 되었다.
가장 중요한 것
이미지를 저장하기 위해서는 이미지가 인코딩 되어야 한다.
이미지 처리 순서
1. 이미지의 차원을 맞춘다.
이미지의 형태가 (height, width, channel) 이 되도록 맞춰주어야 한다. (width, height, channel일수도 있다)
styleGAN3의 경우 이미지를 생성하게 되면 (batch, channel, height, width) 형식의 Tensor가 리턴이 된다.
따라서, batch를 없애고 channel, height, width의 순서를 변경해 주어야 한다.
아래의 코드는 내가 사용한 코드이다. 여러분들이 사용하는 라이브러리에 따라 코드는 다 다를테니, 위에 적어놓은 개념과 순서만 배워가면 좋을 것 같다.
# 생성된 이미지가 img라는 변수에 담겨있다고 하자.
# permute를 이용해서 (batch, channel, height, width)를 (batch, height, width, channel)로 변경한다.
# 0번째 인자를 0번째에, 2번째 인자를 1번째에, 3번째 인자를 2번째에, 1번째 인자를 3번째로 재배치 한다는 의미
img=img.permute(0,2,3,1)
# batch를 없애준다. 즉 차원을 3차원으로 만들어준다.
img = img.squeeze(0)
2. 차원을 맞춘 이미지를 numpy 형태로 변환한다.
나는 지금 img 변수의 타입이 Tensor타입이다. 여러분들도 각자의 타입에 맞는 함수를 사용해서 numpy로 바꾸도록 하자.
참고로, numpy array의 원소들의 타입은 uint8이어야 한다.
# Tensor를 numpy로 변환
img = img.cpu().numpy()
# -1 ~ 1로 정규화된 상태이기 때문에 해당 데이터를 다시 반정규화 해준다.
img = (img + 1) * (255/2)
# 그리고 numpyarray의 원소들의 타입은 uint8로 맞춰주어야 한다.
img = img.astype(np.uint8)
3. 해당 numpy array를 원하는 형식에 맞게 encoding 한다.
opencv-python의 imencode 함수를 사용해서 컴퓨터가 이해할 수 있도록 encoding 한다.
아래 예제는 jpg로 인코딩하는 것을 말한다.
img = cv2.imencode(f".{ext}", img)[1].tobytes()
# ex
img = cv2.imencode(".jpg", img)[1].tobytes()
이렇게 되면 인코딩된 img라는 변수는 bytes타입을 가지게 되고, 이 img 변수를 이용해서 jpg 형식으로 이미지를 저장할 수 있게 된다.
예를들어, Azure blob storage에 img를 저장하려면
# Azure blob storage에 img 업로드
blob_client.upload_blob(img)
이렇게 코드를 작성해주면 된다.
주의사항
와 진짜... 이미지를 저장했는데 계속 파란색으로 나와서 뭐가 잘못되었는지 한참 고민을 했는데,
cv2는 컬러사진을 BGR순서로 저장한다는 것을 깨달았다.
지금 막 깨닫고 글을 급하게 추가로 적는건데... 와... 미쳤다... 기분 너무 좋다.
그러므로 cv2.cvtColor를 해주어야 한다.
나의 경우는 cv2.imencode하기 전에 해주었다.
# RGB 이미지를 cv2형식에 맞는 BGR로 변환해준다.
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)