1. 이미지 읽기
■ OpenCV에서는 imread( ) 함수로 이미지를 BGR 형태로 읽 수 있다.
import cv2
img = cv2.imread('img1.jpg')
■ imread( )의 첫 번째 인수는 읽어올 이미지 파일의 경로이다. 이때, 파일 경로는 절대 경로와 상대 경로 모두 사용 가능하다.
■ imread( )의 두 번째 인수에는 (1) 이미지 파일을 컬러 이미지로 읽을 건지, (2) 그레이 스케일로 읽을 건지, (3) alpha channel(투명도)까지 포함하여 읽을 건지 flag를 지정한다.
(1) cv2.IMREAD_COLOR
- 두 번째 인수의 디폴트 값은 cv.IMREAD_COLOR로 이미지 파일을 컬러 이미지로 읽어 들인다. 이때, 투명한 부분은 무시된다
- 두 번째 인수에 cv.IMREAD_COLOR 대신 숫자 '1'을 지정해도 된다.
img1 = cv2.imread('img1.jpg')
img1.shape
```#결과#```
(1081, 1440, 3)
````````````
- 불러온 이미지는 1081 x 1440 크기의 컬러 이미지임을 확인할 수 있다.
np.array_equal(cv2.imread('img1.jpg', cv2.IMREAD_COLOR), cv2.imread('img1.jpg', 1))
```#결과#```
True
````````````
(2) cv2.IMREAD_GRAYSCALE
- 두 번째 인수에 cv2.IMREAD_GRAYSCALE나 0을 지정하면 이미지를 그레이 스케일로 읽어 들인다.
img2 = cv2.imread('img1.jpg', cv2.IMREAD_GRAYSCALE)
img2.shape
```#결과#```
(1081, 1440)
````````````
- 그레이 스케일로 이미지를 읽었기 때문에 채널 수는 1이 된다.
np.array_equal(cv2.imread('img1.jpg', cv2.IMREAD_GRAYSCALE), cv2.imread('img1.jpg', 0))
```#결과#```
True
````````````
(3) cv2.IMREAD_UNCHANGED
- 두 번째 인수에 cv2.IMREAD_UNCHANGED나 -1을 지정하면 이미지를 투명도까지 포함하여 읽어 들인다.
img3 = cv2.imread('img1.jpg', cv2.IMREAD_UNCHANGED)
img3.shape
```#결과#```
(1081, 1440, 3)
````````````
np.array_equal(cv2.imread('img1.jpg', cv2.IMREAD_UNCHANGED), cv2.imread('img1.jpg', -1))
```#결과#````
True
`````````````
■ imread( ) 함수의 반환값은 이미지 데이터가 담긴 넘파이 배열이다.
img
```#결과#```
array([[[191, 179, 167],
[193, 181, 169],
[193, 181, 169],
...,
[211, 185, 155],
[209, 182, 155],
[206, 179, 152]],
...,
...,
[ 11, 67, 62],
[ 28, 85, 77],
[ 51, 108, 100]]], dtype=uint8)
````````````
- 배열 안의 각 원소가 바로 화소(픽셀) 값이다.
■ 불러온 이미지를 출력하기 위해 cv2.imshow( ) 함수를 사용한다.
■ cv2.imshow( )의 첫 번째 인수에는 이미지를 표시할 창의 이름을 문자열로 지정하고, 두 번째 인수에는 출력할 이미지 데이터가 담긴 넘파이 배열을 지정한다.
■ 첫 번째 인수와 두 번째 인수를 모두 지정하면 imshow( )는 지정된 이름의 창을 생성하고, 생성된 창에 이미지가 나타난다. 이때, 이미지를 표시한 창이 바로 닫히지 않도록 cv2.waitKey( )를 함께 사용하기도 한다.
■ cv2.waitKey( )의 입력으로는 대기할 시간(밀리초)을 입력하며, 0을 입력으로 넣으면 사용자가 키를 누를 때까지 무한정 대기한다.
- 밀리초를 사용하기 때문에 delay = 1000ms으로 설정하면 1초(1s) 동안 대기한다.
■ cv2.imshow( )로 이미지를 표시하고 cv2.waitkey( )를 호출하지 않으면 프로그램이 즉시 종료되고 이미지 창이 닫히게 된다. 이를 방지하기 위해 cv2.waitkey( )를 사용해서 일정 시간 동안 또는 키 입력이 있을 때까지 이미지가 표시되는 창을 유지한다.
■ 동영상을 처리할 때 cv2.waitkey( )는 동영상의 각 프레임 사이에 일정한 딜레이를 주어 재생 속도를 조절하는 역할을 수행한다. 예를 들어 30으로 설정하면, 약 30 FPS의 속도로 동영상이 재생된다.
■ cv.imshow( )를 사용할 때, 보통 cv2.destroyAllWindows( ) 함수도 같이 사용한다. cv2.destroyAllWindows( )는 현재 열려 있는 모든 OpenCV 창을 닫는 역할을 수행한다.
- OpenCV에서는 여러 개의 창을 동시에 열 수 있다. 이때, cv2.destroyAllWindows( )를 사용하면 모든 창을 한 번에 종료할 수 있다.
- 특정 창만 닫고 싶으면 cv2.destroyAllWindows( )에 특정 창의 이름을 지정하면 된다.
■ 다음과 같이 cv2.imshow( ), cv2.waitKey( ), cv2.destroyAllWindows( )를 사용해서 OpenCV 창에 이미지를 나타낼 수 있다.
if img1 is not None:
cv2.imshow('image', img1) # img1을 화면에 표시
cv2.waitKey() # 키가 입력될 때까지 대기
cv2.destoryAllWindows('image') # image라는 이름을 갖는 창을 닫음
else: print('No Image file.')
if img2 is not None:
cv2.imshow('image2', img2)
cv2.waitKey()
cv2.destoryAllWindows() # 모든 창을 닫음
else: print('No Image file.')
2. 이미지 저장하기
■ 이미지를 저장할 때는 cv2.imwrite( ) 함수를 사용한다.
■ cv2.imwrite( )의 첫 번째 인수에는 이미지를 저장할 경로, 두 번째 인수에는 저장할 이미지(넘파이 배열로 표현된 이미지)를 지정한다. 이때, 이미지 파일이 성공적으로 저장되면 True를, 실패하면 False를 반환한다.
cv2.imwrite('../opencv/img_grayscale.jpg', img2)
```#결과#```
True
````````````
■ 세 번째 인수에 리스트 형식으로 (1) JPEG 파일로 저장할 건지, (2) PNG 파일로 저장할 건지, (3) Webp 파일로 저장할 건지 저장할 이미지 형식과 압축률/품질을 지정할 수 있다.
(1) cv2.IMWRITE_JPEG_QUALITY
- 이미지를 JPEG 파일 품질로 설정한다.
- 이때 0에서 100 사이의 값으로 지정할 수 있으며, 기본값은 95이다. 값이 클수록 이미지 품질이 높아진다.(파일 크기가 커진다.)
cv2.imwrite('../opencv/img_grayscale2.jpg', img2, [cv2.IMWRITE_JPEG_QUALITY, 99])
```#결과#```
True
````````````
(2) cv2.IMWRITE_PNG_COMPRESSION
- PNG 파일의 압축 수준을 설정해서 PNG 파일로 저장할 수 있다.
- 이때 0에서 9 사이의 값으로 지정할 수 있으며, 기본값은 3이다. 값이 클수록 압축이 강해져서 파일 크기가 줄어들지만, 저장 속도가 느려진다.
cv2.imwrite('../opencv/img_grayscale3.png', img2, [cv2.IMWRITE_PNG_COMPRESSION, 5])
```#결과#```
True
````````````
(3) cv2.IMWRITE_WEBP_QUALITY
- Webp 파일 품질로 설정한다.
- 1에서 100 사이의 값을 가지며, 기본값은 100이다.
cv2.imwrite('../opencv/img_grayscale4.Webp', img2, [cv2.IMWRITE_WEBP_QUALITY, 99])
```#결과#```
True
````````````
3. 동영상 및 카메라 프레임 읽기
■ OpenCV에서 파일에 있는 비디오를 읽거나 웹캠같은 비디오 장치로부터 실시간 동영상을 읽기 위해 cv2.VideoCapture( )를 사용하여 비디오 데이터를 프레임 단위로 읽는다.
cf) 프레임 단위로 읽는 이유는 '여러 장의 프레임(이미지)이 일정 시간 동안 재생되는 것이 동영상'이기 때문이다.
■ 불러오고자 하는 비디오 데이터가 파일 경로에 있는 비디오라면, cv2.VideoCapture( )의 첫 번째 인수에는 해당 비디오 데이터의 경로를 문자열로 지정한다.
- 예를 들어 비디오 데이터의 형식이 .avi면 '../video.avi', mp4면 '../video.mp4'로 경로를 설정한다.
video1 = '../opencv/video1.mp4'
cap = cv2.VideoCapture(video1) # 동영상 캡쳐 객체 생성
■ 위와 같이 cv2.VideoCapture( )로 생성된 객체는 다음과 같은 메서드들을 사용할 수 있다.
(1) open( ): 비디오 파일이나 카메라 장치를 열기 위해 사용
- VideoCapture( ) 클래스의 생성자 메서드로 이미 열었기 때문에 일반적으로 필요하지 않다.
- 보통 VideoCapture 객체를 재사용할 경우 유용하게 사용한다.
(2) isOpened(): 비디오 파일이나 카메라가 정상적으로 열렸는지 확인
- True를 반환하면 성공적으로 열렸다는 것을 의미한다.
(3) read() : 비디오의 다음 프레임을 읽는다. 이때, read( )는 다음 두 개의 값을 반환한다.
- ret: 프레임을 성공적으로 읽으면 True, 실패하면 False를 반환한다.
- frame: 읽어들인 프레임을 반환한다. 만약, 읽기에 실패했다면 None을 반환한다.
(4) release(): 비디오 파일이나 카메라 장치를 닫고 자원을 해제한다.
- 프로그램이 종료될 때 메모리 누수를 방지하는 데 도움을 주기 때문에 작업이 끝나면 호출하는 것이 좋다.
(5) set( ): 비디오 캡처 속성을 설정하는 메서드이다.
- 예를 들어 해상도, 프레임 속도 등을 설정할 수 있다.
(6) get( ): 비디오 캡처 속성을 가져오는 메서드이다.
- 예를 들어, 현재 프레임의 폭, 높이나 해상도 등을 가져올 수 있다.
if cap.isOpened():
cnt = 0
while True:
ret, img = cap.read() # .read()로 동영상의 프레임을 읽는다. 무한 루프 안에 있으므로 모든 동영상의 프레임을 읽게 된다.
if ret: # <=> if Ture:
cv2.imshow(video1, img) # 화면에 표시
cv2.waitKey(25) # 25ms 지연
cnt += 1
if cnt == 50: # 50개의 프레임만 읽음
break
else: # 더 이상 읽을 프레임이 없으면
break # 종료
else:
print("can't open video")
cap.release()
cv2.destroyAllWindows()
- 여기서 cv2.imshow( )의 첫 번째 인수는 화면에 나타나는 제목, 두 번째 인수는 화면에 표시할 프레임 이미지 객체이다.
- 프레임 한 장당 25ms씩 읽으면 1초가 1000ms이므로 초당 40fps로 읽게 된다.
- 그러므로 동영상을 천천히 재생하고 싶으면 cv2.waitKey( )에 큰 숫자 값을 넣으면 된다.
■ cap.read( )에서 반환되는 frame은 이미지이므로 cv2.imwrite( )를 이용해서 특정 프레임 이미지를 저장할 수 있다.
■ 예를 들어 100번 째 프레임을 .jpg 형식으로 저장하고 싶으면, 다음과 같이 cv2.imwrite( )를 사용하면 된다.
if cap.isOpened():
cnt = 0
while True:
ret, img = cap.read()
if ret:
cv2.imshow(video1, img)
cv2.waitKey(25)
cnt += 1
if cnt == 100:
cv2.imwrite('video1_jpg.jpg', img)
break
else:
break
else:
print("can't open video")
cap.release()
cv2.destroyAllWindows()
■ 비디오 장치(카메라)로부터 비디오를 읽고 싶다면 cv2.VideoCapture( )의 첫 번째 인수에는 카메라 장치의 인덱스를 지정한다.
- 카메라에는 장치 번호가 있으며, 숫자 '0'은 기본 웹캠, 숫자 '1'은 두 번째 카메라를 의미한다.
■ 카메라 장치로부터 불러오는 동영상은 실시간으로 계속 동영상을 읽어 들이기 때문에 별도의 기능을 통해 읽어 들이는 것을 중지해야 한다.
■ 파일에 있는 비디오는 로컬에 저장되어 있기 때문에 일정 시간마다 프레임을 가져올 수 있는데, 카메라 장치는 1초 당 33ms씩 프레임을 가져온다.
cap = cv2.VideoCapture(0) # 0번 카메라 장치 연결
if cap.isOpened():
while True:
ret, img = cap.read()
if ret:
cv2.imshow('camera', img)
if cv2.waitKey(1) != -1: # 1ms 동안 키 입력 대기
break # 아무 키라도 입력이 있으면 중지
else:
print('no frame')
break
else:
print("can't open camera.")
cap.release()
cv2.destroyAllWindows()
- cv.waitKey(1) != -1으로 루프를 탈출한다.
- cv.waitKey( )는 지정된 시간 동안 키 입력이 없으면 -1을 반환한다. 그러므로 아무 키나 입력하면 -1이 반환되지 않기 때문에 조건문은 break를 수행한다.
■ 카메라 장치로부터 동영상을 읽는 경우에도 cv.waitKey(1) != -1와 cv2.imwrite( )를 사용하여 특정 순간의 프레임 이미지를 저장할 수 있다.
cap = cv2.VideoCapture(0)
if cap.isOpened():
while True:
ret, img = cap.read()
if ret:
cv2.imshow('camera', img)
if cv2.waitKey(1) != -1: # 아무 키나 누르면
cv2.imwrite('camera_jpg.jpg', img) # 그 순간의 프레임 이미지 저장
break # 아무 키라도 입력이 있으면 중지
else:
print('no frame')
break
else:
print("can't open camera.")
cap.release()
cv2.destroyAllWindows()
3.1 카메라 비디오 속성 설정
■ OpenCV에서는 다음과 같은 속성 아이디들을 이용해서 카메라 장치의 속성을 설정할 수 있다.
속성 아이디 | 의미 |
cv2.CAP_PROP_FRAME_WIDTH | 프레임 폭 |
cv2.CAP_PROP_FRAME_HEIGHT | 프레임 높이 |
cv2.CAP_PROP_FRAME_FPS | 초당 프레임 수 |
cv2.CAP_PROP_FRAME_AUTOFOCUS | 카메라 자동 초점 조절 |
cv2.CAP_PROP_FRAME_ZOOM | 카메라 줌 |
■ 위와 같은 속성 아이디를 get( ) 함수에 전달하면 해당 속성의 값을 가져올 수 있고, set( ) 함수에 특정 값과 함께 전달하면 특정 값으로 속성이 지정된다.
■ 예를 들어 cv2.CAP_PROP_FRAME_WIDTH = 120, cv2.CAP_PROP_FRAME_HEIGHT = 120, cv2.CAP_PROP_FRAME_FPS = 33으로 설정하면 다음 그림과 같이 120 x 120 크기의 프레임을 33ms씩 순서대로 읽게 된다.
■ 예를 들어 다음과 같이 카메라 장치의 속성 값을 변경하고 cv2.VideoWriter( ) 객체를 생성해서 실시간 동영상을 녹화하여 저장할 수 있다.
cap = cv2.VideoCapture(0)
if cap.isOpened:
file_path = '../opencv/record_video.avi' 저장할 파일 경로
fps = 30.0 # FPS, 초당 프레임 수
fourcc = cv2.VideoWriter_fourcc(*'DIVX') # 인코딩 포맷 문자
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # 현재 프레임 폭 값
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # 현재 프레임 높이 값
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 300) # 프레임 폭을 300으로 설정
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 200) # 프레임 높이를 200으로 설정
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # 재지정한 프레임 폭 값
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # 재지정한 프레임 높이 값
size = (int(width), int(height)) # 재지정한 프레임 크기
out = cv2.VideoWriter(file_path, fourcc, fps, size) # VideoWriter 객체 생성
while True:
ret, img = cap.read()
if ret:
cv2.imshow('recording',img)
out.write(img) # 파일 저장
if cv2.waitKey(int(1000/fps)) != -1: # 지연 시간 33ms
break
else:
print('no frame')
break
out.release() # 파일 닫기
else:
print("can't open camera.")
cap.release()
cv2.destroyAllWindows()
■ cap.get(cv2.CAP_PROP_FPS) 값을 1000에 나누면 적절한 속도로 비디오 파일을 재생할 수 있다.
video1 = '../opencv/video1.mp4'
cap = cv2.VideoCapture(video1) # 동영상 캡쳐 객체 생성
## 비디오 초당 프레임 수
cap.get(cv2.CAP_PROP_FPS)
```#결과#```
30.0
````````````
if cap.isOpened():
fps = cap.get(cv2.CAP_PROP_FPS)
delay = int(1000/fps)
cnt = 0
while True:
ret, img = cap.read()
if ret:
cv2.imshow(video1, img)
print(f'FPS: {fps}, Delay: {delay}ms')
cv2.waitKey(delay) # fps에 맞게 시간 지연
cnt += 1
if cnt == 10:
break
else:
break
else:
print("can't open video.")
cap.release()
cv2.destroyAllWindows()
```#결과#```
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
FPS: 30.0, Delay: 33ms
````````````
'OpenCV' 카테고리의 다른 글
기하학적 변환 (1) (0) | 2024.12.16 |
---|---|
이미지 프로세싱 (3) (0) | 2024.12.15 |
이미지 프로세싱 (2) (0) | 2024.12.14 |
이미지 프로세싱 (1) (0) | 2024.12.13 |
NumPy와 Matplotlib (0) | 2024.12.13 |