PC에 연결하는 웹캠은 여전히 USB 타입이 대부분이지만, 최근들어 보안감시 분야에서 네트워크 카메라가 많이 출시되고 있습니다. 네트워크 카메라들은 기존의 NTSC나 PAL을 출력하는 카메라들에 비해 추가로 필요한 장비가 거의 없고 이미 깔려있는 네트워크를 그대로 이용하면서도 로컬의 PC나 원격에서 스마트폰으로 영상을 볼 수 있는 장점이 있습니다. 그리고 요즘들어 검사 장비나 로봇의 시각으로 사용되던 고급 사양의 카메라 모듈들도 IEEE1394보다 Gigabit Ethernet을 더 많이 지원하는것같습니다.
어쨌거나 네트워크 카메라를 이용하면 USB 2.0의 대역폭 한계를 넘어서는 대용량의 HD급 영상을 속도 저하 없이 PC에서 받아볼 수도 있고 USB나 IEEE1394의 케이블 길이 문제도 극복할 수 있습니다. 여기서는 OpenCV 라이브러리의 비디오 캡쳐 함수를 이용해서 네트워크 카메라로부터 바로 이미지를 읽을 수 있는 방법에 대해 설명합니다. 제가 테스트한 네트워크 카메라는 보안 감시카메라로 사용되는 휴바이론 카메라 SK-N190XAI/R1 모델과 삼성테크윈 카메라 SNZ-5200 모델입니다.
먼저 카메라를 네트워크 허브에 연결하고 IP를 설정한 다음 웹 브라우저로 카메라에 연결하여 영상을 받을 수 있는지 확인합니다. 영상을 받는 방법은 카메라 제조사나 모델마다 제각각이기때문에 카메라의 메뉴얼을 참조해야 합니다. 카메라 구매시 제공하는 메뉴얼이면 대부분 웹브라우저에서 카메라 영상을 받는부분까지는 충분히 할 수 있습니다.
웹브라우저로 카메라 영상을 보는데 성공했다면, 다음으로 OpenCV 라이브러리로 시도해 볼 차례입니다. 저의 경우, 처음에는 HTTP 프로토콜로 읽으려고 다양한 시도를 했었는데 번번히 실패했고, 결국 RTSP 프로토콜로 읽는데 성공했습니다. 프로토콜에 대한 상세한 문서는 카메라 구매시 제공되지 않기때문에 카메라 제조사의 웹사이트에서 개발자 SDK와 관련 문서를 받거나 직접 기술지원팀에 연락하여 프로토콜에 대한 상세한 문서를 확보해야 합니다. 문서를 뒤져보면 RTSP 프로토콜로 카메라의 비디오 스트림을 읽어오는 방법, 카메라 설정 방법 등 상세한 내용들을 보실 수 있습니다.
다음은 예제 코드입니다. http://stackoverflow.com/questions/712998/opencv-with-network-cameras에서 받은 소스코드를 약간 수정한 소스입니다. videoStreamAddress에 네트워크 카메라의 IP와 아이디, 비밀번호, 비디오 스트림 주소 등을 설정하여 open() 함수로 열면 되는데, 카메라 세팅도 바꿔가면서 메뉴얼을 보고 이것저것 하다보면 되는 경우가 있습니다. 혹시 다른 종류의 네트워크 카메라를 OpenCV 라이브러리에서 읽기 성공 했다면 댓글로 방법 알려주시면 고맙겠습니다.
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <iostream>
using namespace cv;
using namespace std;
int main (int argc, char *argv[])
{
VideoCapture vcap;
Mat image;
string videoStreamAddress =
//"rtsp://192.168.0.108:554/mpeg4"; // 휴바이론 카메라 SK-N190XAI/R1
"rtsp://admin:4321@192.168.0.106:554/profile2/media.smp"; // 삼성테크윈 카메라 SNZ-5200
/* it may be an address of an mjpeg stream,
e.g. "http://user:pass@cam_address:8081/cgi/mjpg/mjpg.cgi?.mjpg" */
if (!vcap.open(videoStreamAddress)) {
cout << "Error opening video stream or file" << endl;
return -1;
}
for(;;) {
if(!vcap.read(image)) {
cout << "No frame" << endl;
waitKey();
}
imshow("Output Window", image);
if(waitKey(1) >= 0) break;
}
return 0;
}