Programming/IoT_Embedded

라즈베리파이 카메라 OpenCV

이세우 2017. 11. 17. 17:25

라즈베리파이에 OpenCV를 설치하고 나면 카메라로 부터 이미지를 얻고 싶을 텐데요.
라즈베리파이에 카메라를 연결해서 OpenCV를 프로그래밍 하는 방법을 알아 보려고 해요.

라즈베리파이에 카메라를 연결 할 수 있는 방법은 2가지 입니다.

1. 라즈파이 카메라를 CSI 포트에 연결해서 사용
2. 웹 캠을 USB에 연결해서 사용

위 2가지 방법 각각은 물론  모두 사용하는 것도 가능합니다.

USB 웹캠

USB 타입의 웹캠은 무얼 사야하나 고민이 될텐데요, “UVC(USB video device class)”를 지원하는 웹캠이면 아무것이나 잘 인식이 됩니다.(https://en.wikipedia.org/wiki/USB_video_device_class)
보통 오픈마켓에서 웹캠을 검색하면 대부분 UVC 지원이라고 써 있습니다.

웹 캠을 USB에 연결하고 아래 명령으로 연결 여부를 확인 할 수 있습니다.
dmesg



lsusb



연결이 제대로 되었다면 아래의 명령어로 연결된 장치를 확인합니다.

ls /dev/video*



보통 연결된 순서대로 /dev/video0, /dev/video1 … 로 증가합니다.

라즈파이 카메라

라즈파이 카메라는 라즈베리파이 전용으로 나온 카메라입니다.
라즈베리파이 CSI(Camera Interface) 포트에 끼우는 형식으로 되어 있습니다.



카메라를 끼우고 나서 raspi-config로 들어가서 카메라 장치를 활성화 시켜 줍니다.

sudo raspi-config




라즈파이 카메라가 제대로 연결되었는지 확인 하는 가장 좋은 방법은 사진을 찍어 보는 겁니다.

raspistill -o pic.jpg

위 명령어를 실행하면 5초 후에 사진을 찍어서 지정한 이름으로 저장합니다.

라즈파이 카메라는 USB 웹캠과는 다르게 연결이 되어서 사진이 잘 찍혀도 OpenCV 라이브러리로 접근할 수 없는데요,
USB 타입이 아니라서 연결과 동시에 장치 인식이 안되고, MMAL(Multimedia Abstract Layer)라는 라이브러를 사용하여 장치를 제어하는데, 라즈베리파이 보드를 만들때 사용하는 BroadCom BCM2835 SoC의 전용 라이브러리인 VideoCore 기반이라서 리눅스의 표준으로 사용하는 V4L2와는 다르게 동작하기 때문입니다.

따라서 라즈파이 카메라를 연결한 후에 v4l2 장치 드라이버를 커널에 로드해서 /dev/video0 장치로 인식시켜야 OpenCV와 같은 라이브러리에서 접근이 가능합니다.
아래 명령어로 간단히 로딩이 가능합니다.

sudo modprobe bcm2835-v4l2

그 다음 다시 video 장치를 확인하면 장치가 인식 됩니다.

ls /dev/video*

이와 같은 작업은 리부팅 할때 마다 해줘야 하는 것이라서 불편 한데요, 부팅 되는 시점에 자동으로 장치 드라이버를 로드하게 하려면 "/etc/modules” 파일에 해당 드라이버 이름을 적어 놓으면 자동으로 부팅 되는 시점에 로딩됩니다.

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

i2c-dev
bcm2835-v4l2
원래 있던 파일 마지막 라인에 추가해 놓습니다.

OpenCV Video 코딩

OpenCV에서 Video 장치에서 이미지를 가져와서 표시하는 코드는 아래와 같습니다. 
아래 코드에서 cv2.VideoCapture() 함수에 전달하는 숫자가 카메라 번호로 /dev/video0, /dev/video1 에서의 숫자입니다.
접근하고자 하는 카메라 번호를 적절히 넣어 주면 됩니다.

import cv2
cap = cv2.VideoCapture(0) #0 or -1
while cap.isOpened():
    ret, img = cap.read()
    if ret:
        cv2.imshow('camera-0', img)
        if cv2.waitKey(1) & 0xFF == 27: #esc
            break
    else:
        print('no camera!')
        break
cap.release()
cv2.destroyAllWindows()