블로그 이미지
pgmr이상현
Instagram:sh_lee77 머신비전, YOLO, 영상처리, Deep Learning, 딥러닝

calendar

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

Notice

물총을 회전시키기 위해서는 지지대가 필요하다고 생각했습니다.

그래서 공방에 의뢰하여 다음과 같이 제작하게 되었습니다.

위와같이 Servomotor를 안에 넣을 수 있게 모양을 따서 만들게 되었습니다.

안에 Servomotor를 넣게되면

네 이쁘게 Servomotor가 들어가는 것을 알 수 있습니다.


그럼 이제 Servomotor가 회전하는 영상을 보겠습니다.

네 위와같이 회전이 잘 되는것을 확인할 수 있습니다.

그러면 이제는 물총에서 Trigger역할을 하는 Servomotor를 달아보겠습니다.

네 제가 열중하면서 Trigger용 Servomotor를 달고 있습니다.

다 되었으면 회전용 Servomotor위에 물총을 달아보겠습니다.


네 이제야 좀 짜세가 나오는 것 같습니다. 저만 그렇게 느끼는 건가요?ㅎㅎ


Servomotor제어를 시뮬레이션 해보면서 문제점이 생겼습니다. 엄청 큰..

우리팀은 회전용 Servomotor와 Trigger용 Servomotor로 총 2개의

Servomotor를 구매했습니다.


그런데 2개다 360도Servomotor를 구매했습니다. 360도Servomotor를

제어를 해보면서 느낀것이 자유자재로 회전을 시킬 수 없다는 것 입니다.


각도를 재서 회전을 할수가없고 한 방향으로 회전을 시키다가 몇초뒤에

역 방향으로 회전을 시킨다는 둥으로의 제어 밖에 가능하지 못한다는

문제점을 이제야 깨닫게 되었습니다. 이제 구매할 시간조차 없는 와중에


수소문 끝에 180도 Servomotor를 가진 친구를 찾았고, 그 친구덕분에

Bounding Box를 따라 각도별로 회전할 수 있게 되었습니다. Thank you


이 포스팅을 보시는 분들 중에서 Servomotor를 사용하기전 이신분들은

꼭 180도와 360도 Servomotor의 차이를 알고 구매하셨으면 좋겠습니다.


그러면 이제 Webcam만 물총위에 장착하게되면 완성입니다. 해보겠습니다.

와 드디어!!!! 이제 뭔가 진짜 있어보입니다. 그러면 우리팀이 만든

Deep Learning(YOLO)기반의 Smart Scarecrow 시연영상을 보도록 하겠습니다.

시연영상을 통해서 잘 동작하는걸 알 수 있습니다.

이 후에 12월22일에 부산 벡스코에서 열리는

2017 한국 소프트웨어 종합 학술대회인

KSC 2017 SW 구현/데모 경진대회에 참가하게됩니다.


[1]번 포스팅인 개발배경부터 다시 간단하게 정리를 해보자면

야생동물인 (고라니, 멧돼지)로 이한 농작물 피해가 연간100억원 이상으로 집계되고

있습니다. 현재 국내에서는 울타리를 치는 등의 방법으로 방지하고자 하는데,

조사를 해보니 고라니들이 울타리 아래의 땅을 파고들어가는 경우를 보았습니다.


또 국내 유사제품으로는 야생동물퇴치기 팜캡스라는 제품이 있었는데, 이 제품 같은 경우에는 시간의 주기적으로 빛 이나 소리를 냄으로써

야생동물을 쫓아내는 형식입니다. 이 경우에는 나중에 고라니가 소리가 나도

아무렇치 않구나 라고 학습을 하게되어 효과가 사라진다는 후기가 있었습니다.


해외에서는 아마존을 통해서 Scarecrow라는 제품을 구입하여 사용하는데,

이 경우에는 모션센서를 이용해 작동합니다. 그렇기에 사람또한 인식되어

스프링클러에 공격을 당하는 경우가 많았습니다.


이러한 문제점들을 해결하기 위해

Deep Learning기술로 야생동물(고라니, 멧돼지)를 학습하여,

사람에게는 피해없이 동작하고, 주기적이 아닌 객체인식을 통하여 작동하는

Deep Learning기반의 Smart Scarecrow를 제작하게 되었습니다.


Smart Scarecrow는 야생동물이 나타나기까지 계속 180도 회전합니다.

야생동물이 나타나 인식하게되면 180도 범위안에서 쫓아낼때까지

좌표를 계속 추적하며 물총을 쏘게됩니다. 

posted by pgmr이상현

앞 포스팅에서 서버연결까지 맞추었습니다.

이제는 아두이노에서도 Bounding Box의 좌표를 가져올 수 있습니다.

그럼이제 그 좌표를 물총이 180도 회전을 하면서 물을 발사할 수 있어야 합니다.


우리는 Servomotor를 2개 준비했습니다.

한개는 물총아래서 돌면서 물총의 회전을 담당하고, 한개는 손잡이 부분에서

Trigger역할을 합니다.


1. Servo motor연결하기


사진출처 [피지컬 컴퓨팅 교육]

 

위 이미지와 같이 2개의 서보모터를 제어할 수 있습니다.

그래서 우리도 위와같이 꽂아 보았습니다.

7번과 9번핀에 서보모터를 연결하였습니다.

하나는 회전 하나는 발사를 담당하게 됩니다.

Servomotor의 제어또한 오픈소스를 이용해서 수정을 하면 되겠습니다.


2. Servo motor코딩하기

위와 같이 Servo예제를 실행하게 되면 다음과 같은 예제코드가 나옵니다.

위에서 핵심 코드입니다.

Servo myservo;        // 서보모터 변수 선언


myservo.attach(9);    // 선언한 서보모터 변수에 9번에 연결된 모터를 연결


myservo.write(pos);    // 서보모터 변수에 연결된 모터를 pos 각도로 회전

위에 코드를 활용하여 서보모터를 제어할 수 있습니다.


posted by pgmr이상현

앞 포스팅에서 JSN270 Wifi Shield의 문제점에 대해 포스팅했고

이번 포스팅은 그로인해 사용하게된 Ethernet Shield를 이용한 Http서버 연결에 대해

포스팅을 해보도록 하겠습니다. GO GO!!


먼저 아래 이미지와같이 Uno보드에 Ethernet Shield를 연결하고

USB와 LAN선을 연결해 줍니다. 불빛이 잘 들어오네요.

Arduino는 오픈소스가 잘 되어있어, 사용하기가 무척 좋은 것 같습니다.

예제 -> Ethernet에서 WebClient와 WebServer예제를 사용합니다.


Web Client

/*

Web client

This sketch connects to a website (http://www.google.com)
using an Arduino Wiznet Ethernet shield.
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe, based on work by Adrian McEwen
*/
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
char server[] = "www.google.com"; // name address for Google (using DNS)
// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
// try to congifure using IP address instead of DHCP:
Ethernet.begin(mac, ip);
}
// give the Ethernet shield a second to initialize:
delay(1000);
Serial.println("connecting...");
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
Serial.println("connected");
// Make a HTTP request:
client.println("GET /search?q=arduino HTTP/1.1");
client.println("Host: www.google.com");
client.println("Connection: close");
client.println();
} else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
}
void loop() {
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing forevermore:
while (true);
}
}


Web Server

/*

Web Server

A simple web server that shows the value of the analog input pins.
using an Arduino Wiznet Ethernet shield.
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Analog inputs attached to pins A0 through A5 (optional)
created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi
*/
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 177);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}


WebServer 코드에서

byte mac[];        // PC와 연결된 아두이노의 Mac address

IPAddress ip();    // PC와 연결된 아두이노의 현재 IP 주소

위의 정보가 필요하다 Mac주소 같은경우는 Ethernet Shield의 아랫면에 적혀 있다는데,

이상하게 우리는 그렇지 않았습니다. 우리와 같은 분들은 Web Server예제를 통해서, Mac주소를

알아낼 수 있습니다.


이제 Web Client 에서 수정만 해주면 됩니다.

IPAddress server();

위의 코드의 주석을 풀어서 우리의 서버를 구축한 PC의 IP주소를 적어 줍니다.


그리고 다음과 같이 수정합니다.

Host부분에 Server IP만 바꾸어주면 됩니다. 간단합니다.

그 이후에 Serial모니터를 보면 서버연결이 잘 되는것을 확인할 수 있습니다.


JSN270 WiFi Shield를 사용했을 때는 끊어지던 서버가 안 끊어지는 것이

확인됩니다.

posted by pgmr이상현

서버에서의 좌표를 받아 물총을 제어하기 위해선 먼저 서버연결을 해야합니다.

서버를 연결하기 위해서는 WiFi Shield 또는 Ethernet Shield가 필요합니다.


우리는 먼저 WiFi Shield를 사용해보기로 했습니다.

JSN270이라는 쉴드를 사용해보기로 했습니다.

JSN270 WiFi Shield 는 위와같이 생겼다. 처음 써봐서 어떻게 쓰는건지 몰라서

두리번 두리번 했습니다.

쓰는 방법을 알아냈는데, 위와같이 Uno보드 위에 고대로 겹쳐서 끼워주시면 됩니다.


JSN270 WiFi Shield는 검색해보니까 다른 Shield들 하고는 서버연결하는 코드가,

조금 상이 했습니다. JMP SYSTEMS라는 회사에서 만든건데 예제소스는 이 회사

홈페이지에서 받을수 있습니다. SITE  <-- 여기 클릭!! 

자료를 다운받으면 예제소스를 받을 수 있습니다.


서버 연결을 해보겠습니다.

예제소스에 우리의 서버 IP주소만 넣어주면 간단하게 위와같이 서버가 연결된 것을 확인할 수 있습니다. 생각보다 간단하게 잘되네요. 그런데 문제점이 있었습니다.

다시한번 연결을 시도하니 Timeout Failed,  Failed connect,  Restart System

연결이 실패합니다. Restart하라고 해서 다시 연결을 시도해 봅니다.

역시나 연결이 실패하네요...

위 사진에 표시한 Reset버튼을 눌러보겠습니다. 다시 연결이 잘 됩니다.

우리가 뭔갈 잘못하고 있나 생각을 해서 자료를 찾아봤습니다.


다른분들도 이러한 문제점을 겪고 있다는 문제점을 인지하고, 여분으로 사놓았던

Ethernet Shield를 사용하기로 했습니다. 같이사길 잘했다


다음 포스팅은 Ethernet Shield를 사용한 서버연결에 대해 포스팅하겠습니다.

posted by pgmr이상현

이전 포스팅 까지 YOLO에서의 인식되는,

야생동물Bounding Box의 가운데 좌표값을 서버로 보내주는 것 까지 포스팅 했습니다. 그럼 이제 그 좌표를 Arduino에서 받아오고 물총을 동작시켜야 하는데 그 이전에 Arduino환경부터 설정해 보겠습니다.



1. Arduino IDE 설치하기

Arduino IDE는 검색창에 Arduino검색만으로 손쉽게 사이트에 접속할 수 있습니다.

검색마저 귀찮으실 까봐 Arduino site <-- 링크를 가져왔습니다. ㅎㅎ

저의 경우에는 Windows Installer를 받았습니다. Windows Installer를 클릭하게되면

다음과 같은 화면이 나오는데 JUST DOWNLOAD를 클릭하면 됩니다.




2. Arduino 환경설정


Arduino IDE를 실행하면 다음과 같이 실행됩니다.

자 실행을 했으니 이제 PC와 Arduino를 연결해 보겠습니다.

Arduino는 위와 같이 USB를 통해서 PC와 연결해서 소스코딩을 할 수 있습니다.

연결을 했으니, 이제 포트번호를 확인해야 합니다. 장치관리자를 들어갑니다.

이미지와 같이 Arduino Uno 라고있을 겁니다. 저는 4번포트이네요~

자 그럼 다시 Arduino IDE로 이동합니다.

툴 -> 보드 -> (본인의 보드) 본인은 Uno r3보드를 사용해서 Uno를 선택했습니다.

보드를 선택했다면 바로 아래 포트에서 자신의 포트번호를 선택하면 되겠습니다.


자그러면 Arduino환경설정이 모두 끝났습니다. 다음 포스팅은 Arduino와 서버연결에 대해 포스팅 하겠습니다.



posted by pgmr이상현

앞 포스팅에서 좌표를 서버로 보내는 것 까지는 성공을 하였습니다.

하지만 저희가 겪은 문제점으로는 Apache서버를 시작하고 서버인 localhost로 이동을하게되면, 서버에 올린 좌표값이들어있는 html파일의 목록이 보이게됩니다.

아래 이미지를 보겠습니다.

앞 포스팅에서 Bounding Box의 정중앙 좌표값을 서버로 받아오는데 성공을 했다고 했습니다. 좌표가 제대로 전달이 되었는데 무엇이 문제냐고 하실 수 있습니다.


위에 이미지의 주소를 보게되면 192.168.123.101에서 끝이아닌 뒤에 /position.html 경로가 더 있는 것을 알 수 있습니다. 경로가 더 있다는 것은 localhost에서 파일목록에있는 position.html을 열었다는 것 입니다.


이게 왜 문제가 되었냐면, Arduino에서 서버를 통해서 좌표값을 가져와야 하는데

Arduino에서 서버에 접속을 해서 파일목록에 있는 position.html을 직접적으로 열고가져올 수 있는 방법이 없기 때문에 문제가 되었습니다. 어떻게 가공을 통해서 Arduino에 바로 넘겨줄 수 있는방법이 없을까에 고민에 빠졌습니다.


그래서 해결한 방법이 바로 Root Directory를 변경 시킴으로써 localhost에 접속시에

바로 저 위에 보이는 이미지처럼 좌표값이 바로 보이게 하는 것 입니다.


방법은 다음과 같습니다.

Root Directory가 html Directory가 아닌 다른 Directory가 Root 일 경우에는

서버에서 파일의 목록이 보여집니다. 하지만 html Directory를 Root로 변경 시키면

localhost서버에서 접속시 바로 좌표값을 볼수가 있습니다.


자 그럼 지금부터 Root Directory변경을 시작하겠습니다.



1. etc디렉토리 안의 파일열기

sudo gedit /etc/apache2/apache2.conf

sudo gedit /etc/apache2/sites-available/000-default.conf


2. 수정하기

* apache2.conf *

<Directory /var/www>

...

...

</Directory>


* 000-default.conf *

DocumentRoot /var/www/html

위 내용에서  "/var/www"   "/var/www/html" 부분을 원하는 폴더의 경로로

지정하면 Root Directory가 됩니다. 저희 같은 경우는 html디렉토리를 끝으로

지정해 줌으로써, localhost에 접속시 바로 좌표값이 나오도록 했습니다.


이렇게 문제해결을 성공적으로 끝 맞췄습니다. 다음 포스팅 부터는

Arduino를 어떻게 사용했는지 Arduino에 관한 포스팅으로 찾아 뵙겠습니다.

그럼이만~~ 

posted by pgmr이상현

앞 포스팅에서 서버를 구축했으니

YOLO의 Bounding Box의 좌표를 서버로 보내는 포스팅을 하겠습니다.


[5]포스팅에서 YOLO의 분석을 다루었는데요.

darknet디렉토리 안에 src디렉토리가 있습니다.


이 안에는 여러 source code들이 있었지만 우리가 사용할 source code는

image.c입니다. image.c는 Bounding Box에 관한 좌표와 object에 Bounding Box를

그리는 c코드들이 존재합니다. 여기서 code수정을 통해서 Bounding Box의 좌표를

따오겠습니다.

image.c 코드를 캡쳐한 이미지입니다. 코드가 작아서 잘 안보일 수 있기 때문에

클릭하여 확대해서 보는걸 추천해 드립니다.


image.c 코드에서 약 238번째 line에 void draw_detections라는 함수가 보입니다.

이 안에 파일 입출력을 통해서 Bounding Box가 존재하게 되면

html파일이 생성되면서 구축해놓은 서버에 html파일이 올라가게 됩니다.

이 코드는 약 327 line인데 똑같은 void draw_detections함수 안 입니다.


strcmp를 사용하여, yolo에서 인식되는 야생동물의 class name이

inermis(고라니), wild boar(멧돼지)이면 index.html을 생성합니다.


그리고 Bounding Box의 left좌표와 right좌표의 가운데 지점 좌표를 구해줍니다.

이렇게 되면 서버의 index.html에는 야생동물의 Bounding Box의 정중앙 값이

보내집니다.  아래 이미지를 통해서 확인해 보겠습니다.

인식된 멧돼지 Bounding Box의 가운데 지점을 빨간색으로 표시를 했는데요

저렇게 정 중앙의 좌표값이 서버에 잘 전달되는 것을 확인할 수 있습니다.


여기서도 파일입출력을 하는데 위에서는 왜 파일입출력을 한거냐 라고 생각하시는

분들이 많으실겁니다. 아래에서 인식한 야생동물의 정보가 남아있기 때문에,

위에서 한번더 파일입출력을 함으로써 초기화 해준다는 개념으로 생각하시면 될 것 같습니다.


네 이번 포스팅에서는 YOLO Source의 수정을 통해서 좌표값을 계산하고,

그 좌표값을 http서버로 전송하는 포스팅을 했습니다. 다음 포스팅에서는

서버로 전송했을 때 문제점이 발생했었는데 그것에 대해서 포스팅을 해보도록

하겠습니다. 그럼이만~~

posted by pgmr이상현

Ubuntu에서 서버를 구축해 본적이 없는데

찾아보니 엄청 간단하게 구축이 가능했습니다.

LAMP(Linux Apache MySQL PHP)를 설치하면 됩니다.


서버를 구축하기 이전에 root 계정 및 암호설정을 미리하는 것이 좋습니다.


1. Apache 설치

  1. sudo apt-get update
  2. sudo apt-get upgrade

Apache설치가 아니더라도 항상 무언갈 설치하기전에 Package를 최신으로 update 및 upgrade를 해주는게 좋습니다. 설치 이후에도 마찬가지 입니다.


  1. sudo apt-get install apache2

이것으로 Apache설치는 끝났습니다. 

Apache가 제대로 설치가 됬는지 확인을 해보겠습니다.


인터넷 주소창을 하나 엽니다.

  1. http://localhost

'Apache2 Ubuntu Default Page'라는 메세지가 보이면 잘 설치한 것 입니다.


Apache명령어는 아래와 같습니다.

  1. service apache2 start
  2. service apache2 stop
  3. service apache2 reload

위 명령어로 apache서버의 시작과 종료를 할 수 있습니다.


2. MySQL 설치


  1. sudo apt-get install mysql-server

MySQL이 설치가 진행됩니다.

진행중에 중간에 MySQL의 비밀번호 설정화면이 나오게 됩니다.

비밀번호를 잘 설정을 하고 잊어버리지않게 조심합시다.


3. PHP 설치


PHP는 5버전과 7버전이 있는데 우리는 안전하게 5.6버전을 택하였습니다.

PHP설치에 앞서 Repository를 먼저 설치합니다.

  1. sudo add-apt-repository ppa:ondrei/php
  2. sudo apt-get update


이제 PHP 5.6버전을 설치하겠습니다.

  1. sudo apt-get install php5.6 php5.6-common
  2. sudo apt-get install php4.6-mysql php5.6-curl php5.6-xml php5.6-zip php5.6-gd php5.6-mbstring php5.6-mcrypt

PHP설치가 끝났으면, 설치가 정상적으로 되었는지 확인해 보겠습니다.


먼저 Apache의 Root디렉토리로 이동합니다.

초기의 Root디렉토리는 /var/www/html/ 입니다.

  1. cd/var/www/html/
  2. sudo sh info.php

스크립트 창이 열리면 아래의 코드를 입력한 후 현재의 폴더에 저장합니다.

echo "<?php phpinfo(); ?>"

이후에 PHP설치가 완전히 마무리 되었는지 확인해 보겠습니다.


http://localhost/info.php

PHP Version 5.6 메세지가 나오면 설치가 완료된 것 입니다.

localhost대신에 자신의 ip주소를 입력해도 서버 홈페이지에 접속할 수 있습니다.


여기까지 서버구축 포스팅을 마무리 하도록 하겠습니다.

posted by pgmr이상현

앞 포스팅에서 YOLO의 데이터 학습까지 해서 야생동물(고라니, 멧돼지)를

인식하는 것 까지 끝 맞췄습니다. 


이제는 인식한 야생동물을 물총으로 추적하면서 쫓아내는 일만이 남았습니다.

우리는 물총을 제어하기 위해서 아두이노(Arduino)를 사용하기로 했습니다.


설계한 구성도를 한번 보도록 하겠습니다.

구성도를 설명하자면 Cam은 물총 위에 있으며, 야생동물이 인식되기까지 계속하여 물총과 함께 물총 밑에있는 servomotor를사용, 180도 회전합니다.


YOLO로 야생동물이 인식이 되면, Bounding Box의 정 중앙 좌표값을 계산해,

Http서버로 전송하게 됩니다.


그럼 Arduino는 Http서버에서 좌표를 받아와 야생동물의 위치로 물총을

위치시키고, 손잡이 방아쇠부분에 있는 360도 servomotor를 회전시켜

물총을 발사하게 설계하였습니다. 

posted by pgmr이상현

지금까지 많은 Deep Learning Detection Algorithm중에서 왜 YOLO를 사용해야 하는지, 또 YOLO를 사용하기 위해선 어떠한 환경설정을 해야하는지, 그리고 YOLO의 예제사용 및 YOLO의 분석까지 포스팅 했습니다.


이제는 직접 데이터학습을 어떻게 시키는지에 대해 포스팅 해보도록 하겠습니다.


[1]번 포스팅을 보면 우리는 야생동물로 인한 피해를 줄이기 위해, 

Deep Learning(YOLO)기반의 Smart Scarecrow를 개발하기로 했다고 했습니다. 


그렇기 때문에 우리는 야생동물인 고라니333장 멧돼지222장 그리고 야생동물은 아니지만 강아지222장을 학습시켰습니다. 

이미지 학습에 앞서 이미지파일은 확장자가 모두 JPG이여야 합니다. 그렇기 때문에 데이터들을 수집하시고, 알씨 프로그램을 설치해서 이미지파일들을 모두 드래그후에 이미지 포맷변환을 통해서 한꺼번에 모두 JPG로 변환시킬 수 있으니 참고하시길 바랍니다.


YOLO_MARK github - YOLO_MARK의 github로 Mark의 사용법을 알 수 있습니다.


Darknet github - 데이터학습에 관한 정보를 참고할 수 있습니다.



1. YOLO_MARK


YOLO를 학습시키기 위해서는 YOLO_MARK가 필요합니다.

YOLO-MARK는 이미지파일들에 직접 본인이 Bounding Box를 그려줌으로써 Box의 좌표를 지정해줄 수 있습니다. YOLO_MARK를 설치해 보겠습니다.

git clone https://github.com/AlexeyAB/Yolo_mark

설치를 했다면 yolo-mark디렉토리가 생성되었을 겁니다. 그렇다면 yolo_mark 디렉토리로 이동 후 make하고 yolo_mark를 실행해 보겠습니다.

cmake . make ./linux_mark.sh


YOLO_MARK가 실행된 것을 확인할 수 있습니다. 위에보면

image num은 0번째 이미지인가 1번째 이미지인가를 알려줍니다.

object id는 Class분류 라고 생각하면 되는데 object id로 몇개의 분류를 하고 있는가도 확인해볼 수 있습니다.


2. YOLO_MARK Labeling


yolo_mark/x64/Release/data/img

경로안에 기존에 있던 이미지파일들을 삭제합니다.

그리고 그안에 본인들이 하고싶은 이미지파일을 넣어주시면 됩니다.

저 같은경우에는 위에서 말한대로 고라니333장 멧돼지222장 강아지222장의

JPG 이미지파일을 넣었습니다.


yolo_mark/x64/Release/data  -경로에서

vi obj.data

obj.data를 열게되면 위와같은 정보가 나옵니다. 여기서 맨위에 classes= 2로 되어 있는데 이는 몇개로 분류할 것인가를 설정해주는 곳 입니다. 현재 2개로 분류되어 있는걸 알 수 있습니다. 본인은 고라니, 멧돼지, 강아지 총 3개의 분류를 해야하기 때문에 3으로 변경했습니다.


yolo_mark/x64/Release/data  -경로에서

vi obj.names

obj.names는 말그대로 분류할 class에 이름을 붙여주는 겁니다. 하여 본인은 고라니, 멧돼지, 강아지 총3개의 분류를 할 것이기 때문에 위와같이 했습니다.

그럼다시 cd..해서 yolo_mark 디렉토리로 이동해 줍시다.


./linux_mark.sh

yolo_mark를 실행합니다. 

그리고 Bounding Box를 직접 그려넣어 Labeling을 합니다.

위와같이 직접 마우스로 Bounding Box를 직접 그려넣어주면,

jpg파일 옆에 txt파일이 생성된 것을 확인할 수 있습니다.

이 txt파일 안에는 우리가 그려넣어준 Box의 좌표값이 들어있습니다.


3. 데이터 학습하기


yolo_mark/x64/Release 경로로 이동해 줍니다.

vi yolo-obj.cfg

그럼 위와같이 cfg파일이 열리게 되는데, 맨아래로 내려가 줍니다.

맨아래 [region]에 보면 classes=3이라고 보입니다. 우리는 3가지의 분류를 했기 

때문에 3인 것을 확인할 수 있습니다.


그리고 그 위 [convolutional] 아래 filters=40이라고 있습니다. 40인 이유는 

filters 숫자= 5 * (classes+5) 입니다. 우리는 3가지 분류를 했기 때문에

5 * (3+5) = 40 이기 때문에 40이란 숫자를 넣어 주었습니다. 이 내용은

맨 위에 yolo_mark github 링크에서 확인할 수 있습니다.

다른 convolutional은 수정하지 않습니다.


  • convolutional layer 설치 - darknet디렉토리안에 받아 줍니다.

http://pjreddie.com/media/files/darknet19_448.conv.23



  • yolo-obj.cfg파일도 darknet 디렉토리로 이동해 줍니다.

  • yolo_mark/x64/Release/data 경로안에 있는 image 디렉토리와 obj.names , obj.data , train.txt를 darknet/data 경로로 이동해 줍니다.


자 그럼 이제 진짜 데이터학습을 해보도록 하겠습니다.

cd darknet

./darknet detector train data/obj.data yolo-obj.cfg darknet19_448.conv.23

자 그럼 위와같이 학습이 진행되는데 맨 아래보면 1이 보입니다. 

이제 학습을 1번했다는 것 입니다. 724.731750 avg는 loss 즉, 손실율의 평균인데

가장 낮아질때까지 학습을 계속 진행하면 됩니다.


우리팀은 총 45000번의 학습을 진행하였습니다. 학습시간은 대략 50시간정도 걸렸는데 이것은 우리의 PC Nvidia GTX1070 8G기준 시간입니다.


이렇게 학습을 진행하게되면 Backup디렉토리 안에 자동으로 학습된 가중치파일이 저장이 됩니다. Backup디렉토리를 확인을 해보면 아래와 같습니다.

위와같이 가중치파일은 weights파일이 생성된 것을 확인할 수 있습니다.

이제는 학습된 가중치파일로 YOLO를 실행시켜 보겠습니다.


  1. 이미지파일 실행
  2. ./darknet detector test data/obj.data yolo-obj.cfg backup/ yolo-obj_800.weights data/<image file>
  1. 동영상파일 실행
  2. ./darknet detector demo data/obj.data yolo-obj.cfg backup/ yolo-obj_800.weights data/<video file>
  1. Webcam 실행
  2. ./darknet detector demo data/obj.data yolo-obj.cfg backup/ yolo-obj_800.weights data


4. 실행결과



Webcam으로 실행 시킨 결과 wild boar, gorany가

잘 인식이 되는 것을 확인할 수 있습니다.

Webcam같은 경우에는 Logitech c920제품을 사용했습니다.


이것으로 YOLO데이터학습 포스팅을 마무리 하도록 하겠습니다.

posted by pgmr이상현
prev 1 2 next