Window 10에서 OpenCV 3.1.0을 설치하여 Visual Studio 2019에 라이브러리를 포팅해 설치 확인 테스트까지 진행해보겠습니다.

 

 

1. OpenCV 3.1.0 Version 파일 설치

 

 

   - 구글에 OpenCV를 검색하시면 가장 상단에 공식 홈페이지가 나옵니다.

     (www.opencv.org)

 

구글에 OpenCV 검색

 

 

   - 홈페이지에 접속하면 아래와 같이 나오게 되며, 홈페이지 가장 하단에 Source Forge를 찾아 클릭합니다.

 

Source Forge 클릭

 

 

  - 설치하고 싶은 OpenCV Version를 찾습니다. (본 블로그에선 Window에 맞는 OpenCV 3.1.0 Version을 설치합니다.)

 

 

 

 

  - 설치 파일을 받은 후 경로를 지정하여 설치를 진행합니다.

 

 

 

 

  2. 환경 변수 설정

 

   - 키보드에서 윈도우+pause를 누르거나 검색하여 시스템 속성 창을 켜서 환경 변수를 클릭합니다.

 

 

 

  - 환경 변수에서 하단의 시스템 변수 속의 path를 찾아 아래와 같이 설치한 OpenCV에서의 파일 경로를 입력합니다.

 

 

 

 

3. Visual Studio

 

 - Visual Studio를 켜서 프로젝트를 생성합니다.

 - 프로젝트를 누른 뒤 alt + enter을 누르거나 상단 카테고리에서 프로젝트의 속성 페이지 창 찾아 띄웁니다.

 - 아래와 같이 설치한 OpenCV 경로에 맞춰 입력시켜줍니다(C/C++ - 일반, 링커 - 일반, 입력)

 

 

 

  - OpenCV 라이브러리가 잘 포팅되었는지 확인하도록 아래의 코드를 입력하여 이미지를 띄워봅니다.

    (.raw 파일이 아닌 png, jpg, jpeg, bmp 등의 포맷 형태의 이미지를 사용하시면 됩니다.)

 

 

 

- 만약 다음과 같은 에러가 발생한다면 에러 아래의 이미지를 따라해주세요.

- 해당 dll 파일을 OpenCV 폴더 속에서 찾아 Visual Studio 프로젝트의 경로에 복사해주세요.

 

 

 

  - 다시 위의 코드를 컴파일하면 경로에 맞는 이미지가 출력되는걸 확인할 수 있어, OpenCV 라이브러리가 잘 포팅되었다는 것을 알 수 있습니다.

 

* 위 글은 임시적으로 작성된 글이며, 추후에 다시 정리할 예정입니다.

 

 

Window 10에서 Tensorflow 1.14와 Object Detection API를 설치

 

 

1. Window 10에서 아나콘다 설치 

   - Anaconda Python 3.7 버전 설치

   * 아나콘다 홈페이지 참고 
www.anaconda.com/products/individual

 

Anaconda | Individual Edition

Anaconda's open-source Individual Edition is the easiest way to perform Python/R data science and machine learning on a single machine.

www.anaconda.com

 

2. TensorFlow GPU

 

필요조건 

NVIDIA GeForce Graphics 630
CUDA Toolkit v10.0
CuDNN 7.6.5 ( CuDNN v7.6.5(Nov 5, 2019))
Anaconda with Python 3.7

* CUDA와 CuDNN은 NVIDIA 홈페이지 참고 // CuDNN v7.6.5(Nov 5, 2019) 설치

* 회원가입 후 설치파일 설치 가능

CUDA : developer.nvidia.com/cuda-10.0-download-archive?target_os=Windows&target_arch=x86_64&target_version=10&target_type=exenetwork

 

CUDA Toolkit 10.0 Archive

Select Target Platform Click on the green buttons that describe your target platform. Only supported platforms will be shown. Operating System Architecture Distribution Version Installer Type Do you want to cross-compile? Yes No Select Host Platform Click

developer.nvidia.com

CuDNN : developer.nvidia.com/compute/machine-learning/cudnn/secure/7.6.5.32/Production/10.0_20191031/cudnn-10.0-windows10-x64-v7.6.5.32.zip

* 설치 파일 압축을 푼 뒤 CuDNN 파일 속 "cuda" 파일을 해당 경로에 복사

"<INSTALL_PATH>\NVIDIA GPU Computing Toolkit\CUDA\v10.0\"

<INSTALL_PATH>는 CUDA가 설치된 경로를 말함

 

 

* GPU가 동일하지 않다면 GPU와 호환되는 CUDA를 찾고 CUDA 호환되는 CuDNN의 버전을 찾아서 설치해야 함.

* TensorFlow은 버전에 따라서 동작되지 않는 상황이 빈번하기 때문에 처음 설치 시 설치 안내 블로그를 찾아 참고 추천

 

 

3. 환경변수 

 - 키보드에서 윈도우+Pause Break 입력

 - 고급 시스템 설정

 - 환경 변수

 - 시스템 변수 안에서 PATH를 찾아 클릭

 - 하단과 같이 작성

    * 본인이 설치한 경로에 맞게 작성해야 함

 

<INSTALL_PATH>\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin

<INSTALL_PATH>\NVIDIA GPU Computing Toolkit\CUDA\v10.0\libnvvp

<INSTALL_PATH>\NVIDIA GPU Computing Toolkit\CUDA\v10.0\extras\CUPTI\libx64

<INSTALL_PATH>\NVIDIA GPU Computing Toolkit\CUDA\v10.0\cuda\bin

 

4. 가상 환경 생성

 

   - cmd창에서 anaconda prompt (Anaconda3) 검색 후 실행

   - 아래 커맨트 타이핑

conda create -n tensorflow_cpu pip python=3.7
activate tensorflow_gpu

 

다음과 같이 왼쪽에 가상환경 실행 확인

(tensorflow_gpu) C:...

 

pip install --upgrade tensorflow-gpu==1.14

 

설치된 텐서플로우 버전 확인

python

>>> import tensorflow as tf
>>> tf.__version__

 

5. 텐서플로우 모델 설치

 

필요 조건

pillow 6.2.1
lxml 4.41
jupyter 1.0.0
matplotlib 3.1.1
opencv 3.4.2
pathlib 1.0.1
pip install <package_name>(=<version>)

* opencv 설치 시 설치가 되지 않으면 opencv 대신 opencv-python으로 작성

 

 

텐서플로우 모델 설치

github.com/tensorflow/models/tree/r1.13.0

 

tensorflow/models

Models and examples built with TensorFlow. Contribute to tensorflow/models development by creating an account on GitHub.

github.com

설치 후 하단과 경로가 같은지 확인

TensorFlow
└─ models
    ├── official
    ├── research
    ├── samples
    └── tutorials

 

Protobuf 설치/편집

 

설치 사이트

버전 : protoc-3.11.0-win64.zip

github.com/protocolbuffers/protobuf/releases

 

Releases · protocolbuffers/protobuf

Protocol Buffers - Google's data interchange format - protocolbuffers/protobuf

github.com

설치 후 환경변수 PATH에 경로 추가

<PATH_TO_PB>\Google Protobuf

 

* 사용하던 터미널을 종료하고 새로운 터미널을 켜서 하단 커맨드 입력

# From within TensorFlow/models/research/
protoc object_detection/protos/*.proto --python_out=.
# From within TensorFlow/models/research/
pip install .

 

6. COCO API 설치

pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI

* Visual C++ 2015가 설치되어있어야함

 

7. 테스트

# From within TensorFlow/models/research/object_detection
jupyter notebook

www.youtube.com/watch?v=COlbP62-B-U&feature=youtu.be&t=7m23s

 

위 과정은 하단 사이트를 참고하여 본인이 설치한 과정을 작성함

tensorflow-object-detection-api-tutorial.readthedocs.io/en/tensorflow-1.14/install.html

 

Installation — TensorFlow Object Detection API tutorial documentation

Install Anaconda Python 3.7 (Optional) Although having Anaconda is not a requirement in order to install and use TensorFlow, I suggest doing so, due to it’s intuitive way of managing packages and setting up new virtual environments. Anaconda is a pretty

tensorflow-object-detection-api-tutorial.readthedocs.io

 

 

 

오늘은 영상 속의 특징점(Keypoint)를 검출할 수 있는 Harris Corner에 대해 알아보겠습니다.

 

1998년도에 발표된 Harris Corner는 1980년도에 발표된 Moravec's Corner의 방법을 보안한 알고리즘으로서,

영상에서 코너의 특징점을 찾는 것입니다. 간략하게 말하자면 아래 그림과 같이 작은 영역을 이동시키며,

이동된 영역과 비교하여 얼마나 변화했는지 찾는 것입니다.

 

 

출처 : https://darkpgmr.tistory.com/131

 

아래 그림과 같이 이동되기 전과 이동된 영역의 변화의 차이인 R이 0보다 작으면 엣지(Edge), 둘다 0에 가까우면

플렛(Flat), 0보다 크면 코너점이 됩니다.

 

출처 : https://darkpgmr.tistory.com/131

 

 * 위 설명은 수학적 과정에 대한 언급 없이 표면적으로 간단하게 설명한 것입니다. 수학적인 전체의 과정은 추후에
충분히 이해한 뒤 내용을 추가해 작성하도록 하겠습니다.

 

 

 

아래 코드는 Opencv에서 제공하는 라이브러리 속 함수인 cornerHarris()를 사용한 예시입니다.

 

* 본 코드는 Opencv 3.1.0 Version에서 사용하였습니다.

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

using namespace cv;
using namespace std;

// Harris Corner thresh
int thresh = 120;

int main()
{
	Mat img = imread("D:\\sea.jpg");
	Mat gray;

	// Image resize
	resize(img, img, Size(500, 500), 0, 0, INTER_LANCZOS4);

	Mat img_copy = img.clone(); // 원본 이미지 복사
	Mat show_img = img.clone(); // 원본 이미지 복사

	// Grayscale
	cvtColor(img, gray, CV_BGR2GRAY);

	Mat harris_c;
	Mat harris_norm;
	Mat cs_abs;

	harris_norm = Mat::zeros(gray.size(), CV_32FC1);
	
	// Harris Corner
	// cornerHarris(입력 이미지(Grayscale), 출력 이미지, 인접 픽셀 크기(Blocksize), Sobel ksize, Harris parameter, 픽셀 보간법)
	cornerHarris(gray, harris_c, 2, 3, 0.05, BORDER_DEFAULT);

	// 정규화(Normalizing)
	// normalize(입력 이미지, 출력 이미지, normalize range(low), normalize range(high), 픽셀 보간법) 
	normalize(harris_c, harris_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());

	// 미분한 결과에 절대값을 적용하여 8bit의 unsigned int형으로 바꾸어 표현
	convertScaleAbs(harris_norm, cs_abs);

	// Drawing a circle around corners
	for (int j = 0; j < harris_norm.rows; j += 1)
		for (int i = 0; i < harris_norm.cols; i += 1)
			if ((int)harris_norm.at<float>(j, i) > thresh)
				circle(img_copy, Point(i, j), 7, Scalar(255, 0, 255), 0, 4, 0);

	imshow("Original Image", show_img);
	imshow("convertScaleAbs", cs_abs);
	imshow("Harris Corner Detection", img_copy);

	waitKey(0);
}

Original Image

 

cornerHarris() to convertScaleAbs()

 

Harris Corner Detection (코너점을 마젠타색 원으로 표현)

 

Harris Corner Detection은 영상의 평행이동, 회전변화에는 불변이고, affine 변화, 조명 변화에도 어느정도 강인한

특성을 가지고 있지만 영상의 크기 변화에는 민감함을 보입니다.

 

 

 

 

< 참고 및 인용 자료 >

 

1) https://darkpgmr.tistory.com/131

 

영상 특징점(keypoint) 추출방법

영상 특징점이 무엇이고 어떻게 뽑는지, 그리고 대표적인 방법에는 어떤 것들이 있는지 정리해 봅니다. 1. 영상 특징점이란? 2. Harris corner [1988] 3. Shi & Tomasi [1994] 4. SIFT - DoG [2004] 5. FAST [2006..

darkpgmr.tistory.com

2) http://egloos.zum.com/eyes33/v/6097465

 

Corner 검출 #1- Harris corner detector

이미지에서 특정 물체를 인식하거나, 추적할때 물체를 특징짖을 수 있는 주요 특징점을 매칭 시키면 쉽게 인식하거나, 추적할 수 있다. Harris Corner는 1980년 Moravec 의 아이디어를 수정 보완한것이다. Moravec은 작은 윈도우를 수직, 수평, 좌대각선, 우대각선 4개 방향으로 1 픽셀씩 이동시켰을 때의 변화하는 intensity 의

egloos.zum.com

3) https://leechamin.tistory.com/293

 

[OpenCV] 05-2. Harris Corner Detection

< Harris Corner Detection > " style="clear: both; font-size: 2.2em; margin: 0px 0px 1em; color: rgb(34, 34, 34); font-family: "Roboto Condensed", Tauri, "Hiragino Sans GB", "Microsoft YaHei",..

leechamin.tistory.com

 

 

어떠한 프로젝트를 진행하면서 픽셀의 값을 이용한 알고리즘으로 접근할 때, 이미지 전체가 아닌 특정 영역의 픽셀 값의

정보를 알고 싶은 경우가 있었습니다. 하지만 제가 아는 것은 이미지 전체의 픽셀에 접근하여 정보를 추출하거나 캡쳐

 

도구를 통해 수작업으로 이미지를 잘라서 처리하는 방법 뿐이여서 불편함을 많이 느꼈습니다.

 

오늘은 제가 느꼈던 불편함을 해소할 수 있는 방법으로 마우스 이벤트인 setMouseCallback 함수를 이용하여,

 

이미지 속에서 직접 지정한 특정 영역의 이미지와 픽셀 값의 정보를 추출하는 방법에 대해 소개하려합니다.

 

 

 

마우스 이벤트는 사용자가 함수를 설계하여 처리할 수 있습니다.

 

여기서 중요한 부분은 인터럽트처럼 사용자가 설계한 함수에서의 마우스 이벤트 발생했을 때

 

바로 처리가 가능하도록 콜백 함수(Event Handler)를 만들어 함수를 setMouseCallback()에 등록하는 겁니다.

 

 

setMouseCallback 함수에 대해 알아보겠습니다.

setMouseCallback 함수 설명

 

 

코드를 통해 살펴보도록 하겠습니다.

 

아래 코드는 입력된 이미지 창에서 마우스 이벤트인 setMouseCallback 함수를 이용하여 마우스를 통해 박스를 그리고

그려진 박스 영역의 이미지를 추출해 Grayscale하여 저장한다.

(마우스는 왼쪽 버튼을 누르면 박스가 그려지는 중이 되며 뗐을 때 완전한 박스가 그려진다.

 

또한, Grayscale이 적용된 이미지에서 픽셀 정보를 읽어 생성된 텍스트에 입력시켜 저장한다. 추가적인 옵션으로 이미지

창에서 키보드의 SPACE를 누를 때 그려진 박스들이 사라지고 EXC를 누르면 프로그램에 종료된다.

 

* 본 코드는 Opencv 3.1.0 Version에서 사용하였습니다.

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void onMouse(int x, int y, int flags, int, void *param);      // 마우스 콜백 함수
void img_save(Mat img); // 이미지, 텍스트 저장

int x_1, x_2, y_1, y_2; // 그린 박스의 네 꼭짓점 좌표
int draw_start; 
int draw_save;
int index = 1;

int main()
{
	Mat image = imread("D:\\test.jpg");
	Mat image_copy;
	Mat crop_img;
	Mat img_backup;

	int pre_num = 0;
	int r, g, b; //RGB 색상

	resize(image, image, Size(500, 500), 0, 0, CV_INTER_LANCZOS4);
	img_backup = image.clone();

	while (1){
		// 원복 복사(박스가 자연스럽게 그려지는 것을 보여주기 위함)
		image_copy = image.clone();

		//박스 색상(그리는 중)
		r = 0;
		b = 255;
		g = 0;

		// 박스 좌측 상단에서 우측 하단으로 그리기
		if (x_1 < 0)
			x_1 = 0;
		if (x_2 > image_copy.cols)
			x_2 = image_copy.cols;
		if (y_1 < 0)
			y_1 = 0;
		if (y_2 > image_copy.rows)
			y_2 = image_copy.rows;

		// 박스 그리기
		if (draw_start == 1 && draw_save == 0)
			rectangle(image_copy, Point(x_1, y_1), Point(x_2, y_2), Scalar(b, g, r));
		else if(draw_start == 1 && draw_save == 1){	

				// 박스를 자연스럽게 그리기 위함
				if (x_1 > x_2) {
					pre_num = x_2;
					x_2 = x_1;
					x_1 = pre_num;
				}
				if (y_1 > y_2) {
					pre_num = y_2;
					y_2 = y_1;
					y_1 = pre_num;
				}

				// 이미지 저장 함수
				img_save(img_backup);

				// 초기화
				draw_start = 0;
				draw_save = 0;

				index++;

				// 박스 색상(그려진)
				r = 255;
				g = 0;
				b = 0;

				rectangle(image, Point(x_1, y_1), Point(x_2, y_2), Scalar(b, g, r));

				// 이미지 추출
				crop_img = img_backup(Range(y_1, y_2), Range(x_1, x_2));
				cvtColor(crop_img, crop_img, CV_RGB2GRAY);

				imshow("선택 영역", crop_img);
		}
		
		// 창에 텍스트 세기기
		putText(image, "Space : Delete all box", Point(10, 15), FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255), 2);
		putText(image, "  ESC : End of Program", Point(10, 35), FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255), 2);
		 

		imshow("Original", image_copy);
		setMouseCallback("Original", onMouse, 0);

		if (waitKey(10) == 32)
			image = img_backup.clone(); // 스페이스를 누를 시 그려진 박스 없앰

		if (waitKey(5) == 27) // ESC를 누를 시 종료
			exit(0);
	}
	//waitKey(0);
}

void img_save(Mat img)
{
	FILE *pixel;

	Mat save;

	char buf[256]; // 이미지 저장 경로 버퍼
	char buf2[256]; // 이미지 저장 경로 버퍼
	int pixel_info = 0;

	save = img(Range(y_1, y_2), Range(x_1, x_2));
	cvtColor(save, save, CV_RGB2GRAY);
	sprintf(buf, "D:\\%d.jpg", index);
	imwrite(buf, save);

	//픽셀 값 텍스트에 저장
	sprintf(buf2, "D:\\%d.txt", index);
	pixel = fopen(buf2, "w");

	fprintf(pixel, "이미지 사이즈(가로,세로)\n\n", save.cols, save.rows);
	fprintf(pixel, "%dx%d\n\n", save.cols, save.rows);

	for (int y = 0; y < save.rows; y++){
		for (int x = 0; x < save.cols; x++){
			pixel_info = save.at<uchar>(y, x);
			fprintf(pixel, "%03d ", pixel_info);
		}
		fprintf(pixel, "\n");
	}
	fclose(pixel);
}
void onMouse(int event, int x, int y, int flags, void * param)
{
	switch (event) //switch문으로 event에 따라 버튼 종류를 구분
	{
	case EVENT_MOUSEMOVE: // 마우스 이동
		x_2 = x;
		y_2 = y;
		break;

	case EVENT_LBUTTONDOWN:   // 마우스 왼쪽 버튼 누를 때
		x_1 = x;
		y_1 = y;
		draw_start = 1;
		break;

	case EVENT_LBUTTONUP:    // 마우스 왼쪽 버튼 뗄 때
		draw_save = 1;
		break;
	}
}

원본 이미지
영역을 지정하는 중 (파란색 박스)
지정된 영역(빨간색)
추출된 지정 이미지와 픽셀 정보(GrayScale이 적용됨)

 

 

 

추가적으로 본 코드의 onMouse 함수를 보게 되면 여러 인자가 들어가게 된다.

 

인자 값은 setMouseCallback를 통해서 정보를 가져온 것들이며, 자세한 내용은 아래와 같다.

 

 

 

마우스 이벤트 옵션는 아래와 같으니 필요 상황에 맞춰 사용하시면 된다.

 

 

 

위 표의 정보는 아래의 참고 문헌을 인용하여 작성하였습니다.

 

 

< 참고 문헌 >

 

정성환,배종욱 지음. 2017년. OpenCV로 배우는 영상 처리 및 응용. 생능출판사

 

 

 

동영상을 입력받아 전처리를 하여 동영상으로 저장하는 방법을 알아보도록 하겠습니다.

 

동영상을 저장하기 위해선 Opencv의 클래스인 VideoWriter를 사용해야합니다.

 

또한 저장시킬 동영상의 코덱, 프레임, 영상의 크기 등의 정보를 정해야 합니다.

 

 

 

아래 코드는 영상을 입력받아 크기를 500x500으로 줄이고 RGB에서 Grayscale을 적용한 뒤

 

동영상으로 저장하는 과정입니다. 

 

* 본 코드는 Opencv 3.1.0 Version에서 사용하였습니다.

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

using namespace cv;
using namespace std;


int main()
{
	Mat img;
	Mat pre_p;

	VideoCapture capture("D:\\ship.mp4"); // 입력 영상

	double fps = 35; // 영상 프레임
	int  fourcc = VideoWriter::fourcc('D', 'X', '5', '0'); // 코덱 설정


	VideoWriter  save;

	//save.open(입력 영상, 코덱, 프레임, 영상 크기, 컬러)
	save.open("D:\\save_Video.avi", fourcc, fps, Size(500, 500),0);

	while (1) {
		capture >> img;       // 카메라 영상받기
		if (img.empty())
			break;
		
		pre_p = img.clone(); // 영상 복사
		resize(pre_p, pre_p, Size(500, 500), 0, 0, CV_INTER_LANCZOS4); // 이미지 리사이징
		cvtColor(pre_p, pre_p, CV_RGB2GRAY); // Grayscale
		save << pre_p; // 프레임을 동영상으로 저장
		

		imshow("원본 영상", img);
		imshow("전처리 영상", pre_p);

		waitKey(10);
	}
}

 

원본 영상의 한 프레임

 

전처리를 거친 영상의 한 프레임

 

좌측 : 원본 영상 / 우측 : 저장된 영상

딥러닝 모델을 사용해보셨다면 라벨링이라는 단어를 많이 들어보셨을 겁니다.

 

라벨링이란 이미지 속 비슷한 무리의 픽셀끼리 그룹화 하여 구별이 가능하도록 이름을 새기는 것을 말합니다.

 

 

이진화 라벨링은 검은색과 흰색 픽셀로 이루어진 이미지를 라벨링하는 것입니다.

 

더욱 자세하게 아래 그림의 예로 설명하자면 아래의 이미지가 있을 때, 이미지(x, y)   (0,0) -> (1,0) -> (2,0) ... 순으로

 

픽셀을 지나치며 회색의 픽셀을 찾습니다. 회색의 픽셀을 찾으면 주변 픽셀들과의 상관 관계를 찾으며, 이때 4방향과

 

8방향 접근 방법을 사용합니다. 4방향 접근은 픽셀의 좌우, 상단의 상관 관계를 찾는 것이며, 8방향 접근은 좌우, 상단

 

그리고 대각선의 상관 관계를 찾습니다.

 

 

이진화로 된 이미지

 

4방향 접근 방법

 

8방향 접근 방법

 

Opencv에서 제공하는 connectedComponentsWithStats() 함수는 이진화로 표현된 이미지를 이용하여 라벨링을 처리가

 

가능하며, Opencv 3.0이상부터 본 함수를 제공해주고 있습니다.

 

 

connectedComponentsWithStats() 함수의 인자는 총 6가지를 입력해야 합니다.

 

1) 입력 이미지

 

2) 라벨링 결과 이미지

 

3) 라벨링 된 이미지의 정보

 

4) 라벨링 된 이미지의 중심 좌표

 

5) 4방향/8방향

 

6) 타입

 

 

아래 코드를 통해 connectedComponentsWithStats() 함수를 사용해보도록 하겠습니다.

 

* 본 코드는 Opencv 3.1.0 Version에서 사용하였습니다.

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

using namespace cv;
using namespace std;

int main()
{
	Mat image = imread("D:\\과일.jpg");
	Mat image_gray;
	Mat image_bi;
	Mat label_box;

	// 라벨 레이어 변수
	Mat img_label;
	Mat stats;
	Mat centroids;
	int label;


	//이미지 축소/확대
	resize(image, image, Size(500, 500));

	// 복사
	label_box = image.clone();

	//그레이스케일
	cvtColor(image, image_gray, CV_RGB2GRAY);

	//이진화
	threshold(image_gray, image_bi, 230, 255, CV_THRESH_BINARY);
	image_bi = ~image_bi;

	label = connectedComponentsWithStats(image_bi, img_label, stats, centroids, 8, CV_32S);
	for (int j = 1; j < label; j++) 
	{
		int area = stats.at<int>(j, CC_STAT_AREA);
		int left = stats.at<int>(j, CC_STAT_LEFT);
		int top = stats.at<int>(j, CC_STAT_TOP);
		int width = stats.at<int>(j, CC_STAT_WIDTH);
		int height = stats.at<int>(j, CC_STAT_HEIGHT);

		// 라벨링 박스
		rectangle(label_box, Point(left, top), Point(left + width, top + height), Scalar(0, 0, 255), 3);

	}

	imshow("original", image);
	imshow("Binary", image_bi);
	imshow("Label box", label_box);

	waitKey(0);
}

원본 이미지

 

이진화된 이미지

 

라벨링 이미지

 

 

 

< 참고 자료>
https://skkuassa.tistory.com/203

 

opencv , image processing , 2 pass labeling

살펴보기.. openCV에 신기하게도 라벨링이 없는듯하다. 라벨링 (Labeling) 이란 바이너리 이미지 ( 0과 1만 있는 이미지) 로 처리하는 과정 중에서 독립된 개체를 찾아서 라벨을 붙여주는 알고리즘이다. 여기서 배..

skkuassa.tistory.com

 

 

 

Keras를 이용하여 이미지 데이터를 구축하고 훈련하여 테스트하는 과정을 알려드리겠습니다.

 

훈련시킬 이미지는 숫자이며, 이전 글인 [Opencv] 히스토그램을 이용한 숫자 인식에 사용했던 이미지입니다.

 

 

 

숫자 데이터셋

 

이미지 데이터가 부족하여 Python 기반 라이브러인 Augmentation을 이용하여 이미지를 왜곡시켜 증강시켰습니다.

* Augmentation에 대한 내용은 이전 글을 참고해주세요.

 

각 숫자별로 100장의 이미지로 부풀려 데이터셋을 구축하였습니다.

 

 

 

 

* Keras 2.2.4 / Tensorflow 1.14.0 버전을 사용했으며, 설치하신 버전을 잘 모르겠다면, 아래의 코드를 입력하여

  확인하실 수 있습니다.

import tensorflow as tf
import keras

## 텐서플로우 버전
print(tf.__version__)

## 케라스 버전
print(keras.__version__)

 

 

< 훈련셋 이미지를 이용한 npy 파일 생성>

from PIL import Image
import os, glob, numpy as np
from sklearn.model_selection import train_test_split

caltech_dir = "D:/SPB_Data/.spyder-py3/test/0~10 숫자"
categories = ["0", "1", "2", "3","4", "5", "6", "7", "8", "9"]
nb_classes = len(categories) #해당하는 변수의 길이를 표현, len(categories)는 10이 된다

image_w = 28
image_h = 28

X = []  #X, Y는 데이터와 라벨을 저장하기 위해 만드는 배열
y = []

for idx, cat in enumerate(categories):
    
    #one-hot 돌리기.
    label = [0 for i in range(nb_classes)] #i = range(nb_classes) 즉 4이다.
    label[idx] = 1

    image_dir = caltech_dir + "/" + cat
    files = glob.glob(image_dir+"/*.jpg")
    print(cat, " 파일 길이 : ", len(files))
    for i, f in enumerate(files):
        img = Image.open(f)
        img = img.convert("RGB")
        img = img.resize((image_w, image_h))
        data = np.asarray(img)

        X.append(data)
        y.append(label)

X = np.array(X)
y = np.array(y)


X_train, X_test, y_train, y_test = train_test_split(X, y)
xy = (X_train, X_test, y_train, y_test)

np.save("D:/SPB_Data/.spyder-py3/test/0~10 숫자/digit.npy", xy)

 

< 모델 구축 및 훈련 >

import os, glob, numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout
from keras.callbacks import EarlyStopping, ModelCheckpoint
import matplotlib.pyplot as plt
import keras.backend.tensorflow_backend as K

"Tensor 2.0에서 configproto, session 등을 변경해서 선언해야 함"
import tensorflow as tf
config =  tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.Session(config=config)

## 데이터셋 생성
X_train, X_test, y_train, y_test = np.load('D:/SPB_Data/.spyder-py3/test/0~10 숫자/digit.npy', allow_pickle=True)
print(X_train.shape)
print(X_train.shape[0])


categories = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
nb_classes = len(categories)

#일반화
X_train = X_train.astype(float) / 255
X_test = X_test.astype(float) / 255


## GPU를 이용하여 모델 구성 및 훈련
with K.tf_ops.device('/device:GPU:0'):
    model = Sequential()
    model.add(Conv2D(10, (3,3), input_shape=X_train.shape[1:], activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Conv2D(20, (3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    
    model.add(Flatten())
    model.add(Dense(20, activation='relu'))
    model.add(Dense(nb_classes, activation='softmax'))
    
    ## 모델 학습과정 설
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    model_dir = 'D:/SPB_Data/.spyder-py3/test/0~10 숫자/'
    
    if not os.path.exists(model_dir):
        os.mkdir(model_dir)
    
    model_path = model_dir + '/car_number_classification.h5'
    checkpoint = tf.keras.callbacks.ModelCheckpoint(filepath=model_path , monitor='val_loss', verbose=1, save_best_only=True)
    early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=7)
    
    ## 모델 구성 요약
    model.summary()
    
    ## 모델 학습시키기
    ## 배치사이즈 에포크 설정
    history = model.fit(X_train, y_train, batch_size=35, epochs=60, validation_data=(X_test, y_test), callbacks=[checkpoint, early_stopping])
    
print("정확도 : %.4f" % (model.evaluate(X_test, y_test)[1]))

 

model.surmmary()

model.surmmary()를 통하여 설계된 모델을 한 눈으로 파악할 수 있으며, Convolution Layer와 Dense Layer에서

추출되는 Weight와 Bias의 수도 확인할 수 있습니다.

 

 

 

 

< 인식 >

from PIL import Image
import os, glob, numpy as np
import tensorflow as tf

caltech_dir = "D:/SPB_Data/.spyder-py3/test/0~10 숫자/9"

image_w = 28
image_h = 28


X = []
filenames = []

## 재귀함수 glob()
## 파일 내 모든 jpg 파일 로드
files = glob.glob(caltech_dir+"/*.jpg*")

for i, f in enumerate(files):
    img = Image.open(f)
    img = img.convert("RGB")
    img = img.resize((image_w, image_h))
    data = np.asarray(img, dtype='float32') # 데이터를 하나의 index(=list)를 가진 배열로 재생성 해주는 함수.
    filenames.append(f)
    X.append(data) # append는 이어쓰기

X = np.array(X)
# Tensor 2.0 버전의 문제인지 X는 uint8 타입으로 저장되어 지원되지 않는 형식으로 저장된다. 이때 형변환하는 함수이다.
# 밑의 함수로 변경해주거나 asarray에서 형식을 지정해줄 수도 있다.
#X = X.astype('float32') 

model = tf.keras.models.load_model('D:/SPB_Data/.spyder-py3/test/0~10 숫자/number_classification.h5')

#predict는 input data가 numpy array나 list of array 형태만 가능하다.
prediction = model.predict(X)

#numpy float 출력옵션을 변경하는 함수. float 형식으로 x: 뒤에 부분을 표현한다.
#0:0.3f = 0번 index 값의 소수점 3번째 자리까지 출력함.
np.set_printoptions(formatter={'float': lambda x: "{0:0.3f}".format(x)}) 
cnt = 0

# 이 비교는 그냥 파일들이 있으면 해당 파일과 비교. 카테고리와 함께 비교해서 진행하는 것은 _4 파일.
for i in prediction:
    pre_ans = i.argmax()  # 예측 레이블
    print(i)
    print(pre_ans)
    pre_ans_str = ''
    if pre_ans == 0: pre_ans_str = "Zero"
    elif pre_ans == 1: pre_ans_str = "One"
    elif pre_ans == 2: pre_ans_str = "Two"
    elif pre_ans == 3: pre_ans_str = "Three"
    elif pre_ans == 4: pre_ans_str = "Four"
    elif pre_ans == 5: pre_ans_str = "Five"
    elif pre_ans == 6: pre_ans_str = "Six"
    elif pre_ans == 7: pre_ans_str = "Seven"
    elif pre_ans == 8: pre_ans_str = "Eight"
    else: pre_ans_str = "Nine"
    
    if i[0] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[1] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"으로 추정됩니다.")
    if i[2] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[3] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[4] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[5] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[6] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[7] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[8] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    if i[9] >= 0.8: print("해당 "+filenames[cnt].split("\\")[1]+" 이미지는 "+pre_ans_str+"로 추정됩니다.")
    cnt += 1
    # print(i.argmax()) #얘가 레이블 [1. 0. 0.] 이런식으로 되어 있는 것을 숫자로 바꿔주는 것.
    # 즉 얘랑, 나중에 카테고리 데이터 불러와서 카테고리랑 비교를 해서 같으면 맞는거고, 아니면 틀린거로 취급하면 된다.
    # 이걸 한 것은 _4.py에.

 

0의 이미지들을 인식시켰을 때 결과

 

'딥러닝 > Keras' 카테고리의 다른 글

이미지 증강 - Augmentation  (0) 2020.04.04

 

오늘은 케라스에서 심층 신경망을 구축하기 앞서 Python 기반의 한 가지 라이브러리를 소개하려 합니다.

 

 

 

영상 기반의 인공지능 모델을 사용하여 어떠한 객체를 검출 및 인식하기 위해선 가장 먼저 해야될 작업은

 

이미지 데이터를 수집하여 CNN을 거쳐 훈련을 시키는 것입니다.

 

이때 이미지 데이터의 수는 인식률을 높히기 위해선 객체당 수백장에서  수천, 수만장까지 필요합니다.

* 이미지의 수에 비례하여 인식률이 높아지는 것은 아닙니다. 


물론 COCO data, Kaggle, GitHub 등에서 오픈하여 제공하는 데이터를 가져와 활용하면 쉽게 데이터셋을

구축할 수 있지만 내가 원하는 이미지 데이터가 존재하지 않을 수도 있으며, 또는 이미지 데이터가 수가

 

부족한 상황이 매우 드물게 마주칩니다.

 

그래서 오늘은 이미지를 증강시킬 수 있는 파이썬 라이브러리인 Augmentation를 사용해보도록 하겠습니다.

 

 

 

 

Augmentation 라이브러리엔 이미지를 회전, 확대, 왜곡, 반전 등등의 함수들이 있습니다.

 

설치 방법은 아래와 같으며, 저는 Window 10에서 가상환경을 구축하여 cmd 창을 통해 라이브러리를 설치하고

Spyder 툴에서 설치된 라이브러리를 이용하여 파이썬 기반의 코드로 이미지를 증강하였습니다.

 

* 가상환경을 구축하지 않고 Anaconda를 설치하여 Spyder가 아닌 Jupyter Notebook을 이용하셔도 됩니다.

  저는 케라스를 사용하기 위해 구축된 가상환경에서 Augmentation 라이브러리를 설치한 것입니다.

 

 

라이브러리 설치

pip install Augmentor

 

라이브러리 설치는 매우 간단합니다...

 

 

 

 

라이브러리에서 몇가지의 함수를 코드를 통해 알아보겠습니다.

 

아래 그림의 원본 이미지를 좌우 반전, 상하 반전, 왜곡시키며 이 세 가지를 통합한 결과입니다.

 

import Augmentor

## 증강 시킬 이미지 폴더 경로
img = Augmentor.Pipeline("D:/이미지 증강")

## 좌우 반전
img.flip_left_right(probability=1.0) 

## 상하 반전
img.flip_top_bottom(probability=1.0)

## 왜곡
img.random_distortion(probability=1, grid_width=10, grid_height=10, magnitude=8)

## 증강 이미지 수
img.sample(10)

 

원본 이미지

 

좌우 반전

 

상하 반전

 

왜곡

 

좌우, 상하 반전 + 왜곡

 

상하, 좌우 반전은 눈으로 쉽게 확인하실 수 있겠지만, 왜곡운 둥근 그릇의 모양을 보시는 게 쉽게 확인되실겁니다.

 

좌우, 상하 반전 함수는 인자에 전체 이미지에서 적용시킬 확률값을 입력할 수 있으며, 왜곡 함수는 왜곡시킬 범위를

인자에 입력할 수 있습니다

 

 

 

< 정리글 >

 

  오늘은 이미지를 증강하는 파이썬 기반의 라이브러에 대해 알아보았습니다. 이미지가 부족거나 조금의 변화에 객체를

인식 못하는 상황에 이 라이브러리를 사용하는 것이 인식률 향상에 도움이 될거라 생각이 듭니다. 위에서 사용한 함수 

말고도 Rotation, Cropping, Perspective Transforms 등을 이용하여 증강시킬 수 있는 다양한 함수들이 존재합니다.

자세한 설명은 아래 참고 자료에 첨부한 사이트를 참고해주세요.

 

 

 

 

< 참고 자료 >

 

https://github.com/mdbloice/Augmentor

 

mdbloice/Augmentor

Image augmentation library in Python for machine learning. - mdbloice/Augmentor

github.com

 

'딥러닝 > Keras' 카테고리의 다른 글

[Keras] 숫자 인식  (0) 2020.04.04

+ Recent posts