일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- transformer
- flame
- 큐
- OpenCV
- re-identification
- level2
- 자료구조
- 프로그래머스
- 알고리즘
- 스택
- numpy
- Object Detection
- Knowledge Distillation
- Python
- center loss
- 임계처리
- Threshold
- Computer Vision
- deep learning
- attention
- 3D
- point cloud
- NLP
- Deeplearning
- Object Tracking
- 딥러닝
- 파이썬
- reconstruction
- cv2
- 논문 구현
- Today
- Total
공돌이 공룡의 서재
[python openCV] 이미지 처리 - 크기 / 색상 변환 : resize, cvtColor 본문
이번 포스트에서 다뤄볼 함수는 이전 포스트의 기본개념을 바탕으로 이뤄진다.
따라서 새로 배울 내용은 없고 바로 코드를 보자.
기본개념 복습!
https://mr-waguwagu.tistory.com/11
<들어가기 전>
크기와 색상 변환 결과로 확인하고자 하는 것은 가로 폭, 세로 폭, 채널 수이다.
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
각 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를 쓰는 것이 좋겠다.
다음 포스트에서는 이미지 임계처리에 대해 다뤄보겠다.