[Python] OpenCV 카메라 다루기

OpenCV에서 이미지를 다루는법을 전 포스팅에서 작성했는데,

카메라 다루는법도 있어 남깁니다.

 

카메라(웹캡) 프레임 읽기

import cv2

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()

OpenCV에서 웹캠으로 라이브 영상을 읽을 수도 있습니다.

만약 사용하시는 노트북이나 PC에 웹캠이 있다면 아래 코드를 실행할 수 있습니다.

위 코드를 실행하면 웹캠을 통해 자신의 모습이 보이는 창이 하나 뜰 겁니다.

 

cv2.VideoCapture()은 인자로 동영상 파일 경로를 입력할 수도 있지만
카메라 장치 번호를 입력할 수도 있습니다.
동영상 파일 경로를 입력하면 해당 동영상의 캡처 객체가 return 되지만,
카메라 장치 번호를 입력하면 웹캠과 연결됩니다.
카메라 장치 번호는 0부터 시작합니다.
웹캠이 하나밖에 없다면 인자로 0을 넣으면 됩니다.

cap.isOpened()는 cap 객체가
지정한 파일로 정상적으로 초기화되었는지 확인하는 코드입니다.
초기화가 잘 되었다면 True를 반환하고,
그렇지 않으면 False를 반환합니다

연속해서 파일의 프레임을 읽어오기 위해
while로 cap.read()를 호출합니다.

프레임을 잘 읽었다면 ret은 True, img는 프레임 이미지가 됩니다.
제대로 읽히지 않았다면 ret은 False, img는 None이 됩니다.

다음 프레임 읽기가 실패하는 경우는
파일이나 장치에 문제가 있거나 파일의 끝에 도달했을 경우입니다.

이제, cv2.imshow(video_file, img)를 호출하여
프레임 이미지를 화면에 표시합니다.

카메라로부터 프레임을 읽는 경우
파일의 끝이 정해져 있지 않아 cv.waitKey(1) != -1 코드에서
사용자가 아무 키나 누르면 break가 되어 루프를 빠져나옵니다.

cv2.waitKey() 함수는
지정된 시간 동안 아무 키 입력이 없으면 -1을 반환합니다.
아무 키나 입력을 하면 -1이 반환되지 않기 때문에
break가 되는 것입니다.

모든 코드가 실행되고 난 뒤에는 cap.release() 함수를 호출해
자원을 반납해야 합니다.

 

여기서 약간을 변형을 하여

if cv2.waitKey(1) != -1:    # 1ms 동안 키 입력 대기
    cv2.imwrite('shot.jpg', img) #보이는 이미지를 shot.jpg로 저장
    break                   # 아무 키라도 입력이 있으면 중지

cv2.imwrite('shot.jpg', img)를 추가해준다면
중지 전 보이는 이미지를 shot.jpg로 저장할 수 있습니다.

 

하나의 프레임을 이미지로 저장할 수 있는 것처럼,
cv2.VideoWriter() 함수를 쓰면
여러 프레임을 동영상으로 저장할 수도 있습니다.

import cv2

cap = cv2.VideoCapture(0)    # 0번 카메라 연결
if cap.isOpened:
    file_path = './record.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)
    size = (int(width), int(height))                        # 프레임 크기
    out = cv2.VideoWriter(file_path, fourcc, fps, size) # VideoWriter 객체 생성
    while True:
        ret, frame = cap.read()
        if ret:
            cv2.imshow('camera-recording',frame)
            out.write(frame)                        # 파일 저장
            if cv2.waitKey(int(1000/fps)) != -1:
                break
        else:
            print("no frame!")
            break
    out.release()                                   # 파일 닫기
else:
    print("can't open camera!")
cap.release()
cv2.destroyAllWindows()

 

cv2.VideoWriter(file_path, fourcc, fps, (width, height)) 에서
file_path는 동영상 파일을 저장할 경로,
fourcc는 동영상 인코딩 형식(codec 정보),
fps는 초당 저장될 프레임 수,
(width, height)는 프레임의 너비와 높이를 뜻합니다.
아래 코드를 실행한 뒤 아무 키나 누르면 키를 누르기 전까지
모든 프레임이 record.avi라는 동영상으로 저장됩니다.

 

cv2.VideoWriter() 객체를 생성하여 out 변수에 저장했습니다.

out.write(frame)을 호출하면 현재 frame이 저장됩니다.

cap.get()은 동영상이나 카메라의 속성을 확인하는 함수입니다.

cv2.CAP_PROP_FRAME_WIDTH는 프레임 너비,

cv2.CAP_PROP_FRAME_HEIGHT는 프레임 높이를 뜻합니다.

따라서 cap.get(cv2.CAP_PROP_FRAME_WIDTH)은 cap 객체의 프레임 너비를 반환합니다. 

참고로, FPS(Frames Per Second)는 초당 프레임 수를 뜻하며,

지연 시간은 FPS를 활용하여 구할 수 있습니다.

지연시간 = 1000 / fps

1000으로 계산하는 이유는 1초(1s)가 1,000밀리 초(1,000ms)이기 때문입니다. 따라서 코드에서 지연 시간을 cv2.waitKey(int(1000/fps))로 설정한 것입니다.