image는 width, height, channel의 pixel로 이루어진 행렬이다.
@ 주의할점 @
일반적으로 1024x680이라고 적혀있다면 width가 1024, height가 680이라는 의미이지만, OpenCV에서 사용하는 배열 형태에서는 height가 1024, width가 680이라는 의미로 받아들여진다. 즉, width와 height를 적어주는 순서가 다르다.
==> (n, h, w, c) 으로 표현됨
n은 이미지 개수, h는 height, w는 width, c는 channel 수
cv2.imread(filename, [,flags])
cv2.imshow("윈도우창이름", 이미지객체명)
cv2.waitKey(0) # 키보드 입력을 무한히(0으로 표현) 기다린다. 키보드 입력하면 다음 코드로 넘어감.
cv2.destroyAllwindows() # 모든 사진 윈도우창 닫기
예제
import cv2
lenna = cv2.imread("images/Lenna.png")
print(type(lenna), lenna.shape)
# 배열 형태로 불러오게 되고, height width channel 순으로 shape이 이루어진다.
# matplotlib사용해서 출력하기
import matplotlib.pyplot as plt
plt.imshow(lenna)
plt.show()
이 때 출력된 사진 색이 다르게 출력될 것이다. 이유는 OpenCV에서는 BGR로 읽고, matplotlib는 RGB를 사용하기 때문이다. 이건 OpenCV가 처음에 색을 표현하는데 특이한 방식을 이용해서 생긴 해프닝이다.
밑은 matplotlib가 아닌 OpenCV 내장함수를 이용해 출력하는 코드다.
cv2.imshow("frame", lenna)
cv2.waitKey(0)
cv2.destroyAllWindows()
BGR -> RGB 변환하기
lenna_rgb = cv2.cvtColor(lenna, cv2.COLOR_BGR2RGB)
plt.imshow(lenna_rgb)
plt.show()
다음과 같이 BGR을 RGB로 바꾼 뒤 matplotlib를 이용해 출력하면 제대로 된 색으로 출력되는 모습을 확인할 수 있다.
또한 lenna_rgb의 shape을 확인하면 (512, 512, 3)으로 표현됨을 확인할 수 있다. 이는 height, width, color을 나타낸 값으로 3배열은 순서대로 Blue, Green, Red이다. 만약 Blue로 표현된 이미지를 얻고 싶다면 다음과 같이 작성한다.
plt.imshow(lenna_rgb[:,:,2], cmap="gray")
이때 화면에 출력되는 사진은 색이 표현되지 않고 농도가 표현된다! cmap이 회색으로 되어있어, 짙은 회색이면 농도가 낮고 옅은 회색이면 농도가 높음을 알 수 있다.
이때 색은 무조건 RGB나 BGR로만 표현되지 않는다. HSV라는 표현 방식이 있다.
# ex)
cv2.imwrite("경로 및 파일명", image객체)
동영상은 image와 다를게 없다. 여러 image들이 모여진 것이 동영상일 뿐이다.
import cv2
cap = cv2.VideoCapture(0) # (0번)웹캠 불러오기
while cap.isOpened():
success, frame = cap.read()
if not success:
print("캡처실패")
break
cv2.imshow("frame",frame) # 읽어온 웹캠 화면 출력
if cv2.waitKey(1)==27: # waitKey(1)은 1ms이므로 알아차리기 어려울만큼 찰나
break
cap.release()
cv2.destroyAllWindows()
만약 웹캠 영상이 아닌 동영상 파일을 불러오고 싶다면 cap = cv2.VideoCapture(0) 를 cap = cv2.VideoCapture(경로 및 파일명)으로 수정하면 된다.
그리고 동영상의 재생속도는 위 코드에서 if cv2.waitKey(1)==27:에 의해 결정된다. 27은 키보드에서 ESC키를 의미하고 1은 1ms를 의미한다. 즉, 1ms마다 ESC가 눌리지 않으면 다음 프레임을 보여주는 것이다. 이를 늦추고 싶다면 1을 더 큰 수로, 더 빠르게 하고 싶다면 1을 더 작은 수로 바꿔준다.
cap = cv2.VideoCapture("images/wave.mp4")
FPS = cap.get(cv2.CAP_PROP_FPS)
print(FPS)
위 코드로 해당 동영상의 FPS(Frame Per Second)를 알 수 있다. 위에서 설명한 if cv2.waitKey(1)==27:코드에 해당 FPS값을 넣으면 원본과 같은 실행속도의 영상을 출력할 수 있다.
# cv2.VideoCapture.read()로 읽어온 img를 다음과 같이 수정한다.
img = cv2.flip(frame, 1) # 반전
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 색깔변형
웹캠 영상을 저장하는 예제를 통해 알아본다.
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("웹캠 연결 실패")
exit(1)
success, frame = cap.read()
if not success:
print("이미지 캡쳐 실패")
exit(1)
height, width, channel = frame.shape
print(height, width)
FPS = cap.get(cv2.CAP_PROP_FPS)
print(FPS)
codec = cv2.VideoWriter_fourcc(*"MJPG")
######################## 동영상 저장 객체 생성 ########################
writer = cv2.VideoWriter("output/web_cam_output.avi",
codec,
FPS,
(width, height) # width 먼저임 !!!
)
#####################################################################
while cap.isOpened():
success, frame = cap.read()
if not success:
print("이미지 캡쳐 실패")
break
image = cv2.flip(frame, 1)
writer.write(image) # writer에 해당 프레임을 write하기
cv2.imshow("frame",image)
if cv2.waitKey(int(1000/FPS)) == 27:
break
cap.release()
writer.release()
cv2.destroyAllWindows()
src_color = cv2.imread("images/penguin.jpg")
result = cv2.add(src_color, (-100, -100, -100, 0)) # blue green red 명도
cv2.imshow("팽귄",result)
cv2.waitKey(0)
cv2.destroyAllWindows()
위 코드는 밝기가 -100되어서 출력된다.
result = np.clip(img+(img-128)*alpha, 0.0, 255.0).astype("uint8")
위 코드는 최소값 0부터 최대값 255 사이에서 img이미지배열을 img+(img-128)*alpha 만큼 명암을 조정한 코드다. alpha를 조정해서 명암을 조절한다.
img[:,:,1] = np.clip(img[:,:,1]-50.0, 0, 255).astype("uint8")
위 코드는 채도를 조정하는 코드다.(hsv의 0 idx : 색, 1 idx : 채도, 2 idx : 명도 이므로)
위에서 나열된 필터, 윈도우, 마스크, 커널은 모두 같은 말이다. 이 개체는 이미지와 연산하는 NxN 행렬을 의미한다. 이 필터가 어떤값을 가지고 있냐에 따라 이미지에 다양한 처리가 가능하다.
cv2.filter2D(src, # 원본 이미지(영상)
ddepth, # 출력 결과의 타입지정
kernel, # filter배열(float타입)
dst=None, # 처리결과 넣어줄 배열
anchor=None, # kernel의 anchor위치
delta=None, # convolution연산시 추가적으로 더해줄 값(bias)
borderType=None # padding 방식
)
일반적으로 많이 사용되는 필터들이 존재한다. 이 필터들을 알아본다.
cv2.blur(src, ksize)cv2.GaussianBlur(src, ksize, sigmaX, sigmaY)lenna_sharp = np.clip(lenna_rgb+1*(lenna_rgb-lenna_blur), 0, 255).astype("uint8")
cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace)cv2.line(img,(50,50), (250,50), 0, 3 , cv2.LINE_AA)
# 이미지, 시작, 끝, 색, 두께, 라인스타일
cv2.rectangle(img, (50,250), (200,350), (0,120,0), -1, cv2.LINE_AA) # 이미지, 우상단, 좌하단, 색, 두께(-1은 안에 채우기), 라인스타일
이 외의 원 그리기, 다각형 그리기 등등은 위와 비슷한 형식의 매개변수를 받아서 그릴 수 있다.