공돌이 공룡의 서재

[python openCV] 이미지 처리 - 크기 / 색상 변환 : resize, cvtColor 본문

코딩/opencv

[python openCV] 이미지 처리 - 크기 / 색상 변환 : resize, cvtColor

구름위의공룡 2020. 8. 21. 11:43

이번 포스트에서 다뤄볼 함수는 이전 포스트의 기본개념을 바탕으로 이뤄진다.

따라서 새로 배울 내용은 없고 바로 코드를 보자.

 

 

기본개념 복습!

 

https://mr-waguwagu.tistory.com/11

 

[python openCV] 이미지 처리 - 읽기 / 보기 : imread, imshow, waitKey

<기본 개념> 1. 이미지 저장형식 컬러 이미지로는 RGB, BGR, HSV 등이 있고 흑백으로는 Grayscale 형태가 주로 쓰인다. 이미지를 불러오면 전자의 경우 3차원 행렬, 후자의 경우 2차원 행렬이다. 각 저장�

mr-waguwagu.tistory.com


<들어가기 전>

크기와 색상 변환 결과로 확인하고자 하는 것은 가로 폭, 세로 폭, 채널 수이다. 

cv2.imread로 읽은 이미지 파일의 배열에 .shape을 붙이면 세로(height), 가로(width), 채널 수(channel)가 순서대로 나온다.

 

import cv2

ferret = cv2.imread('./ferret.jpg')
print(ferret.shape)

# (540, 961, 3)

 

<크기(해상도) 변환>

1. 필요성

 

이전 포스트에서 결과로 확인한 사진이 그러했지만, 해상도가 높다보니 파일 용량도 클 뿐 아니라, 픽셀 수가 많아서 실행 시간이 좀 걸린다. 실시간 이미지 스트리밍 및 처리에는 이렇게 높은 해상도로 처리하기에는 하드웨어 성능이 따라오지 못 할 수 있다. 또는 반대로 상황에 따라 높은 해상도가 필요할 수 있다. 따라서 크기(해상도) 변환이 필요하다.

 

2. 함수 설명

 

cv2.resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)

 

src: 원본 이미지

dsize: 해상도. (가로,세로) 형태로 값을 지정해야 한다. 꼭 소괄호 형태로 지정해주시길.

fx: 가로 확대.축소 비율 설정 0.5면 가로가 절반으로 줄어듬

fy: 세로 확대.축소 비율 설정

interpolation: 사전적 의미로는 보간법이라고 하는데 이미지 크기가 바뀌면서 생기는 문제를 해결하기 위한 방법이다.

이미지가 커진다고 생각하면 기존 픽셀들 사이에 해당하는 픽셀의 값을 결정해야 하고, 이미지가 줄어든다고 생각하면 기존 픽셀들의 수보다 더 적은 수로 표현하므로 정보를 잃는 문제가 생긴다. 

 

flag로는 여러 종류가 있는데 대표적인 것들은 다음과 같다.

  • cv2.INTER_NEAREST : 인접한 픽셀들의 정보 이용
  • cv2.INTER_LINEAR : 쌍선형 보간법 이용
  • cv2.INTER_AREA : pixel area relation을 이용하여 resampling
  • cv2.INTER_CUBIC: 4x4 픽셀 이웃들을 이용
  • cv2.INTER_LANCZOS4: 8x8 픽셀 이웃들을 이용

+@:

https://stackoverflow.com/questions/23853632/which-kind-of-interpolation-best-for-resizing-image

https://stackoverflow.com/questions/3112364/how-do-i-choose-an-image-interpolation-method-emgu-opencv

 

각 flag별로 어떻게 다르고 사용법이 어떠한지 찾다가 stackoverflow에서 도움될만한 2개의 글을 보게 되었다. 일반적으로 이미지가 줄어들 땐 cv2.INTER_AREA, 확대될 땐 cv2.INTER_CUBIC, cv2.INTER_LINEAR를 사용한다고 하는데 자세한 이유는 나와있지 않다.

기회가 되면 왜 그러한지 보간법의 자세한 내용에 대해서는 좀 더 공부하고 올려보도록 하겠다. 

 

+@:

아래 코드를 실행하고 나면 보간법에 따른 차이가 큰가? 라는 의문점이 드는 분들을 위한 링크.

참고로 보면 될 것 같다.

https://chadrick-kwag.net/cv2-resize-interpolation-methods/

 

3. 코드

 

import cv2

ferret = cv2.imread('./ferret.jpg')

img1 = cv2.resize(ferret, dsize=(640, 480))
img2 = cv2.resize(ferret, dsize=(0,0), fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)

cv2.imshow('original', ferret)
cv2.imshow('use dsize=', img1)
cv2.imshow('use fx, fy', img2)
cv2.waitKey()

 

dsize= 를 이용하여 해상도를 수치로 지정한 경우 fx와 fy는 필요 없다. 

반대로, 정확한 해상도는 잘 모르겠고 그냥 원본의 가로 세로 비율로 조절하고 싶은 경우 fx와 fy를 이용하면 된다. 다만 이 경우 dsize=(0,0)으로 선언해야 한다. 선언 안 하면 오류가 뜬다.

 

결과는 다음과 같다.

 

 

<색상 변환>

1. 필요성:

 

이전 포스트에선 간단히 cv2로 이미지 보는 방법만 하고 넘어갔는데, 불러들인 이미지 픽셀 값 자체로만 보면 사실은 다음과 같다.

 

import cv2
import matplotlib.pyplot as plt

ferret = cv2.imread('./ferret.jpg')

plt.imshow(ferret)
plt.show()

이는 cv2.imread()를 사용하면 픽셀을 RGB순서가 아니라 BGR 순서로 읽기 때문이다.

 

2. 함수 설명

 

cv2.cvtColor(src, code, dst=None, dstCn=None)

 

src: 원본 이미지

code: 어떤 색상으로 변환할 것인지를 결정 flag와 유사하다.

dst: 결과 이미지. 선언해주지 않으면 결과 이미지를 return한다.

dstCn: 결과 이미지의 채널 수. 0으로 선언하면 자동으로 설정된다. 경우에 따라 따로 설정해주지 않아도 되는듯

 

주로 쓰는 code의 종류는 다음과 같다.

  • cv2.COLOR_BGR2RGB
  • cv2.COLOR_BGR2GRAY
  • cv2.COLOR_BGR2HSV

아무래도 원본이 BGR 순서로 픽셀을 읽다보니 위의 3개가 주로 쓰이는데 반대로 RGB2BGR, GRAY2RGB 등 여러 형태로 변환이 가능하다. 

 

import cv2
import matplotlib.pyplot as plt

ferret = cv2.imread('./ferret.jpg')
cv2.cvtColor(ferret, cv2.COLOR_BGR2RGB, dst=ferret)

plt.imshow(ferret)
plt.show()

plt로 plot을 했을 때 원본 그대로 나타남을 확인할 수 있다.

 

dst= 로 선언하지 않고 return 형태로 다음과 같이 작성하는 것도 가능하다.

import cv2
import matplotlib.pyplot as plt

ferret = cv2.imread('./ferret.jpg')
ferret = cv2.resize(ferret, dsize=(0,0), fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
HSV = cv2.cvtColor(ferret, cv2.COLOR_BGR2HSV)
Gray = cv2.cvtColor(ferret, cv2.COLOR_BGR2GRAY)


cv2.imshow('Original', ferret)
cv2.imshow('HSV', HSV)
cv2.imshow('Gray', Gray)
cv2.waitKey()

 

 

+@:

plot을 할 때 plt를 쓰든 cv2를 쓰든 상관없다.

다만 RGB = cv2.cvtColor(ferret, cv2.COLOR_BGR2RGB)를 하고 RGB를 cv2로 plot했을 시

오히려 BGR처럼 나왔다. plt와 cv2에서 plot하는 방식의 차이가 있는 듯 하다.

 

+@:

print(Gray.shape)
print(ferret.shape)

plot한 후에 위 2줄을 추가해서 실행해보자.

흑백사진의 경우 HSV에서 V값만 갖고 있으므로 채널이 1개임을 알 수 있다.

 

Gray의 경우 다음과 같이 imread에서 flag를 설정하여 cvtColor를 쓰지 않고도 가능하다.

 

import cv2
import matplotlib.pyplot as plt

ferret = cv2.imread('./ferret.jpg', cv2.IMREAD_GRAYSCALE)

cv2.imshow('gray', ferret)
cv2.waitKey()

 

흑백으로 바꿀 시 그럼 cvtColor를 쓰지 않는 것이 코드가 더 짧아지고 보기 편하지 않나 싶을 수 있다.

결과상의 차이는 없다. 다만 시간상 차이가 존재한다.

 

cvtColor를 사용할 때 IMREAD_GRAYSCALE을 사용했을 때 보다 시간이 더 빨랐다. 

 

다음은 두 함수의 성능을 확인하기 위한 코드다. 

import time
import cv2
import numpy as np
import glob
import os

images = sorted(glob.glob('C:\\Users\\82106\\Desktop\\edison\\road\\*.jpg'), key=os.path.getctime)
read_n_cvt = []
read_flag = []
wrong = []
back = []
for path in images:
    start = time.perf_counter()
    img1 = cv2.imread(path)
    gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    finish = time.perf_counter()
    read_n_cvt.append(finish - start)

    start = time.perf_counter()
    img2 = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
    finish = time.perf_counter()
    read_flag.append(finish - start)

read_n_cvt = np.array(read_n_cvt)
read_flag = np.array(read_flag)
print(np.mean(read_flag)) 	# 0.0026초
print(np.mean(read_n_cvt))  # 0.0045초

실시간 이미지 처리가 목표일 경우 조금이라도 빨리 처리하는 것이 더 좋으므로 cvtColor를 쓰는 것이 좋겠다. 

 

다음 포스트에서는 이미지 임계처리에 대해 다뤄보겠다.

Comments