[OpenCV C++] 웹캠 크롭하기
최근 손가락 검출 및 이벤트 맵핑 프로젝트를 진행했었는데 그 일부분을 정리해 하나씩 올려보고자 한다.
아래 코드는 피부색을 검출하기 전 단계로 피부색 검출 시 얼굴과 손이 동시에 검출되는 것을 막기 위해 ROI(Region Of Interest | 관심 영역)로 설정한 부분을 따로 크롭하여 분리한다.
이 방법은 쉽고 단순한 방법이며, Feature 기반 API를 활용하지 않고 사용할 수 있는 방법이다.
전체 코드는 맨 아래에 기술해두었다.
Mat frame, crop; //frame : 웹캠 프레임, crop : 웹캠 프레임에서 크롭된 이미지
VideoCapture cap; //웹캠
int deviceID = 0; //디폴트 카메라
int apiID = CAP_ANY; //디폴트 API
cap.open(deviceID, apiID); //웹캠 열기
//웹캠 오류 확인
if (!cap.isOpened()) {
cerr << "ERROR! Unable to open the camera\n";
return -1;
}
우선 VideoCapture 객체를 선언한다.
open함수의 첫번째 인자로 0을 넣게 되면 디폴트로 설정된 카메라를 사용하게 된다.
VideoCapture는 웹캠뿐 아니라 비디오 파일도 불러올 수 있다.
VideoCapture cap("비디오파일.mp4") 으로 입력하면 exe파일 실행 시 같은 폴더 내에 보관된 지정된 이름의 비디오 파일을 불러오게 된다.(mp4는 예시이다)
main함수 인자로 argc, argv를 입력하고 비디오파일 이름 대신 argv[1]을 넣게 되면 cmd창에 두 번째 인자로 입력한 비디오 파일을 불러온다. cmd창의 두 번째 인자를 경로와 함께 입력하면 꼭 exe파일과 같은 폴더 내에 있지 않아도 불러올 수 있다.
if문은 웹캠이 열리지 않았을 경우 예외처리를 해주는 부분인데, 예외처리를 해주는 편이 좋다.
Rect rect(350, 100, 200, 200); //크롭 영역
//웹캠 출력
for (;;) {
cap.read(frame);
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
//좌우반전
flip(frame, frame, 1);
//영상 크롭
crop = frame(rect);
//크롭되는 영역 표시
rectangle(frame, Point(350, 100), Point(550, 300), CV_RGB(255, 0, 0));
imshow("Live", frame);
imshow("crop", crop);
//아무 키나 누르면 종료
if (waitKey(5) >= 0) {
break;
}
}
웹캠을 포함해서 모든 비디오는 낱개의 이미지가 초당 몇장씩 연결해 보여주는 것으로 이해하면 된다.
for(;;) 또는 while(1)문으로 무한 루프를 돌리는 이유가 이 때문이다.
화면은 웹캠을 통해 받은 이미지를 Mat 변수에 따로 저장하여 imshow로 보여주면 된다.
역시 프레임을 받지 못했을 경우를 예외처리 해준다.
웹캠을 그냥 켜게 되면 좌우가 반대로 보이는데, 이 부분이 불편하니 우리가 일반적으로 거울을 보는 것처럼 보기 위해 좌우반전을 해준다.
Rect객체는 인자로
(왼쪽 위 x포인트, 왼쪽 위 y포인트, 사각형 가로 크기, 사각형 세로 크기)
이렇게 넣어주면 된다.
rectangle 함수는 ROI 영역을 명시적으로 보여주기 위해 그려준다. 이 영역 안에 손을 올리면 된다.
아무 키나 누르면 무한루프를 빠져나오도록 구현했다.
전체 코드
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
Mat frame, crop; //frame : 웹캠 프레임, crop : 웹캠 프레임에서 크롭된 프레임
VideoCapture cap; //웹캠
Rect rect(350, 100, 200, 200); //크롭 영역
int deviceID = 0; //디폴트 카메라
int apiID = CAP_ANY; //디폴트 API
//웹캠 열기
cap.open(deviceID, apiID);
namedWindow("Live");
namedWindow("crop");
//웹캠 오류 확인
if (!cap.isOpened()) {
cerr << "ERROR! Unable to open the camera\n";
return -1;
}
//웹캠 출력
for (;;) {
cap.read(frame);
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
//좌우반전
flip(frame, frame, 1);
//영상 크롭
crop = frame(rect);
//크롭되는 영역 표시
rectangle(frame, Point(350, 100), Point(550, 300), CV_RGB(255, 0, 0));
imshow("Live", frame);
imshow("crop", crop);
//아무 키나 누르면 종료
if (waitKey(5) >= 0) {
break;
}
}
return 0;
}
혹시나 틀린 부분이 있다면 지적 환영합니다:)
응원 댓글은 작성자에게 큰 힘이 됩니다!