얼마전에 Ubuntu 18.04 LTS 버전이 나왔습니다. 그래서 오늘은 Ubuntu 18.04 에서 OpenCV 최신 버전을 설치하는 방법에 대해 알아보도록 하겠습니다. 예전에 라즈베리파이에서 OpenCV를 설치하는 방법을 설명한 적이 있었는데요, 거기서 크게 다르지 않습니다.


일단 저는 Virtual Box를 이용하여 가상 머신 형태로 리눅스 우분투 18.04를 설치를 했구요, 여기에 OpenCV 3.4.0 버전을 설치하겠습니다. (참고로 CPU 코어는 2개를 할당했습니다.) 모두 5개의 Step으로 설치를 설명하고, 실제 OpenCV C++ 예제 코드를 빌드하여 실행하는 방법까지 알아보겠습니다. 각각의 Step에서 #으로 시작하는 내용은 설명을 의미하고, 실제 입력할 명령어는 $ 으로 표기하였습니다.


Step 1. 가장 먼저 리눅스를 최신 상태로 업데이트합니다.

# Optional. Ubuntu 18.04에서 libjasper-dev 패키지를 설치하기 위해서 저장소를 추가해야 합니다.
$ sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"

$ sudo apt update
$ sudo apt upgrade

# Optional. Ubuntu 18.04 설치 후 추가적으로 필요한 코덱, 미디어 라이브러리를 설치합니다.
$ sudo apt install ubuntu-restricted-extras


Step 2. 필요한 패키지를 설치합니다.

# Build tools & required
$ sudo apt install build-essential cmake git pkg-config

# For still images
$ sudo apt install libjpeg-dev libtiff5-dev libjasper-dev libpng-dev

# For videos
$ sudo apt install libavcodec-dev libavformat-dev libswscale-dev
$ sudo apt install libdc1394-22-dev libxvidcore-dev libx264-dev x264
$ sudo apt install libxine2-dev libv4l-dev v4l-utils
$ sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev

# GUI
$ sudo apt install libgtk-3-dev

# Optimization, Python3, etc.
$ sudo apt install libatlas-base-dev libeigen3-dev gfortran
$ sudo apt install python3-dev python3-numpy libtbb2 libtbb-dev


Step 3. OpenCV 3.4.0 소스 코드를 다운로드합니다.

# Create a working directory named opencv
$ cd ~
$ mkdir opencv
$ cd opencv

# Download sources
$ wget -O opencv-3.4.0.zip https://github.com/opencv/opencv/archive/3.4.0.zip
$ wget -O opencv_contrib-3.4.0.zip https://github.com/opencv/opencv_contrib/archive/3.4.0.zip

# Unpack
$ unzip opencv-3.4.0.zip
$ unzip opencv_contrib-3.4.0.zip


Step 4. CMake를 이용하여 Makefile을 생성합니다.

# Create a build directory
$ mkdir build && cd build

# Run CMake
$ cmake \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D BUILD_WITH_DEBUG_INFO=OFF \
-D BUILD_EXAMPLES=ON \
-D BUILD_opencv_python2=OFF \
-D BUILD_opencv_python3=ON \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D OPENCV_EXTRA_MODULES_PATH=../opencv_contrib-3.4.0/modules \
-D WITH_TBB=ON \
-D WITH_V4L=ON \
../opencv-3.4.0/ 2>&1 | tee cmake_messages.txt


Step 5. 컴파일과 설치를 진행합니다.

# find out the number of CPU cores in your machine
$ nproc

# substitute 2 after -j by the output of nproc
$ make -j2 2>&1 | tee build_messages.txt
$ sudo make install
$ sudo ldconfig

# If the output of next command is '3.4.0' then it's ok!
$ pkg-config --modversion opencv


여기까지 설치가 잘 진행되었으면 이제 OpenCV 예제 프로그램을 만들어서 정상적으로 동작하는지를 확인해보겠습니다. 일단 홈디렉토리 아래에 ~/coding/HelloCV 라는 디렉토리를 만들고, 그 안에 HelloCV.cpp 파일을 아래와 같이 작성합니다.


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

using namespace cv;
using namespace std;

int main(void)
{
        Mat img = imread("lena.jpg");

        if (img.empty()) {
                cerr << "Image load failed!" << endl;
                return -1;
        }

        namedWindow("image");
        imshow("image", img);
        waitKey(0);
        return 0;
}


그리고 위 소스 코드를 빌드하기 위한 Makefile 파일을 아래와 같이 생성합니다. 아래 코드에서 들여쓰기(인덴트)는 스페이스가 아니라 탭(tab)입니다.


CC = g++
CFLAGS = -g -Wall
SRCS = HelloCV.cpp
PROG = HelloCV

OPENCV = `pkg-config opencv --cflags --libs`
LIBS = $(OPENCV)

.PHONY: all clean

$(PROG):$(SRCS)
    $(CC) $(CFLAGS) -o $(PROG) $(SRCS) $(LIBS)

all: $(PROG)

clean:
    rm -f $(OBJS) $(PROG)


위와 같이 입력하고, $ make 명령어를 입력하면 HelloCV 라는 이름의 실행 파일이 생성됩니다. 그러므로 $ ./HelloCV 라고 명령어를 입력하면 프로그램이 실행되는데요.. 에러만 출력되고 종료됩니다. 왜냐하면 테스트로 사용하는 lena.jpg 파일이 없어서죠. 그러므로 opencv 소스 코드에 포함되어 있는 lena.jpg 파일을 현재 폴더로 복사합니다.

$ cp ~/opencv/opencv-3.4.0/samples/data/lena.jpg .


그리고 다시 $ ./HelloCV 명령을 입력합니다. 그러면 아래 그림처럼 lena 영상이 화면에 나타납니다. 


참 쉽죠? :-)

Posted by kkokkal
:

엊그제 CUDA 9.2가 릴리즈되었다는 메일을 받고 새로 설치를 해봤습니다. CUDA Toolkit은 아래 링크에서 다운로드 받을 수 있구요..

https://developer.nvidia.com/cuda-downloads


새로 릴리즈된 CUDA 9.2는 최신 Visual Studio 2017을 잘 지원하는지가 궁금했는데요..

일단 c:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.2\include\crt\host_config.h 파일을 열어서 _MSC_VER 값에 대한 설정을 봤더니 아래처럼 되어 있습니다.


즉, _MSC_VER 값이 1912까지만 지원을 한다는 건데요, 이전에 CUDA 9.1에서는 1910까지만 지원을 했었는데 버전 번호가 조금 늘기는 했지만, 음...


일단 _MSC_VER와 Visual Studio 제품명 또는 실제 버전 번호와의 관계를 보시죠. (출처: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B)


MS에서 Visual Studio 2017에서는 유별나게 마이너 버전 업그레이드에서 _MSC_VER 값을 변경을 해놔서, 가장 최근의 Visual Studio 2017 15.7 버전의 경우 _MSC_VER 값이 1914입니다. 그렇다는 것은 CUDA 9.2는 최신 버전의 Visual Studio 2017에서는 제대로 동작하지 않을 가능성이 있다는 거구요... 그래서 강제로 host_config.h 파일을 편집해서 아래와 같이 바꾸고,


nVidia에서 제공하는 CUDA 예제 프로젝트를 실행해봤는데요, 어라? 잘 됩니다. :-)


자, 그래서 이번에는 OpenCV 소스 코드를 Visual Studio 2017에서 CUDA를 활성화하여 빌드하는 작업을 해봤습니다. 일단 기본적인 방법으로 CMake 프로그램을 사용하여 OpenCV 프로젝트를 생성하면 빌드가 잘 되지 않습니다. 아마도 CUDA 9.2의 문제가 아니라 Visual Studio 2017 최신 버전의 셋팅 문제라고 생각되는데요.. 결론을 말씀드리면 CMake-gui 화면에서 아래와 같이 CUDA_HOST_COMPILER 값을 수정하시면 됩니다.

CUDA_HOST_COMPILER: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.14.26428/bin/Hostx64/x64/cl.exe


이에 대한 좀 더 자세한 내용은 아래 내용을 펼쳐서 보세요.


이렇게 수정하여 CUDA를 설정한 상태에서 OpenCV를 빌드하면 역시나 몇시간의 시간이 소요됩니다. 그래도 실패 없이 잘 빌드가 되는 것을 확인했습니다. ^^


세 줄 요약:

1. host_config.h 파일에서 _MSC_VER 허용 범위를 수정.

2. CMake에서 CUDA_HOST_COMPILER 값을 수정.

3. 빌드.


Posted by kkokkal
:


문득 알파 채널이 있는, 투명한 PNG 파일을 합성하는 방법이 궁금해져서 인터넷을 찾아봤습니다. 역시나 잘 정리되어 있는 사이트가 꽤 있더군요.


https://www.learnopencv.com/alpha-blending-using-opencv-cpp-python/
여기는 저도 자주 참고하는 learn opencv 블로그구요.. 일단 PNG 파일을 채널 분리하여 multiply(), add() 함수를 조합해서 합성하는 방법과 직접 픽셀 값에 접근해서 합성하는 방법을 비교해놓았습니다. 픽셀 값 접근할 때 Mat::data 멤버 함수를 직접 참조하는데, 음.. 개인적으로는 좋아하지 않는 방법입니다.


http://jepsonsblog.blogspot.kr/2012/10/overlay-transparent-image-in-opencv.html
큰 배경 영상의 일부분에 작은 크기의 PNG 파일을 합성하는 코드를 잘 만들어둔 블로그입니다. 역시나 data 멤버 변수를 직접 사용했구요..


https://blog.naver.com/h2ohyukhyuk/220935134665
한글로 된 블로그인데, 예제로 사용한 그림이 꽤 재미있었습니다.


일단 위에 나타난 코드와 예제를 참고하여, 이번 포스트에서는 입력 영상에서 얼굴을 검출하고, 검출한 얼굴 위에 고양이 귀를 합성하는 예제를 만들어보았습니다. 일단 전체 코드를 공개하겠습니다.


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

using namespace cv;
using namespace std;

void overlayImage(Mat& src, const Mat& over, const Point& pos)
{
	CV_Assert(src.type() == CV_8UC3);
	CV_Assert(over.type() == CV_8UC4);

	int sx = std::max(pos.x, 0);
	int sy = std::max(pos.y, 0);
	int ex = std::min(pos.x + over.cols, src.cols);
	int ey = std::min(pos.y + over.rows, src.rows);

	for (int y = sy; y < ey; y++) {
		int y2 = y - pos.y; // y coordinate in overlay image

		Vec3b* pSrc = src.ptr<Vec3b>(y);
		const Vec4b* pOvr = over.ptr<Vec4b>(y2);

		for (int x = sx; x < ex; x++) {
			int x2 = x - pos.x; // x coordinate in overlay image

			float alpha = (float)pOvr[x2][3] / 255.f;

			if (alpha > 0.f) {
				pSrc[x][0] = saturate_cast<uchar>(pSrc[x][0] * (1.f - alpha) 
						+ pOvr[x2][0] * alpha);
				pSrc[x][1] = saturate_cast<uchar>(pSrc[x][1] * (1.f - alpha) 
						+ pOvr[x2][1] * alpha);
				pSrc[x][2] = saturate_cast<uchar>(pSrc[x][2] * (1.f - alpha) 
						+ pOvr[x2][2] * alpha);
			}
		}
	}
}

int main()
{
	Mat src = imread("dlwlrma.jpg", IMREAD_COLOR);
//	Mat src = imread("iujelly.jpg", IMREAD_COLOR);
	Mat cat = imread("cat.png", IMREAD_UNCHANGED);

	if (src.empty() || cat.empty()) {
		cerr << "Image load failed!" << endl;
		return -1;
	}

	CascadeClassifier face_cascade("haarcascade_frontalface_default.xml");

	if (face_cascade.empty()) {
		cerr << "Failed to open (face) xml file!" << endl;
		return -1;
	}

	vector<Rect> faces;
	face_cascade.detectMultiScale(src, faces);

	for (Rect face : faces) {
		float fx = float(face.width) / cat.cols;

		Mat tmp;
		resize(cat, tmp, Size(), fx, fx);

		Point pos(face.x, face.y - face.height / 3);
		overlayImage(src, tmp, pos);
	}

	imshow("src", src);

	waitKey(0);
	return 0;
}


위 예제에서 overlayImage(src, over, pos); 함수는 3채널 컬러 영상 src에, 4채널 PNG 파일로부터 만들어진 over 영상을 pos 위치에 합성하여 src에 저장합니다. 제가 작성한 overlayImage() 함수가 앞서 소개한 블로그에서 사용한 함수와 다른 점은,

- data 멤버를 직접 참조하는 방법 대신, 좀 더 안전한 Mat::ptr() 함수를 사용하였고..
- for 루프 시작 전에 실제 합성이 이루어지는 영역을 계산하였고..
- 한 장의 입력 영상에 여러 번 합성을 할 수 있도록 구조를 변경했다는 점입니다.


얼굴을 검출하는 코드에 대한 자세한 설명은 생략하구요.. ranged-for 루프에서 합성할 때에는 검출된 얼굴 영역의 가로 크기에 맞게 고양이 귀 영상 크기를 축소한 후, 얼굴 위 적당한 위치에 고양이 귀를 합성합니다. 얼굴이 2개 있으면 2번 합성하게 됩니다. 실제 결과는 아래와 같습니다.




참고로 제 Desktop에서 512x512 영상에 합성하는데 0.1ms도 걸리지 않았습니다. 꽤 빠르네요.


Posted by kkokkal
: