# 동영상 압축

# 핵심 강의

동영상 준비 중

# 강의 개요

화상채팅의 중요 모듈 중 하나인 화상 압축 모듈에 대한 사용법을 알아봅니다. 이 강의에서는 화상 압축의 구체적인 원리를 다루지 않고 이미 만들어진 라이브러리를 사용하는 방법에 집중합니다.

# 강의 전 준비 사항

# 이 강의에서 다룰 내용

  • CameraList: PC 카메라 목록 가져오기
  • VideoCapture: PC 카메라에서 동영상 캡쳐
  • VideoZip: 동영상 압축
  • WindowSDL: SDL2를 이용하여 이미지를 화면에 표시
  • VideoUnZip: 동영상 압축 해제

# CameraList

PC에 설치되어 있는 카메라의 목록을 가져오는 클래스입니다. 이 강의에서는 사용하지 않지만 최종 마무리에서 사용할 클래스이기 때문에 살펴보고 넘어가도록 하겠습니다.

# Class 구조

class CameraList
{
public:
	/** 카메라 목록을 갱신합니다.
	*/
	void update()

	/** 찾아낸 카메라의 개수 */
	int size()

	/** 카메라의 이름을 가져옵니다.
	@param index 가져올 카메라의 순번 (순번은 0부터 시작함)
	*/
	string getName(int index)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 사용방법

#include <iostream>
#include <ryulib/CameraList.hpp>

int main()
{
	CameraList cameralist;
	cameralist.update();
	for (int i = 0; i < cameralist.size(); i++) {
		printf("%d: %s", i, cameralist.getName(i).c_str());
	}

	return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
  • 6: 카메라 목록을 가져올 CameraList 객체를 생성합니다.
  • 7: 카메라 목록을 업데이트합니다. 만약 update() 메소드 사용 이후 카메라를 PC에 연결하거나 제거하였다면, update() 메소드를 다시 실행해야 합니다.
  • 8-10: 카메라 목록의 갯수만큼 반복하면서 각 카메라의 이름을 표시해줍니다.

# 실행결과

# VideoCapture

OpenCV에서 제공하는 클래스입니다. 카메라로 부터 이미지를 캡쳐해서 가져올 수 있습니다.

# class 구조

아래 링크를 참고하시기 바랍니다.

# 사용방법

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;

int main(int argc, char* args[])
{
	int width  = 640;
	int height = 480;

	VideoCapture cap;
	cap.set(CAP_PROP_CONVERT_RGB, true);
	cap.set(CAP_PROP_FRAME_WIDTH, width);
	cap.set(CAP_PROP_FRAME_HEIGHT, height);
	cap.open(0);
	if (cap.isOpened() == false) {
		printf("error! \n");
		return 0;
	}

	Mat image;
	while (true) {
		cap.read(image);
		imshow("Camera View", image);
	}

	return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • 8-9: 카메라로부터 가져올 영상의 크기를 지정합니다.
  • 11: 영상을 캡쳐하기 위해서 VideoCapture 객체를 생성합니다.
  • 12: RGB 이미지를 사용하도록 설정합니다.
  • 13-14: 영상의 크기를 설정합니다.
  • 15: 기본 카메라로 설정된 카메라로부터 영상 캡처를 시작합니다.
  • 16-19: 카메라를 오픈하는데 실패하였다면 에러 메시지를 표시하고 프로그램을 종료합니다.
  • 21: 카메라 영상을 저장할 객체를 생성합니다. (https://docs.opencv.org/4.1.2/d3/d63/classcv_1_1Mat.html (opens new window) 참고)
  • 22-25: 무한히 반복합니다.
    • 23: 카메라에서 이미지를 가져옵니다.
    • 24: 가져온 이미지를 화면에 표시해줍니다.

# 실행결과

수염 때문에 모자이크 처리

# VideoZip

VideoZip는 VP8 코덱을 이용하여 영상을 압축하는 클래스입니다.

# Class 구조

class VideoZip {
public:
	/** 비디오 인코더를 준비시킵니다.
	@param width 인코딩 할 영상의 넓이 (가로 크기)
	@param height 인코딩 할 영상의 높이 (세로 크기)
	@return 인코딩 준비 중 에러가 없으면 true가 리턴됩니다.
	*/
	bool open(int width, int height)

	/** 인코더 사용을 중단합니다. */
	void close()

	/** 영상을 인코딩 합니다.
	@param bitmap 인코딩 할 BITMAP 데이터
	@param depth 인코딩 할 BITMAP의 색상수 (비트단위, 현재는 24비트만 가능)
	@return 인코딩 중 에러가 없으면 true가 리턴됩니다.
	*/
	bool encode(void* bitmap, int depth)

	/** 인코딩 결과 데이터 */
	void* getData()

	/** 인코딩 결과 데이터의 크기 */
	int getSize()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 사용방법

#include <iostream>
#include <opencv2/opencv.hpp>
#include <ryulib/VideoZip.hpp>

using namespace cv;

int main(int argc, char* args[])
{
	int width  = 640;
	int height = 480;

	VideoCapture cap;
	cap.set(CAP_PROP_CONVERT_RGB, true);
	cap.set(CAP_PROP_FRAME_WIDTH, width);
	cap.set(CAP_PROP_FRAME_HEIGHT, height);
	cap.open(0);
	if (cap.isOpened() == false) {
		printf("error! \n");
		return 0;
	}

	width  = cap.get(CAP_PROP_FRAME_WIDTH);
	height = cap.get(CAP_PROP_FRAME_HEIGHT);

	VideoZip video_zip;
	video_zip.open(width, height);

	Mat image;
	while (true) {
		cap.read(image);
		imshow("Camera View", image);

		if (video_zip.encode(image.data, 24)) printf("encode: %d \n", video_zip.getSize());
	}

	return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  • 25: 영상을 압축할 VideoZip 객체를 생성합니다.
  • 26: VideoZip.open() 메소드로 지정된 크기의 영상 압축을 준비합니다.
  • 33: VideoZip.encoder() 메소드로 이미지를 압축합니다.
    • 24는 24비트 컬러를 의미합니다.
    • 압축된 데이터의 크기를 콘솔화면에 표시합니다.

# 실행결과

VideoCapture 결과화면과 거의 같으나 콘솔창에 압축된 데이터의 크기가 계속 표시됩니다.

# WindowSDL

WindowSDL은 SDL2를 이용해서 화면에 영상을 표시하는 클래스입니다. 에제를 단순하게 보이기 위해서 SDL2를 다루는 구체적인 내용을 캡슐화하였습니다.

# Class 구조

class WindowSDL {
public:
	/** 영상을 출력하기 위한 윈도우를 생성(오픈)합니다.
	@param caption 윈도우의 제목
	@param width 윈도우의 넓이 (가로 크기)
	@param height 윈도우의 높이 (세로 크기)
	*/
	bool open(string caption, int width, int height)

	/** 윈도우를 닫습니다. */
	void close()

	/** 32비트 BITMAP을 윈도우에 표시합니다.
	@param bitmap 표시할 BITMAP 데이터
	*/
	void showBitmap32(void* bitmap)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# VideoUnZip

VideoUnZip는 VideoZip을 이용해서 압축된 영상 데이터를 압축 해제하는 클래스입니다.

# Class 구조

class VideoUnZip {
public:
	/** 비디오 디코더를 준비시킵니다.
	@param width 디코딩 할 영상의 넓이 (가로 크기)
	@param height 디코딩 할 영상의 높이 (세로 크기)
	@return 디코딩 준비 중 에러가 없으면 true가 리턴됩니다.
	*/
	bool open(int width, int height)

	/** 디코더를 초기화 시킵니다. 화상 채팅 중 상대가 접속이 끊겨서 다시 입장한 경우 등에 활용할 수 있습니다. */
	void refresh()

	/** 디코더 사용을 중단합니다. */
	void close()

	/** 영상을 디코딩 합니다.
	@param bitmap 디코딩 할 데이터
	@param size 디코딩 할 데이터의 크기
	@return 디코딩 중 에러가 없으면 true가 리턴됩니다.
	*/
	bool decode(void* data, int size)

	/** 디코딩이 완료된 BITMAP의 데이터 */
	void* getBitmap() { return bitmap_; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 사용방법

#include <iostream>
#include <opencv2/opencv.hpp>
#include <ryulib/VideoZip.hpp>
#include <ryulib/VideoUnZip.hpp>
#include <ryulib/sdl_window.hpp>

using namespace cv;

int main(int argc, char* args[])
{
	int width  = 640;
	int height = 480;

	VideoCapture cap;
	cap.set(CAP_PROP_CONVERT_RGB, true);
	cap.set(CAP_PROP_FRAME_WIDTH, width);
	cap.set(CAP_PROP_FRAME_HEIGHT, height);
	cap.open(0);
	if (cap.isOpened() == false) {
		printf("error! \n");
		return 0;
	}

	width  = cap.get(CAP_PROP_FRAME_WIDTH);
	height = cap.get(CAP_PROP_FRAME_HEIGHT);

	VideoZip video_zip;
	video_zip.open(width, height);

	VideoUnZip video_unzip;
	video_unzip.open(width, height);

	WindowSDL window;
	window.open("VideoZip test", width, height);

	Mat image;
	while (true) {
		cap.read(image);

		if (video_zip.encode(image.data, 24)) {
			printf("encode: %d \n", video_zip.getSize());

			if (video_unzip.decode(video_zip.getData(), video_zip.getSize())) {
				window.showBitmap32(video_unzip.getBitmap());
			}
		}
	}

	return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  • 30: 영상 압축 해제를 할 수 있는 VideoUnZip 객체를 생성합니다.
  • 31: VideoUnZip.open() 메소드로 지정된 화면 크기의 영상 압축 해제를 준비합니다.
  • 33: 압축 해제된 BITMAP 이미지를 표시하기 위해서 SDL 윈도우를 사용할 수 있는 WindowSDL 객체를 생성합니다.
  • 34: WindowSDL.open() 메소드로 지정된 크기의 윈도우 화면을 표시합니다.
  • 43: VideoUnZip.decode() 메소드로 압출된 데이터를 다시 압축해제하고 WindowSDL 객체를 이용해서 화면에 표시합니다.

# 실행결과

수염을 가리고 찰칵!