How to get accumulation array on Hough transform in OpenCV



허프 변환(Hough transform)은 주로 영상에서 직선을 검출할 때 사용됩니다. OpenCV에서는 HoughLines() 함수를 이용하여 직선을 나타내는 파라미터(rho, theta)를 얻을 수 있습니다. 직선을 검출하는 것만이 목적이라면 HoughLines() 함수가 반환하는 rho, theta 값만 이용하면 되지만, 간혹 HoughLines() 함수 내부에서 축적 배열이 어떻게 생성되는지 궁금해하는 분들이 있습니다. 그런 분들을 위해 OpenCV 소스 코드를 변경하여 축적 배열을 받아오는 방법에 대해 설명하겠습니다. 참고로 이 포스팅에서는 OpenCV 4.0.0 버전을 기준으로 설명합니다.


HoughLines() 함수는 <OpenCV-SRC>\modules\imgproc\include\opencv2\imgproc.hpp 파일에 선언되어 있고, <OpenCV-SRC>\modules\imgproc\src\hough.cpp 파일에 정의되어 있습니다. 그러므로 이 두 개의 파일을 수정하여 HoughLines() 함수를 변경할 수 있습니다. OpenCV에서 제공하는 HoughLines() 함수 선언은 다음과 같습니다.

void HoughLines( InputArray image, OutputArray lines,
                 double rho, double theta, int threshold,
                 double srn = 0, double stn = 0,
                 double min_theta = 0, double max_theta = CV_PI );

이 함수 선언에 인자를 하나 추가하여 축적 배열을 받아오는 용도로 사용하겠습니다. 그래서 함수 선언을 아래와 같이 변경합니다.

void HoughLines( InputArray image, OutputArray lines,
                 double rho, double theta, int threshold,
                 double srn = 0, double stn = 0,
                 double min_theta = 0, double max_theta = CV_PI,
                 OutputArray accum = noArray() );

HoughLines() 함수에 accum 인자를 새로 추가했지만 디폴트 인자를 지정해두었기 때문에 기존 방식의 HoughLines() 함수와 완전히 호환됩니다. 축적 배열을 받고 싶으면 accum에 Mat 객체를 지정하고, 축적 배열이 필요없다면 accum을 지정하지 않으면 됩니다.


그럼 이제 해야할 일은 HoughLines() 함수 안으로 들어가서 함수 내부에서 만들어서 사용하던 축적 배열을 accum 인자로 복사해주면 됩니다. 아주 간단하죠. 다만 허프 변환에 의한 직선 검출이 실제로는 HoughLines() 함수 안에서 다시 호출하는 HoughLinesStandard()라는 이름의 함수에서 수행되고 있기 때문에 건드려야할 부분이 조금 많다는 점이 귀찮을 뿐입니다. 수정해야할 부분을 패치 파일 형식으로 나타내면 아래와 같습니다.


그리고 실제 텍스트 문서로 된 패치 파일도 첨부합니다.   hough.cpp.patch  imgproc.hpp.patch


OpenCV 소스 코드를 변경했으니 실제로 사용하려면 OpenCV를 다시 빌드해야 합니다. OpenCV 소스 코드를 빌드하는 방법은 4.0.0 기준으로 설명해둔 것이 (아직) 없으니 일단 3.3.0 버전 빌드하는 방법을 보시고 따라하시면 될 것 같습니다. http://kkokkal.tistory.com/1315


빌드가 잘 되었고 DLL 파일이 정상적으로 만들어졌다면 이제 수정된 HoughLines() 함수를 사용하는 방법을 설명하겠습니다. 설명은 길게할 것이 없고, 아래 소스 코드를 참고하세요. :-)


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

using namespace cv;
using namespace std;

int main(void)
{
	Mat src = imread("building.jpg", IMREAD_GRAYSCALE);

	Mat src_edge;
	Canny(src, src_edge, 50, 200);

	vector<Vec2f> lines;
	Mat accum;
	HoughLines(src_edge, lines, 2, CV_PI / 360, 450, 0, 0, 0, CV_PI, accum);

	Mat dst;
	cvtColor(src, dst, COLOR_GRAY2BGR);

	for (size_t i = 0; i < lines.size(); i++) {
		float r = lines[i][0], t = lines[i][1];
		double cos_t = cos(t), sin_t = sin(t);
		double x0 = r * cos_t, y0 = r * sin_t;
		double alpha = 1000;

		Point pt1(cvRound(x0 + alpha * (-sin_t)), cvRound(y0 + alpha * cos_t));
		Point pt2(cvRound(x0 - alpha * (-sin_t)), cvRound(y0 - alpha * cos_t));
		line(dst, pt1, pt2, Scalar(0, 0, 255), 2, LINE_AA);
	}

	Mat accum_norm;
	normalize(accum, accum_norm, 0, 255, NORM_MINMAX, CV_8U);

	imshow("dst", dst);
	imshow("accum_norm", accum_norm);

	waitKey(0);
	return 0;
}

위 소스 코드에서 HoughLines() 함수 맨 마지막 인자로 accum을 지정하였고, 이 행렬은 실수행 행렬입니다. 그러므로 이를 영상 형태로 화면에 나타내려면 normalize() 함수를 이용하여 픽셀 값 범위를 0~255 사이로 변경하고, 타입도 CV_8UC1으로 변경해야 합니다. 그렇게 만들어진 결과가 accum_norm 영상입니다.


실제로 위 코드를 실행하면 아래와 같은 창이 나타납니다.


참 쉽죠? 참고로 accum 행렬은 가로 방향이 rho, 세로 방향이 theta 입니다.


Posted by kkokkal
:

OpenCV 4.0 Beta release and QR code decoder


엊그제 OpenCV 4.0 Beta 버전이 릴리즈되었습니다. OpenCV 4.0 Beta 버전은 아래 링크에서 다운로드 받을 수 있습니다.

https://github.com/opencv/opencv/releases
https://github.com/opencv/opencv_contrib/releases


OpenCV 4.0 Beta 버전의 특징은 https://opencv.org/opencv-4-0-0-beta.html 에 잘 설명되어 있구요.. 아래는 해당 사이트의 설명을 번역한 것입니다.

================================================
OpenCV 4.0 Beta에는 OpenCV 4.0 Alpha보다 29개의 새로운 패치가 포함되었습니다.

* ONNX* (Open Neural Network Exchange) 가져오기 기능이 향상되어 더 많은 토폴로지를 지원합니다.
* OpenCV DNN 샘플 object_detection.py 파일이 올바른 모델 파라미터를 채울 수 있도록 향상되어 사용하기 쉬워졌습니다.
* G-API (Graph API) - 매우 효율적인 영상 처리 파이프 라인 엔진이 opencv_gapi 모듈로 통합되었습니다.
* 무료 QUirc( https://github.com/dlbeer/quirc) 라이브러리에 기반한 빠른 QR 코드 디코더가 통합되었으며, 이를 이용하여 완전한 QR 코드 검출 및 디코딩이 가능합니다. (640x480 해상도에서 20~80FPS).
* AVX2를 사용하는 18개의 함수, 60개 이상의 커널이 가속화되었습니다.
* iGPU용 Kinect Fusion 알고리즘이 가속화되어 고해상도 볼륨(512x512x512)에서 병렬 CPU 버전보다 3배 빨라졌습니다.
================================================


OpenCV 4.0 Alpha 버전에서는 QR 코드 검출 함수만 들어가 있었는데요, Beta 버전에는 검출과 해석 함수 모두 포함되어 있네요. OpenCV 4.0에 들어가는 QR 코드 해석 기능은 QUirc라는 라이브러리를 OpenCV에서 통합한 것입니다.


QR 코드 해석 성능이 어떨까 궁금해서 예제 코드를 만들어 봤습니다.
(2018/11/14 수정: OpenCV 4.0.0 RC 버전에서 QR 코드 관련 API가 변경되어 코드를 새로 업데이트 하였습니다. OpenCV 4.0.0 Beta 버전용 코드는 아래 [더보기]를 클릭하면 볼 수 있습니다.)

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

using namespace cv;
using namespace std;

int main(void)
{
	VideoCapture cap(0);

	if (!cap.isOpened()) {
		cerr <<"Camera open failed!" << endl;
		return -1;
	}

	QRCodeDetector detector;

	Mat frame, gray;
	while (1) {
		cap >> frame;

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

		cvtColor(frame, gray, COLOR_BGR2GRAY);

		vector<Point> points;
		if (detector.detect(gray, points)) {
			polylines(frame, points, true, Scalar(0, 255, 255), 2);

			String info = detector.decode(gray, points);
			if (!info.empty()) {
				polylines(frame, points, true, Scalar(0, 0, 255), 2);
				cout << info << endl;
			}
		}

		imshow("frame", frame);
		if (waitKey(1) == 27)
			break;
	}

	return 0;
}


위 소스 코드는 컴퓨터에 연결된 카메라로부터 프레임을 받아와 QR 코드를 검출하고, QR 코드에 포함된 문자열을 콘솔 명령창에 출력합니다. QR 코드에 노란색 박스가 그려지면 검출만 된거고, 빨간색 박스가 그려지면 해석까지 성공한 상태입니다. 실제로 프로그램을 빌드해서 실행해서 QR 코드를 카메라로 비추면.. 음.. 잘 됩니다. 간간히 몇몇 프레임은 QR 코드를 검출만 하고 해석을 못하는 경우가 생기는데, 제 컴퓨터의 카메라 화질이 너무 안 좋아서 그런건지 라이브러리 성능의 문제인지 명확하지가 않네요.


실제 동작 화면을 캡쳐해서 보여드리면요... 프로그램을 실행해서 아래 QR 코드가 있는 모니터 화면을 카메라로 비추면 콘솔창에 문자열이 출력됩니다.

(화질이 진짜 안 좋죠? :-)


그래도 함수 한 두 개로 QR 코드를 해석할 수 있게 되었네요. 참 쉽네요.. :-)






Posted by kkokkal
:

OpenCV 3.4.2 Jpeg library performance (compare to OpenCV 3.4.0)


OpenCV 3.4.2 버전부터 기본 JPEG 라이브러리가 libjpeg-turbo(ver 1.5.3-62)로 변경되었습니다. 그 전에는 Independent JPEG Group의 JPEG 라이브러리(v9.0b)가 사용되었었죠. libjpeg-turbo 라이브러리는 SIMD를 사용하기 때문에 Independent JPEG Group의 라이브러리보다 더 빠르게 동작한다고 알려져 있습니다. 각각의 라이브러리에 대한 자세한 설명은 홈페이지를 참고하세요.


이미 OpenCV 3.4.3 버전이 나온 시점이지만, 3.4.2의 libjpeg-turbo 라이브러리의 성능 향상이 어느 정도인지 확인해보기 위해 간단한 테스트 프로그램을 만들어보았습니다.


int main(void)
{
	Mat src[10];
	TickMeter tm;

	cout << "OpenCV version: " << CV_VERSION << endl;

	tm.start();
	for (int i = 0; i < 10; i++) {
		String filename = format("in\\test%d.jpg", i);

		src[i] = imread(filename);

		if (src[i].empty()) {
			cerr << "Image load failed!" << endl;
			return -1;
		}
	}
	tm.stop();
	cout << "JPEG load took " << tm.getTimeMilli() << "ms." << endl;

	tm.reset();
	tm.start();
	for (int i = 0; i < 10; i++) {
		String filename = format("out\\data%d.jpg", i);

		bool ret = imwrite(filename, src[i]);

		if (!ret) {
			cerr << "Image save failed!" << endl;
			return -1;
		}
	}
	tm.stop();
	cout << "JPEG save took " << tm.getTimeMilli() << "ms." << endl;

	return 0;
}

위 프로그램 소스는 ./in/ 폴더에 있는 test0.jpg ~ test9.jpg 10 장의 JPEG 영상을 불러와서 다시 ./out/ 폴더에 저장하는, 아주 간단한 소스 코드입니다. 시간 측정은 TickMeter 클래스를 사용하였구요...


위 소스 코드를 OpenCV 3.4.0 버전을 이용하여 빌드하고, 또 다시 OpenCV 3.4.2 버전을 이용하여 빌드하였습니다. OpenCV 라이브러리는 OpenCV 홈페이지에서 미리 빌드된 버전을 사용하였구요, JPEG 사진은 DSLR과 스마트폰으로 찍은 12M, 16M 사진을 사용했습니다. 측정된 시간은 아래와 같습니다.


OpenCV 3.4.2 버전을 사용했을 경우가 OpenCV 3.4.0 버전보다는 빠르긴 한데, 생각보다 훨씬 빠르지는 않네요. 위의 결과를 표로 정리하면 다음과 같습니다.


사실 이 결과는 인터넷에 나와 있는 JPEG turbo의 성능 비교와 너무 차이가 나서 뭔가 이상하다는 생각이 듭니다. 아래 링크에서는 최소 2~3배는 빨라졌는데 말이죠..

https://libjpeg-turbo.org/About/Performance

http://www.briancbecker.com/blog/2010/analysis-of-jpeg-decoding-speeds/


왜 이렇게 성능 향상이 적은지에 대해서는 더 고민을 해봐야할 것 같습니다. 뭔가 추가적인 환경 설정을 한다거나, 빌드 옵션이 뭔가 잘못되었는지는 확인을 더 해봐야겠지만, 어쨋든 기본적인 사용법으로 OpenCV 3.4.2를 사용할 때 이정도의 성능 향상이 있다... 라는 정도의 결론이네요. 뭔가 좀 아쉽네요. ^^;


Posted by kkokkal
:

How to fix freezing when mouse over OpenCV Mat class in Visual Studio 2017


Visual Sutio 2017 최신 버전, 그러니까 정확하게는 VS2017 15.7.x 버전에서 OpenCV 코드를 작성하다보면 마우스가 Mat 클래스 위로 올라갈 때 Visual Studio가 멈추는 현상이 발생합니다. 코드 편집이 불가능한 상태가 되어서 Visual Studio를 죽였다가 다시 실행을 해야 하는데요...


오늘 Visual Studio 2017 15.7.5 버전으로 업그레이드를 하길래 혹시나 고쳐졌나 확인해봤지만, 여전하네요. ㅎㅎ


이 현상은 Visual Studio에서 사용하는 IntelliSense 기능때문에 발생합니다. 그러므로 간단하게는 IntelliSense 기능을 끄면 Visual Studio 2017이 멈추는 현상은 발생하지 않습니다. IntelliSense 기능을 끄려면 메뉴에서 [도구] -> [옵션] / [텍스트 편집기] -> [C/C++] -> [고급] 선택 후 IntelliSense의 [자동 요약 정보]를 false로 설정하면 됩니다.


그런데 경우에 따라서는 IntelliSense 기능을 달랑 Mat 문제 때문에 끄는 것이 아쉬울 때도 있습니다. 그런 경우라면 OpenCV 소스 코드에서 Mat 클래스 주석 부분을 일부 삭제하는 방법을 사용할 수도 있습니다.


Mat 클래스는 <opencv-src>/include/opencv2/core/mat.hpp 파일에 정의되어 있습니다. 이 파일에서 Mat 클래서 정의 바로 위에 엄청나게 긴 주석이 적혀 있는데, 이 주석을 IntelliSense가 해석하다가 뻗어버리는 것으로 판단이 되네요. 그러므로 이 주석의 대부분을 과감히 삭제하면 멈추는 현상이 발생하지 않습니다. 아래 그림을 보시죠.


원래 Mat 클래스 주석이 (OpenCV 3.4.0 기준) 588라인부터 778라인까지 작성되어 있었는데요, 위 그림처럼 대부분을 지워버리는 겁니다. 그러고나서 OpenCV 소스 코드에서 Mat 클래스 위에 마우스를 올려놓으면 간략하된 Mat 주석만 풍선도움말처럼 화면에 나타납니다.


참 쉽죠? :-)






Posted by kkokkal
:


안드로이드에서 OpenCV를 이용하여 앱을 제작하는 방법을 설명하는 문서입니다.


예전에 패스트캠퍼스의 "OpenCV와 함께하는 컴퓨터 비전 프로그래밍 캠프" 강의에서 진행했던 내용입니다만, 현재는 커리큘럼에서 제외한 상태이구요...


예전에 정리했던 내용을 최신 Android Studio 기준에 맞게 일부 수정하여 배포합니다.




Posted by kkokkal
:

얼마전에 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
:

OpenCV 3.2 버전부터 FreeType 모듈을 지원합니다. FreeType 모듈은 말 그대로 OpenCV에서 Freetype 라이브러리를 활용할 수 있게 도와주는 클래스이며, 이를 이용하면 영상에 다양한 폰트의 영문 및 한글을 적을 수 있습니다. 아래 그림은 lenna 영상에 바탕체 글꼴을 이용하여 영문과 한글 문자열을 출력한 예제입니다.



Freetype 모듈은 OpenCV Extra module에 정의되어 있기 때문에 opencv_contrib 소스 코드를 함께 빌드해야 사용할 수 있습니다. 그런데 Freetype 모듈은 opencv_contrib 소스 코드를 가지고 있다고 해서 자동으로 빌드가 되는 것이 아니라, Freetype과 HarfBuzz 라는 이름의 외부 라이브러리를 미리 빌드하고 설정해두어야 만들어집니다. 이 포스트에서는 OpenCV에서 Freetype 모듈을 빌드하는 방법과 실제로 사용하는 방법을 설명합니다. 본문의 순서는 다음과 같습니다.


(1) Freetype 라이브러리 빌드하기
(2) HarfBuzz 라이브러리 빌드하기
(3) Freetype 모듈을 포함한 OpenCV 라이브러리 빌드하기
(4) OpenCV에서 Freetype 모듈 사용하기


(1) Freetype 라이브러리 빌드하기


"FreeType is a freely available software library to render fonts."
Freetype은 폰트를 렌더링할 수 있는 소프트웨어 라이브러리 입니다. 즉, 폰트 파일을 해석하여 프로그램에서 사용할 수 있게 도와줍니다. Freetype 라이브러리의 홈페이지는 https://www.freetype.org/ 이고, 아래 링크에서 다양한 버전의 Freetype 소스 코드를 다운로드 받을 수 있습니다.


https://download.savannah.gnu.org/releases/freetype/


여러가지 버전 중에서 여기서 사용할 freetype 버전은 2.8.1 입니다. 현재 Freetype 최신 버전은 2.9 입니다만 2.9 버전 소개가 new 'minor' series 라고 되어 있는 것이 조금 찝찝해서 그 다음 최신 버전인 2.8.1을 사용했습니다. 아마도 리눅스 커널 버전처럼 홀수와 짝수를 구분하는 것과 같은 맥락일까요? 여하튼 위 링크에서 freetype-2.8.1.tar.bz2 파일을 다운로드 받으시면 됩니다.

일단 freetype 소스 코드를 다운로드 받았으면 빌드 작업을 수행하여 lib 파일을 생성해야 합니다. 이를 위해 폴더 구조를 다음과 같이 만들었습니다.


C:\freetype\build
           \freetype-2.8.1


위의 폴더 구조에서 freetype-2.8.1 폴더는 freetype-2.8.1.tar.bz2 압축을 풀면서 만들어진 폴더이고, build 폴더는 빌드 작업을 위해 직접 만든 폴더입니다. OpenCV 라이브러리를 빌드할 때와 마찬가지로 freetype 소스를 빌드하기 위해서는 Visual Studio 2017 솔루션 파일을 생성해야 합니다. 이 작업을 CMake GUI 버전 프로그램을 이용할 수도 있지만, 여기서는 좀 더 간단하게 command line 명령어를 사용하겠습니다. 일단 도스창(command window)을 실행한 후 C:\freetype\build 폴더로 이동합니다. 그리고 이 폴더에서 다음 명령어를 입력합니다. (CMake 폴더가 시스템 패스에 설정되어 있어야 합니다.)


cmake -DWITH_ZLIB=OFF -DWITH_BZip2=OFF -DWITH_PNG=OFF -G "Visual Studio 15 2017 Win64" ..\freetype-2.8.1



위 명령어에서 WITH_ZLIB, WITH_BZip2, WITH_PNG 항목을 OFF로 설정하지 않으면 나중에 OpenCV 라이브러리의 Freetype 모듈을 빌드할 때 에러가 발생합니다. 그러므로 위와 같이 명령어를 입력하여 freetype.sln 파일을 생성하였습니다. 이제 Visual Studio 2017에서 freetype.sln 파일을 불러와서 빌드 작업을 수행합니다.

빌드 작업은 Debug와 Release 모드로 각각 수행하고, 전체 솔루션 빌드를 하고 난 후에는 INSTALL 프로젝트만 또 따로 빌드합니다. 그러면 C:\Program Files\freetype\ 폴더 아래에 헤더 파일과 라이브러리 파일이 모이게 됩니다. 그리고 시스템 환경 변수에 FREETYPE_DIR 이름으로 C:\Program Files\freetype 폴더를 지정하세요.


참고로 Windows 환경에서 freetype 라이브러리를 직접 사용하는 방법은 SoEn 사이트의 강좌를 참고하세요. http://soen.kr/ 사이트에서 왼쪽 강좌 메뉴의 [라이브러리]를 선택한 후, 오른쪽 상단 메뉴 중에서 [FreeType] 메뉴를 선택하여 한 번 읽어보시기를 권장합니다.


(2) Harfbuzz 라이브러리 빌드하기


"HarfBuzz is an OpenType text shaping engine."
HarfBuzz는 오프타입 테스트 쉐이핑 엔진이며, 홈페이지 주소는 https://www.freedesktop.org/wiki/Software/HarfBuzz/ 입니다. HarfBuzz 소스 코드는 다음 링크에서 다운로드 받을 수 있습니다.


https://www.freedesktop.org/software/harfbuzz/release/


여기에 나열된 소스 파일 중에서 우리는 harfbuzz-1.7.2.tar.bz2 파일을 사용할 것입니다. HarfBuzz 1.7.3 이상 버전을 가지고 CMake 작업을 하려고 하면 이상한 에러가 발생하기 때문입니다. 사실 OpenCV에서는 아주 단순한 기능만을 사용할 것이기 때문에 굳이 최신 버전의 freetype & harfbuzz 소스 코드를 사용하지 않아도 된다고 생각합니다. 그래도 너무 옛날 것을 사용하는 것은 좀 찜찜하니까 그나마 제가 동작을 확인한 최신 소스(harfbuzz-1.7.2.tar.bz2)를 사용할 것을 권장합니다.


Harfbuzz 소스 코드도 아래와 같은 폴더 구조를 만들어서 압축을 해제합니다.


c:\harfbuzz\build
           \harfbuzz-1.7.2


Harfbuzz 소스 코드에 대해 Visual Studio 2017 솔루션 파일을 만드는 작업은 CMake GUI 버전을 사용하겠습니다. CMake-GUI 프로그램에서 "Where is the source code:" 항목에는  c:\harfbuzz\harfbuzz-1.7.2 폴더를 지정하고, "Where to build the binaries:" 항목은 c:\harfbuzz\build 폴더를 지정하세요. 그리고 하단의 [Configure] 버튼을 클릭하면 다음과 같은 화면이 나타납니다.



여러가지 항목 중에서 HB_HAVE_FREETYPE 항목을 선택하세요. 나머지는 기본값을 그대로 사용할 것입니다. 그리고 다시 한 번 [Configure] 버튼을 클릭합니다. 그러면 위 그림에서 빨간색으로 표시되는 것들이 모두 흰색 배경 글씨로 바뀌게 됩니다. 이 상태에서 상단의 [Advanced] 항목을 체크하면 아래와 같이 freetype 관련 폴더가 자동으로 설정이 되는 것을 확인할 수 있습니다.



위와 같이 설정이 되었다면 추가로 변경할 것이 없으므로 그대로 [Generate] 버튼을 클릭하셔도 됩니다. CMake 창 맨 아래에 "Generating done" 메시지가 나타나면 [Open Project] 버튼을 클릭하여 Visual Studio 2017이 자동으로 실행되게 하십시오. 그리고 앞서 freetype 라이브러리를 빌드할 때와 마찬가지로 Debug & Release 모드로 각각 솔루션 빌드를 수행하고, 또한 INSTALL 프로젝트에 대해서만 따로 빌드 작업을 수행하세요.


그러면 C:\Program Files\harfbuzz\ 폴더 아래에 HarfBuzz 관련 헤더 파일과 라이브러리 파일이 생성됩니다. (혹시 INSTALL 프로젝트 빌드 시 권한 관련 에러가 발생한다면 Visual Studio 2017을 관리자 권한으로 실행하여 작업을 수행하세요.)


이제 시스템 환경변수에 HARFBUZZ_DIR 변수를 등록하고, 그 값을 C:\Program Files\harfbuzz 폴더로 지정하십시오.



(3) Freetype 모듈을 포함한 OpenCV 라이브러리 빌드하기


이제 OpenCV를 (새로) 빌드할 차례입니다. 혹시 OpenCV 빌드를 해본 적이 없거나 빌드 방법에 대해 익숙하지 않다면 먼저 아래 포스팅을 먼저 보고 빌드 방법을 익히신 후 따라하시기 바랍니다.


http://kkokkal.tistory.com/1315


OpenCV 라이브러리를 빌드하는 전체적인 방법은 위 링크의 동영상 설명을 그대로 따릅니다. 다만 이번 포스팅에서 사용하는 OpenCV 버전이 3.4.0이라는 점이 바뀌었고, 또한 Freetype 모듈 빌드를 위해 추가적인 작업이 필요하다는 점만 주의하시면 됩니다.


일단 github 사이트에서 opencv-3.4.0.zip 파일과 opencv_contrib-3.4.0.zip 파일을 다운로드 받고, 폴더 구조를 아래와 같이 설정합니다. (이전 포스팅에서는 build 대신 mybuild 폴더명을 사용했습니다만, 이제는 build 라는 폴더 이름을 사용합니다.)


c:\opencv\build
         \opencv-3.4.0
         \opencv_contrib-3.4.0


이후 CMake GUI 프로그램에서 수행할 작업은 http://kkokkal.tistory.com/1315 포스트에 있는 동영상과 크게 다르지 않습니다. 사실 변경점이 아예 없다고 봐도 됩니다. 다만 CMake 프로그램으로 작업을 하기 전에 freetype 모듈과 관련된 CMakeList.txt 파일을 일부 수정해야합니다. 일단 c:\opencv\opencv_contrib-3.4.0\modules\freetype\ 폴더에 있는 CMakeLists.txt 파일을 텍스트 편집기로 열어서 아래와 같이 수정합니다. (freetype 모듈의 CMakeLists.txt 수정 방법은 다음 링크를 참고했습니다: https://gist.github.com/UnaNancyOwen/14c72a3f10a46d41c359ab6ea307a1d2)



실제로 제가 사용한 CMakeLists.txt 파일을 아래에 첨부하였으니 참고하세요.

CMakeLists.txt


이후에 OpenCV 라이브러리를 빌드하는 작업은 앞서 소개한 포스팅의 동영상과 동일하게 진행하시면 됩니다. 다만 CMake 화면을 잘 살펴보면 아래 그림과 같이 BUILD_opencv_freetype 항목이 선택되어 있는 것을 확인하실 수 있습니다.



(4) OpenCV에서 Freetype 모듈 사용하기

이제 OpenCV 라이브러리에 포함된 Freetype 모듈을 사용하는 예제를 만들어보겠습니다. Freetype 모듈에서 핵심이 되는 클래스는 cv::freetype::FreeType2 클래스이며, 이 클래스에 대한 자세한 설명은 아래 링크를 참고하세요.

https://docs.opencv.org/master/d9/dfa/classcv_1_1freetype_1_1FreeType2.html


위 링크에 있는 내용을 참고하여 만든 예제 프로젝트의 소스 코드는 다음과 같습니다.


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

using namespace cv;
using namespace cv::freetype;
using namespace std;

int main(void)
{
	Mat src = imread("lenna.bmp", IMREAD_COLOR);

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

	// FreeType2 객체 생성
	Ptr<Freetype2> ft2 = createFreeType2();

	// 바탕체 글꼴 불러오기
	ft2->loadFontData("c:\\windows\\fonts\\batang.ttc", 0);

	// 문자열 출력
	ft2->putText(src, u8"Hello?", Point(50, 50), 50, Scalar(255, 255, 255), -1, LINE_AA, false);
	ft2->putText(src, u8"안녕하세요!", Point(50, 120), 50, Scalar(0, 255, 255), -1, LINE_AA, false);

	imshow("src", src);
	waitKey(0);
	return 0;
}



위 코드는 매우 단순해서 OpenCV 코딩을 해보신 분이라면 그리 어렵지 않게 해석하실 수 있을 겁니다. 다만 출력할 문자열 "안녕하세요!" 앞에 UTF-8 인코딩을 의미하는 리터럴 u8을 붙여서 u8"안녕하세요!" 라고 입력한 것을 주의깊게 살펴보시면 될 것 같습니다. 이 소스 코드를 빌드하여 실행한 결과는 아래와 같습니다. (Visual Studio에서 OpenCV 소스 코드를 빌드하는 방법은 다른 블로그 또는 https://youtu.be/ptvnUCT7wEQ 링크의 동영상 뒷부분 내용을 참고하세요.)



이로써 이제 OpenCV에서도 이쁜 폰트를 이용하여 한글, 일어, 중국어 등을 출력할 수 있게 되었습니다. 설정이 조금 복잡하다고 느낄 수도 있습니다만, 그리 어렵지 않으니 한번 테스트해보시기 바래요~~ :-)


Posted by kkokkal
:

OpenCV 3.4.1 릴리즈

Study/OpenCV 2018. 2. 27. 00:03 |

(3일 전에) OpenCV 3.4.1 버전이 배포되었습니다.


https://github.com/opencv/opencv/releases/tag/3.4.1

https://github.com/opencv/opencv_contrib/releases/tag/3.4.1


자세한 릴리즈 노트는 없지만, DNN 관련된 기능에 대한 많은 패치가 적용이 된 것 같고, 소스 코드 주석의 오타도 상당히 많이 교정이 되었습니다.


그나저나 벌써 OpenCV 4.0에 대한 이야기가 돌고 있는 것 같습니다. 7월 중순에 릴리즈 목표인 것 같고, 그 전에 Alpha가 됐든 Beta가 됐든 프리뷰 버전도 나올 것 같네요. 2.x 버전에서 3.x 버전까지 5~6년이 걸렸는데, 4.x 버전은 엄청 빠르게 진행되고 있는 것 같습니다.

Posted by kkokkal
: