지난번에는 visual studio에서 설정하는 것만 확인했다.

[OpenCV]OpenCV란 무엇인가? 그리고 설치

 

[OpenCV]OpenCV란 무엇인가? 그리고 설치

1. OpenCV OpenCV는 Open Source Computer Vision의 약자로 영상 처리에 사용할 수 있는 오픈 소스 라이브러리 입니다. 컴퓨터가 사람의 눈처럼 인식할 수 있게 처리해주는 역할을 하기도 하며, 우리가 많이

studium-anywhere.tistory.com

이러한 방식은 간단하게 설정하고 하나의 프로젝트에서 써먹기 좋다. 하지만 여러 프로젝트를 진행해야 하는 상황이라면 지속적으로 lib를 복사해야 하는 귀찮음이 있을 수 있다. (물론 위에서 제시한 방법도 진행해보고 환경변수 설정을 활용한 방법도 진행해봄으로써 실제 상용 프로그램을 만들 때 필요한 프로그램이 무엇인가를 아는 것도 중요하다.)

 


시스템 환경변수 설정

  컴퓨터 시스템은 스스로 할 수 있는 일이 별로 없다. 그래서 우리가 하나하나 알려줘야 한다. "어? 지금까지는 컴퓨터가 알아서 해줬는데요?" 그것은 다른 프로그래머가 하나하나 설정해준 것이므로 이제 우리도 하나하나 할 때가 되었다. 

  무언가를 시작할 때, 어디에 있는지 알아야 시작하지 않겠는가? 그것이 바로 환경 변수이다. 이름이 환경변수인 이유는 영어를 직역해서 그렇다. (Environment variable)

 

윈도우10 기준으로 제어판 -> 시스템으로 들어가자.

그곳에서 시스템 정보를 클릭

 

이렇게 생긴 모습이 나올 것이며, 거기서 고급 시스템 설정을 눌러주자.

 

딱 대놓고 환경 변수라고 나와있다.

 

  하나의 계정에다가만 만들 것이 아니라 시스템 자체에 추가하려고 하니 '시스템 변수'에다가 추가하도록 하겠다. (위, 아래 칸 두 개가 있다고 당황하지 말자, 위에는 특정 사용자에 해당하는 변수 설정이며, 아래에는 시스템 전체에 해당하는 변수이다. 위에다가 해도 상관없지만, 윈도우 계정 로그아웃 시 환경변수 설정을 다시 해야 한다.)  새로 만들기를 눌러준다.

 

앞으로의 세 개를 연달아 입력해준다. 다만 필자는 C에다가 압축해제를 해두었으므로 C:\opencv를 놓은 것이니 만약에 D라면 D:\opencv로 진행하도록 하자. 혹은 폴더에 두는 사람도 있는데 

D:\opencv\opencv의 형태가 있을 수도 있다. 본인의 상황에 맞는 것으로 하자.

 

필자의 상황은 이러하다. C:\opencv 가 바로 있다.

각각의 변수에다가 폴더의 경로를 저장해주는 형태이다. 

 


그 다음으로 시스템 변수 - path를 더블 클릭하자.

 

그리고서 아까 저장한 OPENCV_DIR 를 아래 처럼 입력해도록 하자. 

아까 우리는 OPENCV_DIR = C:\opencv를 저장해두었으니, 아래에 경로명에는 

C:\opencv\build\x64\vc15\bin 의 경로가 생성되는 것이다.

우리는 컴퓨터에게 친절하게 알려줄 필요가 있다. 엄마! 내 OO 어딨어!?

 

확인을 누르고 나면 기본적인 환경설정은 마무리가 되었다.

 

이제 제대로 설정이 되었는가를 확인하기 위해 CMD (명령 프롬프트)를 켜도록 하자. 윈도우 10이라면 아래에 검색에서 cmd라고 치면 나온다.

 

제대로 설치가 되었다면 버전이 나온다. 그렇지 않다면 찾을 수 없다는 메시지가 나올 것이다.

 


Visual Studio 설정하기

프로젝트 -> [프로젝트 이름] 의 속성으로 가보자

*필자는 프로젝트 이름을 opencv_project라 지은 것이다.

 


1. 

창이 열리고 나면, C/C++ → 일반 탭에서 

추가 포함 디렉터리에다가 $(OPENCV_INC)

아까 시스템 변수에 저장된 값을 지정해주도록 해야 합니다.

 

 

2. 

그 다음으로 링커 → 일반에서 추가 라이브러리 디렉터리에

$(OPENCV_LIB)

를 입력하도록 합니다. 이 변수도 위에서 시스템 변수에서 적용한 값이죠.

 

3. 마지막으로 링커 → 입력에서 추가 종속성을 입력해주도록 합니다.

 

추가 종속성

lib를 연결해주는 역할을 합니다. 여기서 주의하실 점은 opencv의 버전에 따라 이름이 조금씩 다릅니다.

C:\opencv\build\x64\vc15\lib

저의 설치 경로는 이렇게 설치했으며, 직접 가셔서 확인해보는 것이 가장 좋습니다.

두 개가 있으며, d가 붙은 버전과 아닌 버전이 있는데, d가 붙어있으면 debug이며, 안 붙어있는 lib는 release 모드에서 사용됩니다. 둘 다 입력해주도록 합니다.

 

이렇게 확인을 누르면 완료가 됩니다.

 

 

지난 시간에는 이미지의 출력을 간단한 예제와 함께 살펴보았다. 이번에는 입력 받아둔 이미지를 간단한 변환인 가우시안블러를 적용해보도록 하자.

 

1. 가우시안 블러 GaussianBlur()


가우시안 블러는 이미지를 부드럽게 만들어주는 필터 같은 것이다. 가우시안이나 이와 비슷한 커널을 활용해서 이미지에 담긴 정보량을 줄여준다. 이미지 처리에서는 너무 많은 정보로 인해 오히려 정보 사이의 유의미한 연결 고리를 찾기 어려울 수 있으므로 가우시안 블러를 통해 줄여주는 것이다.

 

결과부터 먼저 살펴보자.

왼쪽이 가우시안블러가 적용된 이미지, 오른쪽이 원본이미지이다. 뿌옇게 변한 것이 가우시안 블러이다. 

 

실습을 바로 해보도록 하자.

#include <opencv2/opencv.hpp>			// 헤더 파일을 가볍게 만들기 위해 교체!

using namespace cv;

int main(int argc, char** argv) {
	Mat img = imread("cat.png");
	Mat blurredImg;						//가우시안 처리가 된 이미지를 담을 변수

	if (img.empty()) 
		return -1;

	namedWindow("img", WINDOW_AUTOSIZE);		// 입력 결과를 넣을 윈도우 만들기
	namedWindow("blurredImg", WINDOW_AUTOSIZE);	// 출력 결과를 넣을 윈도우 만들기

	imshow("img", img);		

	GaussianBlur(img, blurredImg, Size(5, 5), 3,  3);
	GaussianBlur(blurredImg, blurredImg, Size(5, 5), 3, 3);

	imshow("blurredImg", blurredImg);

	waitKey(0);

	
}

지난 시간에 적용했던 코드를 활용하고 있다.

 

Mat img = imread("cat.png");

Mat blurredImg;

입력에는 img 변수를 사용하고 있으며, 출력에는 blurredImg를 선언해서 넣어주려고 한다. 여기서는 OpenCV가 자동으로 가우시안블러를 적용함으로써 줄어든 메모리를 자동으로 할당하고 메모리 크기를 조정해준다는 점이다. (간단히 우리를 편리하게 자동으로 조정/재할당 해준다.)

 

namedWindow("img", WINDOWnamedWindow("img", WINDOW_AUTOSIZE); 
namedWindow("blurredImg", WINDOW_AUTOSIZE); 

입력과 출력 결과를 넣을 윈도우를 먼저 만들어줘야 한다. 우리의 눈에 비교가 되야 어떤 부분이 달라진지 알 수 있지 않겠는가? 그래서 두 개의 윈도우 창을 만들어 준다. 

imshow("img", img);

먼저, 가우시안블러를 적용하기 전이므로 원본 이미지를 출력해준다.


GaussianBlur(img, blurredImg, Size(5, 5), 3,  3);
GaussianBlur(blurredImg, blurredImg, Size(5, 5), 3, 3);

그 다음으로 가우시안 블러를 적용해준다. 여기서는 두 번 연속으로 가우시안블러를 적용하고 있다. 1번만 해도 상관없지만 조금 더 들여다 보기 위해 2번의 가우시안 블러를 적용해보았다. 2번 째 중복된 가우시안 블러 호출은 자기 자신이 입력과 출력으로 사용되는 위에서 이야기했듯이, Mat 구조체에 해당하는 메모리가 자동으로 조정/재할당을 함으로써 메모리 사용을 최적화해준다. (아주 편리하다! 감사합니다 개발자님들)


imshow("blurredImg", blurredImg);
가우시안 블러가 완료된 것을 윈도우에 출력해준다. 


waitKey(0);

사용자 입력을 대기함으로써 마무리가 된다.

 


GaussianBlur(img, blurredImg, Size(5, 5), 3,  3);
GaussianBlur(blurredImg, blurredImg, Size(5, 5), 3, 3);

 

우리는 이 부분을 조금 더 살펴보기 위해서 코드를 조금 조정할 필요가 있다.

 

일단 코드는 이렇다.

#include <opencv2/opencv.hpp>			// 헤더 파일을 가볍게 만들기 위해 교체!

using namespace cv;

int main(int argc, char** argv) {
	Mat img = imread("cat.png");
	Mat blurredImg1, blurredImg2;						//가우시안 처리가 된 이미지를 담을 변수

	if (img.empty()) 
		return -1;

	namedWindow("img", WINDOW_AUTOSIZE);		// 입력 결과를 넣을 윈도우 만들기
	namedWindow("blurredImg1", WINDOW_AUTOSIZE);	//중간 결과를 넣을 윈도우 만들기
	namedWindow("blurredImg2", WINDOW_AUTOSIZE);	// 마지막 결과를 넣을 윈도우 만들기

	imshow("img", img);		

	GaussianBlur(img, blurredImg1, Size(5, 5), 3,  3);
	GaussianBlur(blurredImg1, blurredImg2, Size(5, 5), 3, 3);

	imshow("blurredImg1", blurredImg1);
	imshow("blurredImg2", blurredImg2);

	waitKey(0);

	
}

중간 과정을 넣을 

namedWindow("blurredImg1", WINDOW_AUTOSIZE); 를 추가했으며, 

 

imshow("blurredImg1", blurredImg1);
imshow("blurredImg2", blurredImg2);

 

확인할 수 있는 코드를 두 개 정도 더 추가해서 변화 과정을 관찰하고자 하였다.

 

다음과 같이 블러가 점진적으로 진행됨을 확인할 수 있다.

 

그렇다면 가우시안 블러의 함수 원형을 살펴보도록 하자.

 

기본 원형은

void cv::GaussianBlur( InoutArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT)

로 이루어져 있다. src는 원본 소스, dst는 출력할 소스를 의미한다. Size는 가우시안 블러를 어떤 범위로 처리할 것인지에 대한 이야기를 하고 있다. 여기서는 5×5 형태로 만들어주고 있으며, 값에 따른 결과는 한번 확인해보도록 하자.(다만 영역의 중심 픽셀에서부터 처리되므로 홀수로 처리해야 한다.)

 

가우스안블러는 수학에서 사용되는 수식을 활용하는데, 정확한 수학적 근거를 보고 싶은 사람은 이곳을 방문하자. 수학적인 해석은 차후 시간이 되면 다루도록 하겠다.

 

* 수식을 풀어서 간단히 요약해서 말하자면 사각형의 범위를 두고 그 범위에 해당하는 수치의 적당한 값으로 수치를 변경해버리는 것이다.

정확한 계산은 아니지만 이런 느낌으로 만들어버리는 것이다. 


여기서 추가로 다운 샘플링 등과 같은 복잡한 형태의 이미지 변환도 존재한다. 이는 나중에 다루도록 하겠다.

 

출처

Computer Vision: Algorithms and Applications, 2nd ed, 2021 Richard Szeliski , szeliski.org/Book/ 

docs.opencv.org/2.4/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html

docs.opencv.org/4.5.1/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1

 

1. 라이브러리들

OpenCV에는 다양한 라이브러리와 모듈이 존재한다. 어떤 모듈이 존재하는지는 OpenCV를 설치한 곳에 가면 볼 수 있으며, 공식 웹사이트에서도 레퍼런스를 얻을 수 있다. 어떤 모듈이 존재하는지만 머릿속에 넣어두면 이를 시기적절하게 써주면 되는 것이다. 마치 공구 상자함에 무엇이 들어있는지 알고 있다면 어떤 일을 하던지 수월하게 할 수 있을 것이다. 하지만 어떤 공구가 들어있는지 인지가 되지 않는다면 힘들게 일할 것이다. 

 

D:\opencv\sources\modules 

 

필자는 D:\에다가 opencv를 설치했으므로 이렇게 나오는 것이지만 설치한 파일에 따라서 다 다르다. 이곳에 기본적인 모듈을 확인할 수 있다.

 

 

이렇게 폴더의 형태로 존재함을 볼 수 있다. 각각의 기능을 하나하나 실행시키는 것도 좋은 일이지만, 어떻게 사용하는지 알아볼 수 있는 설명서가 있는데, 그것이 레퍼런스이다.

docs.opencv.org/4.5.1/

 

OpenCV: OpenCV modules

OpenCV  4.5.1 Open Source Computer Vision

docs.opencv.org

이곳에 가면 여러가지 모듈을 확인하고 설명서를 볼 수 있다. 자주자주 방문하는 습관을 들이자.

 

2. 헤더


opencv2/opencv.hpp에는 OpenCV의 모든 기능을 사용할 수 있도록 모든 헤더파일이 포함되어 있다. 그래서 하나만 넣어도 충분히 컴파일이 가능하다. 하지만 닭 잡는데 소 잡는 칼을 쓸 수는 없는 법이다. 물론 그래도 되지만 너무 힘들다. 헤더파일도 마찬가지이다. 너무 큰 헤더 파일은 컴파일 시간을 늘린다. 그러므로 가볍게 만들어주는 것도 중요하다. 

#include<opencv2/opencv.hpp>	// OpenCV의 기능을 사용할 수 있게 해주는 헤더파일

int main(int argc, char** argv) {
	cv::Mat img = cv::imread("cat.png");

	imshow("img", img);
	cv::waitKey(0);

	return 0;
}

이전 블로그 글에서 사용한 코드를 헤더파일만 바꾸었다. 

[Computer Science/OpenCV] - [OpenCV]OpenCV란 무엇인가? 그리고 설치

 

실제로 두개를 모두 컴파일 해보면 차이남을 알 수 있다. cv::를 사용하고 싶지 않다면 using namespace cv;를 활용하면 cv::를 붙이지 않아도 된다. 이는 C++에서 클래스 이름을 붙여주는 것이므로 컴파일러에게 사전에 알려주는 것이다. 

#include<opencv2/opencv.hpp>	// OpenCV의 기능을 사용할 수 있게 해주는 헤더파일

using namespace cv;				// namespace cv를 알려줌으로써 미리 선언해주는 역할을 한다.

int main(int argc, char** argv) {
	Mat img = imread("cat.png");

	imshow("img", img);
	waitKey(0);

	return 0;
}

여기서 헤더 파일이 너무 많은 헤더 파일을 가지고 있으므로 필요한 기능을 담고 있는 헤더파일만 포함시키면 다음과 같다.

#include"opencv2/highgui/highgui.hpp"			// 헤더 파일을 가볍게 만들기 위해 교체!

using namespace cv;

int main(int argc, char** argv) {
	Mat img = imread("cat.png");

	if (img.empty()) return -1;

	namedWindow("img", cv::WINDOW_AUTOSIZE);
	imshow("img", img);
	waitKey(0);

	destroyWindow("img");

	return 0;
}

OpenCV에는 다양한 유형의 이미지 파일을 읽을 수 있는 유틸들을 제공한다. 기본 패키지 상에 포함되어 있는 HighGUI는 이를 도와준다. 위의 코드는 HighGUI를 활용해서 이미지 파일(여기서는 cat.png)를 열고 화면 상에 출력해주는 역할을 하고 있다.

 

여기서 int argc, char** argv는 argument라하는 인수들이 저장되는 공간이 된다. argc는 argument가 몇 개인지 알려주는 것이며, argv는 char형으로 저장되는 변수인데 배열로써 저장된다. 가장 처음에 있는 argv[0]는 실행 파일명이 저장되며, 그 뒤부터 argv[1], argv[2] ....  의 순서대로 사용자가 입력한 argument가 저장된다.

 

3. 코드 해설


다음 코드를 하나씩 해설해보면서 각각의 코드가 어떤 의미를 가지고 있는지 살펴보도록 하자.

 

#include"opencv2/highgui/highgui.hpp"	

using namespace cv;

int main(int argc, char** argv) {
	Mat img = imread("cat.png");

	if (img.empty()) return -1;

	namedWindow("img", cv::WINDOW_AUTOSIZE);
	imshow("img", img);
	waitKey(0);

	destroyWindow("img");

	return 0;
}

헤더 파일은 제외하고 main 함수 내부에 있는 것들을 살펴보도록 하자.

  1. Mat img = imread ("cat.png");

  2. if(img.empty()) return -1;

  3. namedWindow("img", cv::WINDOW_AUTOSIZE);

  4. imgshow("img", img);

  5. waitKey(0);

  6. destroyWindow("img");

이런 순서대로 살펴보도록 하자. 

1. Mat img = imread ("cat.png")

먼저 나오는 imread 이다.(namespace cv가 없으면 cv::imread) image read 라고 생각하면 되는데, 파일 이름을 기반으로 파일의 포맷을 결정해준다. 예를 들어, cat.png이므로 파일 포맷 PNG에 해당하는 데이터 구조에 필요한 메모리를 자동으로 할당해주는 것이다. 이미지 파일과 관련된 다양한 포맷을 지원한다. (BMP, JPEG, JPG, PNG, DIB, PPM, TIFF 등등 다양한 이미지 포맷을 지원한다.) imread는 최종적으로 구조체 Mat의 형태로 반환한다. 

 

Mat은 구조체로써 OpenCV의 기본을 이루는 구조체라 봐도 무방할 정도로 많이 쓰이는 구조체이다. 이미지 상에 담고 있는 정보를 처리한다. 이 정보는 단일 채널, 다중 채널, 정수 값, 부동 소수 값 등으로 컴퓨터가 이미지를 받아들이는데 사용되는 다양한 데이터를 의미한다. Mat 구조체의 기본 상속은 다음과 같다.

 

조금 더 자세한 내용은 docs.opencv.org/4.5.1/d3/d63/classcv_1_1Mat.html 이곳에서 보자.

 

2. if(img.empty()) reuturn -1;

Mat구조체의 이름을 img라 정했으며, 1번에서 imread를 통해 읽어들인 cat.png 파일을 Mat이라는 구조체 변수, 이름은 img에 넣었다. 이를 통해 img.empty()는 받은 파일이 비어있는지 아닌지를 판단해주는 것이다. 반환값은 true, false로 전달해 준다. (비어있으면 true로 반환해줌, 속에 무언가 들어있으먄 false를 반환) 

 

3. namedWindow("img", cv::WINDOW_AUTOSIZE);

namedWindow 함수는 High-level GUI, HighGUI 모듈에 속하는 함수이다. 화면에 이미지를 표시할 수 있는 윈도우를 열어준다. 인수가 두 가지가 있는데, 첫번째 인수는 윈도우 이름을 지정한다. 만약에 이름이 있으면(중복되면) 아무일도 하지 않는다. 두 번째 인수는 윈도우 사이즈를 결정해주는데,

  • 윈도우 사이즈는 자동으로 이미지 크기와 같을 것인지 - WINDOW_AUTOSIZE (이미지 사이즈에 맞춰 자동 조정되며 이후에 사용자가 조정 가능하다. 하지만 윈도우 창 크기를 마우스로 늘러거나 줄이는 것은 불가능하다. 함수에 의해서 조절해야 한다.)
  • 이미지 사이즈 관계없이 동일한 값으로 만들 것인지 - 0 (기본값이다.), 처음에 만들어진 값은 고정 값으로 만들어지지만, 마우스를 통해 늘리거나 줄이는 것이 가능하다.

두 번째 인수에 들어갈 flag값은 여기에서 확인이 가능하다. 

HighGUI는 4가지의 주요한 함수가 존재하는데, ButtonCallback, MouseCallBack, OpenGIDrawCallback, TrackbarCallback으로 차례대로 버튼, 마우스, 화면 출력, 트랙바에 해당하는 값을 담당한다. [opencv2/highgui.hpp 헤더에 들어있다.] 기본으로 제공된 함수 외 더 많은 기능을 사용하고자 한다면 Qt 를 활용해서 확장해나가면 된다. Qt는 C++을 통해 GUI를 제작하는 크로스플랫폼 프레임워크이다. (C++외에 다른 언어로도 만들 수 있다.) 자동차 계기판 GUI부터 시작해서 스마트 Tv에 들어가는 GUI까지 다양하게 만들어져있다. 

Qt를 더 알고 싶다면 -> www.qt.io/ko-kr/

 

Qt | 임베디드와 데스크탑을 위한 크로스플랫폼 소프트웨어 개발

Qt는 혁신적인 기기와 세련된 UI 및 어플리케이션을 만드는 빠르고, 스마트한 방법입니다. 우수한 크로스플랫폼 소프트웨어 개발을 만나보세요.

www.qt.io

 

4. imgshow("img", img);

Mat구조체 상에 이미지에 대한 정보가 들어있다면 imgshow를 통해 화면에 출력할 수 있다. (조금 더 정확히는 위에서 만든 윈도우에 출력할 수 있다. 만약에 만들어진 윈도우가 없다면 cv::imshow함수는 cv::namedWindow()를 활용해서 새롭게 생성한다. ) 실제로 보여주는 역할을 하게 해주는 함수이다.

 

5. waitKey(0);

waitKey(0); 의 기본 원형 int cv::waitKey ( int delay = 0 ) 의 원형을 가지고 있으며, 키 입력이 있을 때까지 기다리는 함수이다. 인수는 밀리세컨드 단위로 대기하는 것이다. 0 또는 음수로 설정이 될 경우에, 키 입력을 무한히 기다리는 형태이다. (항상 조심해야 하는 것은 시간의 단위가 밀리세컨드 단위라는 점이다! - millisecond는 1000 분의 1초이다. 0.5초라면 500 millisecond)

 

6. destroyWindow("img");

OpenCV는 메모리 사용에 대해서 많은 고려가 되었는데, destroyWindw 또한 메모리 해제와 관련된 함수이다. 일반적으로 표준 템플릿 라이브러리(STL)의 스코프 밖으로 벗어나게 되면 자동으로 메모리 할당이 해제 되지만, 규모가 조금이라도 커진다면 프로그래머가 임의로 해제해줘야 하는 상황이 발생할 수도 있다. destroyWindow는 윈도우를 닫고 관련된 모든 메모리 사용에 대해 해제하는 역할을 해준다. (메모리 누수를 방지하기 위해 중요한 역할을 한다.) 위의 코드 상에는 사실 필요가 없지만, 이러한 것이 있다라는 것을 보여주기 위해 넣어두었다.

 

 

OpenCV 로고

1. OpenCV


OpenCV는 Open Source Computer Vision의 약자로 영상 처리에 사용할 수 있는 오픈 소스 라이브러리 입니다. 컴퓨터가 사람의 눈처럼 인식할 수 있게 처리해주는 역할을 하기도 하며, 우리가 많이 사용하는 카메라 어플에서도 OpenCV가 사용하기도 한다. (추가로 자율주행자동차에서 자동차의 눈이 되주는 것이 카메라와 OpenCV가 합작해서 해낸 일이다.) 추가로 사용되는 예로는 

  • 공장에서 제품 검사할 때
  • 의료 영상 처리 및 보정 그리고 판단
  • CCTV영상
  • 로보틱스

등 다양한 범위에서 사용되고 있다. 카메라로 찍어서 할 수 있는 모든 일은 OpenCV로 처리할 수 있다. 여기에 머신 러닝과 A.I를 활용해서 그 활용도를 더욱 넓혀가고 있는 중이다.

이런 느낌의 일을 할 수 있다.
사진을 보정

 

OpenCV가 더욱 인기있는 이유는 오픈소스이지만 BSD(Berkely Software Distribution)라이선스를 따르기 때문에, 상업적 목적으로 사용해도 좋다. 그리고 소스코드 공개 의무가 없다는 점에서 강점을 가지고 있다. OpenCV의 기원은 인텔에서부터 시작되는데, 컴퓨터 비전과 인공지능의 발달 시키고자 하는 바램으로 OpenCV를 출시한 것이다. (with Grary Bradski) 

 

OpenCV는 실시간 처리에 중점을 두고 설계되서 빠른 속도와 효율성을 자랑한다. 기반 언어는 C++로 멀티 코어 프로세서를 활용할 수 있다. 심지어 인텔IPP(Integrated Performance Primitives)를 통한 최적화 루틴을 활용함으로써 로우레벨에서 자동화된 최적화를 사용할 수 있다. 이전에는 유료로 구매해야 했지만, OpenCV 3.0 부터는 IPP의 일부를 무료로 제공해주고 있다. 

[사실 인텔은 OpenCV를 배포함으로써 OpenCV가 점차 발전함에 따라 빠른 프로세서가 필요시 되고 이는 인텔 프로세서의 수요가 늘어나 수입이 늘어나는 큰 그림을 그리고 있었다.]

그렇다면 여기서 가장 중요한 단어인 컴퓨터 비전이란 무엇인가?

 

2. 컴퓨터 비전?


컴퓨터 비전은 카메라로 얻은 일련의 영상들을 모두 컴퓨터 비전이라 한다. 사람은 눈을 통해 많은 정보를 받아들인다. 지금 이 글을 읽는 순간에도 눈을 통해서 읽고 있지 않은가? 프로그래밍에서 항상 생각해보아야 할 것 중 하나의 원칙은 '사람에게 쉬운 일은 컴퓨터에게 어려울 수 있다.'라는 말이다. 컴퓨터 비전 또한 마찬가지이다. 사람에게 너무나 쉬운 보는 일은 컴퓨터에게는 너무나도 어려운 일이다. 하나의 사진에서 사람을 가려내고, 그 속에서 지나는 여러 사물을 골라내는 일은 컴퓨터에게 어렵다. 사람은 이렇게 어려운 일을 자연스럽게 해낸다. 카메라의 역할을 하고 있는 눈은 빛을 자연스럽게 조절하며, 초점을 자동으로 조절한다. 정말 대단한 일인 것이다. 카메라는 이를 일일히 작업해서 맞춰줘야 한다. 카메라가 사진을 찍으면 컴퓨터는 이를 단순한 숫자로 인식할 뿐이다. 오로지 0과 1로 이루어져서 다시 나올 뿐이다. 

 

컴퓨터는 단순히 숫자로 이루어진 형태로 사진을 인식할 뿐이다.

컴퓨터는 이러한 숫자의 행렬로 사진 및 여러 형태를 인식한다. 그렇다면 우리는 이러한 형태를 가지고 컴퓨터에게 유의미한 정보를 입력해줌으로써 사람이 보는 시선과 최대한 비슷하게 만들어야 하는 것이다. 하지만 여기에는 많은 문제가 도사리고 있다. 우리의 시각 정보는 왜곡이 많다. 예를 들어 우리가 보는 관점에 따라 사물이 왜곡될 확률이 있다. 다른 왜곡은 빛의 양에 따라 달라지기도 하며 비가 오는 경우에는 더욱 심각해진다. 심지어 카메라의 성능에 따라 계속 변한다. 전기적 노이즈도 생각해봐야 한다. 이러한 왜곡을 이겨내고서 우리는 정확한 이미지 처리가 필요한 것이다. (심지어 카메라는 3D 정보를 2D로 받아들이고 있다.) 

 

이 부분에 대한 해결책은 머신러닝 기술로 어느정도 보완하고 있다. 혹은 다른 추가적인 데이터를 활용해서, 예를 들어 라이다 센서 혹은 거리 센서를 활용해서 왜곡정보를 올바르게 해석하기 위한 노력을 하고 있다. 그리고 OpenCV는 이러한 다양한 문제들을 해결하기 위한 도구를 제공해주는 것을 목표로 한다. 지금도 많은 연구가 이루어지고 있으며, 다양한 자료들이 쏟아져 나오고 있다. 

 

OpenCV와 사용할 수 있는 언어로는 C/C++, 파이썬, Java등이 있다. 요새 많이 쓰이는 언어로는 파이썬이 많이 사용되고 있다. 빅데이터와 머신 러닝에서 강점을 보이고 있기에 파이썬이 많이 쓰인다. 하지만 이 블로그에서는 C++을 통해서 사용하도록 할 예정이다. 나중에 기회가 된다면 파이썬을 통한 머신러닝과 딥러닝 그리고 A.I를 사용할 때 파이썬을 사용하려 한다. 하나의 언어를 제대로 배워두면 다른 언어에 대한 장벽은 높지 않은 편이므로 일단은 C++로 진행하려 한다. 

 

3. 기본 구조


OpenCV의 기본 아키텍처는 다음과 같다.

기본 아키텍처

각 요소를 살펴보자면,

  • CV : Computer Vision으로 기본 구성 요소에서는 기본 이지미 처리와 고급 컴퓨터 비전 알고리즘을 포함하고 있다.
  • ML (Machine Learning) : 머신러닝이 주를 이루므로 이를 활용할 수 있는 기본적인 통계 분류기와 클러스터링 도구를 포함하고 있는 라이브러리들이 있다.
  • HighGUI : OpenCV에 기본으로 포함되어 있는 GUI이다. 여기에는 비디오와 이미지 저장 그리고 이를 로드하기 위한 I/O 루틴을 포함하고 있다. 이 모듈을 활용해서 사용자의 입력을 받고 그에 따른 출력하는 기능을 하는 유저 인터페이스 기능을 하고 있다. 기본 기능으로 지원하고 있지만 조금 더 범용적으로 Qt를 사용한다. (윈도우 GUI 툴킷 정도라 생각할 수 있다.)
  • CXCORE : 이곳에는 기본 데이터 구조와 여러 content가 구성되어 있다. 

OpenCV 아키텍처 (TBB는 Threading Building Blocks - 병렬처리를 위한 것이라 생각하면 된다.)

다른 관점에서 보자면 이러한 아키텍처 구조를 갖는다. 다양한 라이브러리의 모듈이다. 업데이트가 되면 달라지겠지만 현재 모듈 구성은 다음과 같다.

  • Core - 모든 객체 타입과 기본 연산자가 들어 있는 라이브러리 섹션

  • Imgproc - 이미지 처리 모듈로써 이미지 변환 등을 포함하고 있다.

  • highgui - 위에서 설명했다. ( 사용자의 입력을 받는 유저 인터페이스 기능 포함)

  • video - 비디오 라이브러리로써 비디오 스트림을 read/write하는 함수가 포함되어 있다.

  • calib3d - 캘리브레이션하는데 필요한 알고리즘이 포함된 모듈

  • features2d - 중요한 feature(특징)을 탐지하고 표현, 매칭하기 위한 알고리즘이 구현된 모듈

  • objdetect - 말 그대로 오브젝트 디텍트, 특정 오브젝트를 탐지하는 알고리즘이 들어있는 모듈이다. 이를 머신 러닝으로 기계 학습 시켜서 특정 물체들을 탐지할 수 있다.

  • ml - 머신러닝 라이브러리

  • flann - Fast Library for Approximate Nearest Neighbors 나중에 이야기하겠지만, 머신러닝에 사용되는 알고리즘이다. 자세한 내용은 

flann의 자세한 내용은 공식 깃헙 [github.com/mariusmuja/flann]에 있다.

  • gpu - 그래픽 카드를 이용한 연산을 사용한다. 일명 그래픽카드 연산을 위한 라이브러리이다. CUDA연산에 최적화 되어 있다. 당연히 머신러닝을 위한 설계이다. CUDA (Computed Unified Device Architecture)로써 NVIDIA에서 개발한 GPU 개발툴이다. 딥러닝에서 사용하기 위해서 만들어졌으며, 하드웨어에서는 얻을 수 없는 연산을 할 때 많이 사용된다. 비트코인 채굴할 때 사용하는 것이 CUDA이다. (tensorflow도 사용된다.)

  • photo - 사진을 활용할 수 있는 다양한 도구를 포함하고 있다.

  • stitching - 스티치 파이프라인을 구현하기 위한 모듈, Image stitching이란 이미지를 포갤 지점을 찾는 과정이라 생각하면 된다. 이를 빠르게 하는 파이프라인을 구현하기 위한 모듈이라 생각하면 된다.

  • nonfree - OpenCV에서 특허나 사용 제한이 걸려있는 알고리즘의 구현이 이곳에 있다. ( 예를 들어 SIFT알고리즘)

등이 존재한다.

 

4. 다운로드 및 설치


앞서 이야기했듯이 설치는 C++로 진행할 예정이다. 바인딩 용 언어는 Java, C++, Python 등을 많이 사용하지만 그 원론에 다가가고자 C++를 이용해서 설치하고 실습해볼 예정이다. 처음 배울 때는 역시 라이브러리가 만들어진 언어 혹은 권장하는 언어가 좋다. 필자는 그냥 C++가 빨라보여서 C++를 사용하고자 한다.

 

선행조건으로 Visual Studio가 설치되어 있어야 한다. 설치는 

visualstudio.microsoft.com/ko/downloads/ 이곳에서 할 수 있다. [커뮤니티]로 설치하면 된다. 공짜다

기본 설치 옵션으로 당연히 C++를 사용할 것이므로 "C++를 사용한 데스크톱 개발"을 체크해줘야 한다. 어차피 체크 못했어도 나중에 추가할 수 있으므로 상관이 없다. 

 

새 프로젝트 만들기 선택

먼저, 프로젝트를 만들어주고, 

 

 

Window 데스크톱 마법사 -> 다음을 눌러준다.

 

 

 

적당한 프로젝트 이름을 만들어준 뒤에, 만들기 버튼을 클릭!

 

 

빈프로젝트 체크박스에 체크해주고 확인 버튼을 누르자.

 

소스파일에서 오른쪽 클릭!

 

 

 

그러면 이렇게 나오는데, 여기서 추가 -> 새 항목을 클릭

 

 

이렇게 C++ 파일을 눌러주고 추가를 누르면 완성!

여기서 이름을 잘 보면 cpp는 C++(씨플플)으로 만들어지며, 확장명이 .c로 끝나면 C언어로 구성된다.

 


opencv.org/releases/

 

Releases - OpenCV

Become a Member Stay up to date on OpenCV and Computer Vision news Join our Newsletter  

opencv.org

OpenCV공식 홈페이지로 들어가면 다양한 버전이 나온다. 안정화 버전은 버전 3.4.13, 최신 버전은 4.5.1이다.

여기서는 4.5.1을 통해 진행해보도록 하자.

 

 

자신에게 맞는 운영체제를 선택하면 되지만, 대부분이 Windows이므로 선택!

소스포지에서 기다리면 알아서 다운로드가 시작된다. 적당한 곳에 다운로드를 받자.

211MB의 크기를 가진다. 배포 서버에 따라 속도가 천차만별 이므로 일단은 기다리자. 다운로드 받은 뒤에는 나머지 창은 꺼도 좋다. 

파일명은 opencv-4.5.1-vc14_vc15.exe 이다.

 

 

실행하면 별거 없다. Extract누르자. 이건 단순히 압축해제를 시켜주는 것이다. C:\나 D:\에다가 해두면 된다.

 


자 이제 비주얼 스튜디오로 가자.

파일을 하나 만들고 (파일명은 main.cpp로 하자)

프로젝트란에 있는 속성을 누르자.

 

구성 : 모든 구성, 플랫폼 : x64로 하자 (기본 운영체제 구성이 64비트면 x64, 32비트면 win32를 선택하면 된다.)

그리고서 좌측에 있는 C/C++ 란에 일반을 클릭한 뒤

추가 포함 디렉터리에 D:\opencv\build\include를 입력한다.

만약에 다른 곳에 저장되어 있으면 저장된 위치에 있는 [ 저장된위치\opencv\build\include ]를 입력해주면 된다.

 

이번에는 링커 탭에 있는 일반으로 간다.

거기에도 마찬가지로 추가 라이브러리 디렉터리 란에

D:\opencv\build\x64\vc15\lib 를 입력해준다. 

 

링커탭에 입력란으로 눌러준다.

그러면 추가 종속성이 있는데, 여기에 opencv_world451d.lib;를 입력해준다. 세미콜론 ;을 꼭 넣어줘야 한다. 컴퓨터가 인식할 때는 세미콜론으로 구분하기 때문에 반드시 넣어주자!

 

여기에 넣는 문장은 설치한 파일명을 명확히 입력해야 한다.

필자는 4.5.1 버전을 설치했으므로 opencv_world451d.lib가 나온것이다. 

일반적으로 [ 설치한 폴더\opencv\build\x64\vc15\lib ]에서 확인할 수 있으므로 확인해보고 가자! 

 

마지막으로

 

x64로 되어 있는지, 디버그 모드인지 확인하자.

 

자 이제 프로젝트 명을 오른쪽 클릭하면 여러 속성이 나오는데, 여기에서 파일 탐색기에서 폴더 열기를 눌러준다.

 

그리고서,

D:\opencv\build\x64\vc15\bin여기에 들어가면

 

파일 두 개가 있다. 이것을 아까 열어둔 파일 탐색기에서 폴더 열기 를 한 곳에다가 복사! 하면 된다.

 

 

프로젝트 폴더 안에 같이 나란히 존재하면 된다. 아까 사용했던 lib 파일이 아니다. 

dll 확장자를 가진 파일이다. 유의하자. 컴파일러에게 파일과 파일을 연결해주는 역할을 해준다. (동적 링크라고 하며, 실행파일에서 라이브러리 기능을 사용 시에, 라이브러리를 참조해서 기능을 호출해주는 역할을 하는 것이다.)

 


이제 프로젝트 파일에다가 코딩 테스트를 할 png 파일을 가져다 두자.

cat.PNG
0.39MB

프로젝트 폴더는 일반적으로 C:\Users\<사용자명>\source\repos\Project_OpenCV_1\Project_OpenCV_1

에 들어있다. 못 찾겠으면 위에 올라가서 탐색기에서 열기를 다시 활용하자.

 

아까 만들어 놓은 main.cpp에다가 입력하자.

#include<opencv2/imgcodecs.hpp>
#include<opencv2/video.hpp>
#include<opencv2/highgui.hpp>

#include<iostream>
#include<stdio.h>

using namespace std;

int main(int arg, char** argu) {
	cv::Mat img = cv::imread("cat.png");

	imshow("img", img);
	cv::waitKey(0);

	return 0;
}

확인할 용도이므로 나중에 설명하도록 하자.

 

타이핑이 완료되었다면, 

디버깅 시작을 누르고 잠시 기다리면 프로그램이 시작된다.

 

귀여운 고양이가 나온다면 완료! 

정말 고생했다. 이로써 우리는 OpenCV를 사용하기 위한 기본 셋팅을 완료한 것이다.

 

다음 시간에는 OpenCV에서 사용되는 기본적인 함수를 사용하면서 하나하나 이야기해보도록 하자.

 

 

참고 자료

docs.opencv.org/master/index.html

+ Recent posts