ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • OpenCV VideoCapture class
    OpenCV/OpenCV_C++ 2023. 12. 13. 22:06

    OpenCV에서 카메라와 동영상으로부터 프레임(Frame)을 받아오는 작업을 VidepCapture class 하나로 처리할 수 있다.

    카메라와 동영상을 여는 작업이 수행되면, 매 프레임을 받아오는 작업을 수행한다.

     

    - 카메라 열기

    VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY);
    bool VideoCapture::open(int index, int apiPreference = CAP_ANY);
    • index: 사용할 캡쳐 장치의 ID (camera_id, domain_offset_id). 시스템 기본 카메라는 0으로 지정됨.(여러대의 카메라는 0부터 순서대로 지정)
    • apiPreference: 선호하는 카메라 처리 방법을 지정.
    • return: VideoCapture 생성자는 VideoCapture 객체를 반환. VideoCapture::open()함수는 작업이 성공하면 True, 실패하면 False를 반환.

     

    - 동영상 파일 열기

    VideoCapture::VideoCapture(const String& filename, int apiPreference = CAP_ANY);
    bool VideoCapture::open(const String& filename, int apiPreference = CAP_ANY);
    • filename: 동영상 파일 이름, 정지 영상 시퀀스, 비디오 스트림 URL 등을 받음.
    • apiPreference: 선호하는 동영상 처리 방법을 지정
    • return: VideoCapture 생성자는 VideoCapture 객체를 반환. VideoCapture::open()함수는 작업이 성공하면 True, 실패하면 False를 반환.

     

    - 현재 프레임 받아오기

    bool VideoCapture::read(OutputArray image);
    VideoCapture& VideoCapture::operator >> (Mat& image);
    • image: 현재 프레임. 만약 현재 프레임을 받지 못하면 빈 영상으로 설정.
    • return: VideoCapture::read()함수는 작업이 성공하면 True, 실패하면 False를 반환.
    • 참고: '>>' 연산자오버로딩은 내부에서 read() 함수를 재호출하는 래퍼(wrapper) 함수이다.

     

    그럼 직접 코드를 작성하며 살펴보자.

    #include <iostream>
    #include "opencv2/opencv.hpp"
    
    int main() {
    	cv::VideoCapture cap;
    	cap.open(0);
    	// 혹은 아래와 같이 사용 가능
    	// cv::VideoCapture cap(0);
        
    	// 동영상 처리시 아래와 같이 사용
    	// cv::VideoCapture cap;
    	// cap.open("동영상 경로");
    
    	// 카메라를 열지 못한 경우 아래의 오류를 출력하고 프로그램 종료.
    	if (!cap.isOpened()) {
    		std::cerr << "Camera open failed!" << std::endl;
    		return -1;
    	}
    
    	int w = cvRound(cap.get(cv::CAP_PROP_FRAME_WIDTH)); // 영상의 Width 출력
    	int h = cvRound(cap.get(cv::CAP_PROP_FRAME_HEIGHT)); // 영상의 Height 출력
    
    	std::cout << "width: " << w << std::endl;
    	std::cout << "height: " << h << std::endl;
    
    	cv::Mat frame, edge;
    	while (true) {
    		cap >> frame; // VideoCapture 객체로부터 한 프레임을 받아 frame 변수에 저장.
    
    		// 영상을 제대로 받지 않으면 Empty frame을 출력하고 while문 탈출
    		if (frame.empty()) {
    			std::cerr << "Empty frame!" << std::endl;
    			break;
    		}
    
    		Canny(frame, edge, 50, 150); // 50 ~ 150의 threshold를 갖는 Canny 이미지를 edge에 담음.
    		imshow("frame", frame);
    		imshow("edge", edge);
    
    		// waitKey(1)은 1ms동안 wait
    		if (cv::waitKey(1) == 27) // ESC를 누르면 while문 탈출
    			break;
    	}
    
    	cap.release();
    	cv::destroyAllWindows();
    	return 0;
    }

    결과

    귀여운 인형과 인형의 Edge

    여기서 FPS라는 용어가 나오는데 FPS는 Frame Per Second의 약자이다.

    FPS는 1초에 몇장의 Frame을 받아올 수 있는지 알려준다.

    만약 1초를 1000ms로 나타내고 1초에 30장을 처리한다고 하면 1장당 약 33ms를 처리한다.

     

    - 카메라와 동영상 속성 값 참조와 설정

    double VideoCapture::get(int propId) const;
    bool VideoCapture::set(int propId, double value);
    • value: 속성 값. 필요한 경우 정수형으로 형변환하여 사용이 가능하다.
    • propId: 속성 플래그(cv::VideoCaptureProperties or Additional flags for video I/O API backends의 상수에서 선택가능)
    cv::VideoCaptureProperties 설명
    CAP_PROP_FRAME_WIDTH 프레임 가로 크기
    CAP_PROP_FRAME_HEIGHT 프레임 세로 크기
    CAP_PROP_FPS 초당 프레임 수
    CAP_PROP_FRAME_COUNT 비디오 파일의 총 프레임 수
    CAP_PROP_POS_FRAMES 현재 프레임 번호
    CAP_PROP_EXPOSURE 노출
    기타등등 기타등등

    이 명령어들로 내 현재 영상의 값을 받거나 해상도의 경우 정의를 해줄 수 있다.

        cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
        cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);

    바뀐 해상도

     

    - VideoWriter

    동영상 파일로 저장할 수 있는 VideoWriter class가 있다.

    VideoWriter::VideoWriter(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
    bool VideoWriter::open(const String& filename, int fourcc, double fps, Size frameSize, bool isColor = true);
    • filename: 저장할 동영상 파일 이름
    • fourcc: 압축 방식을 나타내는 4개의 문자. VideoWriter::fourcc() 함수로 생성. (https://fourcc.org/codecs.php)
    VideoWriter::fourcc('D', 'I', 'V', 'X') DIVX MPEG-4 코덱
    VideoWriter::fourcc('X', 'V'. 'I'. 'D') XVID MPEG-4 코덱
    VideoWriter::fourcc('X', '2', '6', '4') H.264/AVC 코덱
    VideoWriter::fourcc('M', 'J', 'P', 'G') Motion-JPEG 코덱
    • fps: 초당 프레임 수
    • frameSize: 비디오 프레임 크기
    • isColor: 컬러 동영상 플래그. false로 지정하면 그레이스케일.

    한번 edge영상을 저장하는 코드를 간단히 작성해보자.

    #include <iostream>
    #include "opencv2/opencv.hpp"
    
    int main()
    {
    	cv::VideoCapture cap(0);
    
    	if (!cap.isOpened()) {
    		std::cerr << "Camera open failed!" << std::endl;
    		return -1;
    	}
    	
    	int  fourcc = cv::VideoWriter::fourcc('X', 'V', 'I', 'D'); // XVID MPEG-4 코덱사용
    	double fps = 30;
    	cv::Size sz((int)cap.get(cv::CAP_PROP_FRAME_WIDTH), (int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    	std::cout << "FPS = " << fps << std::endl;
    	std::cout << "Size = " << sz << std::endl;
    
    	cv::VideoWriter output("output.avi", fourcc, fps, sz); // 저장파일명 및 설정
    
    	if (!output.isOpened()) {
    		std::cerr << "output.avi open failed!" << std::endl;
    		return -1;
    	}
    
    	int delay = cvRound(1000 / fps);
    	cv::Mat frame, edge;
    	while (true) {
    		cap >> frame;
    		if (frame.empty())
    			break;
    
    		Canny(frame, edge, 50, 150);
    		cvtColor(edge, edge, cv::COLOR_GRAY2BGR); // edge영상은 grayscale 이므로 bgr로 변환이 필요.
    
    		output << edge;
    
    		imshow("edge", edge);
    
    		if (cv::waitKey(delay) == 27)
    			break;
    	}
    
    	std::cout << "output.avi file is created!!!" << std::endl;
    
    	output.release();
    	cap.release();
    	cv::destroyAllWindows();
    	return 0;
    }

    결과

    생성된 영상파일

    다음과 같이 영상이 생성됨을 볼 수 있다.

    'OpenCV > OpenCV_C++' 카테고리의 다른 글

    OpenCV 유용한 함수  (2) 2023.12.21
    OpenCV Draw & Event  (0) 2023.12.14
    OpenCV Mat class 기초 사용법  (0) 2023.12.12
    OpenCV 주요 클래스  (1) 2023.11.27
    OpenCV 기초 및 편하게 사용하기  (2) 2023.11.26
Designed by Tistory.