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은 안에 채우기), 라인스타일
이 외의 원 그리기, 다각형 그리기 등등은 위와 비슷한 형식의 매개변수를 받아서 그릴 수 있다.