[19/04/15] 진행 상황

지난주의 계획대로 TL 전체가 아닌, Light 자체를 검출하는 모델을 만들어봤습니다.

Training dataset은 지난주에 사용했던 이미지들을(2088*1080) 두장으로 나누어(1080*1080) 2134개의 이미지를 썼습니다.

6천번 Training한 모델에 Test Video를 입력한 결과 아래 예시 이미지와 같이 나왔습니다.

Image

Image

Image

정확도를 측정하니 아래와 같이 나왔습니다.

class_id = 0, name = G, ap = 90.44 %
class_id = 1, name = Bus, ap = 99.15 %

for thresh = 0.25, precision = 0.94, recall = 0.99, F1-score = 0.96
for thresh = 0.25, TP = 665, FP = 43, FN = 6

mean average precision (mAP@0.50) = 0.947937, or 94.79 %

'Project > Bus Traffic Light Detection' 카테고리의 다른 글

19/05/27 진행상황  (0) 2020.01.09
Presentation(1)  (0) 2019.05.20
19/04/10 진행 상황  (0) 2019.04.10
19/04/01 진행 상황  (0) 2019.04.01
프로젝트 로드맵  (0) 2019.03.28

[19/04/10] 진행 상황

지난주 계획대로 주말에 약 1000장 정도의 Bus TL이 들어간 사진을 확보했습니다. 그리고 Bus TL과 General TL이 들어간 이미지 1200장과 General TL만 들어간 사진 900여 장을 학습시켰습니다. Class는 지난주와 다르게 Sign을 빼고 Bus TL, General TL로만 구분해서 Training 했습니다. 6000번을 Training 시킨 후 동영상을 입력 시켜본 결과 아래와 같이 나왔습니다.

Image

Image

잘 구분하는것처럼 보이지만, 아래와 같이 False Positive의 결과가 많았습니다.

Image

그래서 자료를 찾아보다가 TL의 arrow를 검출하는 연구에 대한 글을 읽었습니다. 그 글을 읽고, TL의 전체를 Box 처리하는것 보다 신호 자체의 모양을 Box 처리해야 보다 정확한 구분이 가능할것이라는 생각이 들어서 다시 모든 이미지에 대해 Bounding Box를 다시 그린후 Training 시킬 계획입니다.

'Project > Bus Traffic Light Detection' 카테고리의 다른 글

Presentation(1)  (0) 2019.05.20
19/04/15 진행 상황  (0) 2019.04.16
19/04/01 진행 상황  (0) 2019.04.01
프로젝트 로드맵  (0) 2019.03.28
Project proposal  (0) 2019.03.28

#define 대신 const, enum, inline 사용하기

키워드

define, const, enum, inline

#define을 쓰면 소스 코드가 컴파일러에게 가기 전에 선행처리자가 숫자 상수로 바꿔버리기 때문에 컴파일러가 쓰는 기호 테이블에 들어가지 않는다.

때문에 숫자 상수로 대체된 코드에서 컴파일 에러가 발생하게 되면 에러 메시지에 숫자 상수가 나와버리기 때문에 자신이 작성하지 않은 코드인 경우 큰 혼란을 겪을 수 있다.

상수 포인터를 정의하는 경우

상수 포인터는 보통 헤더 파일에 넣는 것이 상례이다.

포인터와 포인터가 가리키는 대상 모두 const로 선언하는 것이 좋다.

const char* const Name = "EXAMPLE";
const string Name("EXAMPLE");

클래스 멤버로 상수를 정의하는 경우

class GamePlayer {
   private:
    static const int NumTurns = 5;  // 상수 부분, 선언 부분, 초기값이 있다.
    int scores[NumTurns];           // 상수 사용 부분
};
  • 헤더 파일에 둔다. NumTurns는 선언되어있고 정의되어 있지 않다.
const int GamePlayer::NumTurns; // NumTurns의 정의
  • 정의 부분은 헤더 파일이 아닌 구현 파일에 둔다. 정의에는 초기값이 없다.

#define은 private 같은 기능이 없기 때문에 캡슐화의 기능이 없다. 그렇기 때문에 const를 쓰는 것이 좋다.

오래된 컴파일러에서는 반대의 경우도 있다. 선언 부분에 초기값이 없고 정의 부분에 초기값을 정해준다. 하지만 아래와 같은 예외사항이 있을 수 있다.

class CostEstimate {
   private:
    enum { NumTurns = 5 }; // 나열자를 이용.
    int scores[NumTurns];
};
  • enumconst보단 #define에 가깝다. enum#define의 주소를 얻어내는 것은 불가능하지만 const는 가능하다.

매크로 함수로 사용하는 경우

#define CALL_WITH_MAX(a, b) ((a) > (b) ? (a) : (b))  // 괄호를 유의하여 작성해야한다.
int a = 5, b = 0;
cout << CALL_WITH_MAX(++a, b);       // a가 2번 증가
cout << CALL_WITH_MAX(++a, b + 10);  // a가 1번 증가
template <typename T>
inline void callWithMax(const T& a, const T& b) {
    cout << (a > b ? a : b);
}

inline을 이용해서 함수를 쓰면 진짜 함수이기 떄문에 유효 범위 및 접근 규칙을 적용할 수 있다. 괄호 때문에 생기는 혼란도 없앨수 있다.

'C++ > Effective C++' 카테고리의 다른 글

[C++] const의 활용  (1) 2019.04.16

YOLO Usage on Windows

  • 컴파일, Linux에서의 사용법은 다루지 않았습니다.
  • AlexeyAB의 darknet을 참고하여 작성했습니다.
  • 순서를 실제로 사용하면서 보게 되는 순서대로 바꿨습니다.
  • 최근 수정 : 2019년 4월 2일

Pre-trained models Download

How to Train

  • 쓰려고 하는 cfg 파일을 수정한다.
    • batch=64
    • subdivision=8
    • heightwidth는 32의 배수로 크면 클수록 정확도가 높다.
    • classes=을 검색해서 자신의 class 갯수로 수정한다.
    • classes=을 검색했을 때, 위에 나오는 filters= 역시 수정해야하는데, 그 값은 (classes+5)*3이다.
    • 다른 해상도에 대한 정확도를 높이려면 파일의 맨아래 random=1로 수정한다.
    • Small Object(416*416으로 Resizing 했을때 16*16보다 작은 경우)라면 Line #720에 layers = -1, 11, Line #717에 stride=4로 수정한다.
    • anchors=를 수정한다.
      • anchors 계산 : darknet.exe detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416
    • 좌우 구별 감지를 원하면 Line #17 flip=0을 입력한다.
  • data 파일을 만들어야 한다.

    classes = 3
    train = EXAMPLE1/train.txt
    valid = EXAMPLE1/test.txt
    names = EXAMPLE1/obj.names
    backup = EXAMPLE1/backup/  # 중간 weights를 저장하는 경로
  • names 파일을 만들어야한다.

    • class 0, 1, 2 ... 이름을 적는다
      bird
      dog
      cat
  • Training 및 Testing 시에 쓸 이미지 파일을 build\darknet\x64\EXAMPLE1에 저장한다.

    • 물론 이 이미지들은 Bounding Box처리가 되어 있어야한다.
    • 다음 링크에서 marking을 하는 툴을 받을 수 있다. Box 작업에는 큰 인내와 끈기가 필요하다.
  • 이미지 리스트의 상대 경로가 적혀있는 txt 파일을 생성해야한다.

    • 이미지가 3개이고 경로가 darknet.exe가 있는 디렉토리에 있는 EXAMPLE1에 있는 경우 train.txt가 아래와 같은 내용이여야한다.

      EXAMPLE/img1.jpg
      EXAMPLE/img2.jpg
      EXAMPLE/img3.jpg
  • darknet.exe detector train .data .cfg .weights로 Training 시킬 수 있다.

    • Training 시에 Loss-Window를 띄우지 않으려면 -dont_show 옵션을 설정하면 된다.
  • Training 후에는 아래 명령어로 어느 weights가 어느 정도의 성능을 보이는지 확인할 수 있다.

    darknet.exe detector map .data .cfg .weights
  • mAP-chart

    • darknet.exe detector train .data .cfg .weights -map

Usage (After Training)

  • https://github.com/AlexeyAB/darknet#how-to-use-on-the-command-line
  • cfg 파일에서 heightwidth를 늘린다.(608 or 832: 32의 배수로)
    • Out of memory 오류가 난다면 subdivision을 16, 32, 64 등으로 증가시킨다.
  • Image : darknet.exe detector test .data .cfg .weights -thresh THRESH OPTION
    • OPTION
      • Output coordinates : -ext_output
      • Use GPU 1 : -i 1
      • List of Image에 대한 결과 저장 : -thresh 0.25 -dont_show -save_labels < list.txt
  • Video : darknet.exe detector demo .data .cfg .weights .videofile OPTION
    • OPTION
      • WebCam 0 : -c 0
      • Net-videocam : http://192.168.0.80:8080/video?dummy=param.mjpg
      • Save result : -out_filename OUT.videofile
  • Check accuracy mAP@IoU=75 : darknet.exe detector map .data .cfg .weights -iou_thresh 0.75

Using Android smartphone(Network Video-Camera)

  1. 어플 다운로드
  1. WiFi 혹은 USB로 컴퓨터와 스마트폰 연결
  2. 어플 실행
  3. darknet.exe detector demo .data .cfg .weights http://192.168.0.80:8080/video?dummy=param.mjpg -i 0으로 실행

YOLO in other frameworks

[19/04/01] 진행 상황

YOLO Training의 Resizing 과정에서 그래픽 메모리가 기존 이미지 데이터(해상도 1920*1080)를 넣었을 때 메모리 초과 오류가 나서 교수님이 제시해주신 방법으로 시도해봤습니다.

사진에서 신호등의 대부분이 사진의 높이 60% 부분에 있기 때문에 사진을 1080 * 60% 정도가 되는 640 픽셀을 기준으로 잡았습니다. 그리고 640 * 640으로 이미지를 3개로 나눴습니다.

Image

그리고 이미지 700장 정도를 3장으로 나눠 총 2100장 정도의 이미지를 아래 Class를 기준으로 Bounding Box를 그렸습니다.

  • Class
    • 0 : General TL
    • 1 : Bus-only TL
    • 2 : TL with Sign

현재 Training 과정에 있고, 화요일 오전에 Test Dataset으로 성능 확인해볼 계획입니다.
6000번 Training 후에 성능 확인을 해봤는데 General TL은 95.58%의 mAP를 보이나, Bus-only TL에 대해서는 현저하게 낮은 성능을 보였습니다. Dataset에 Bus-only TL이 너무 적어서 그런 것으로 판단됩니다.

기존에 가지고 있던 (Training에 쓰이지 않은) TL Image를 입력했을때 General TL을 Bus-only TL로 인식하거나 General TL 자체를 인식하지 못하는 경우가 있는 것도 확인했습니다.

현재 가지고 있는 Dataset이 거리뷰에서 얻은 이미지, 두 종류의 차에서 얻은 Blackbox 이미지, 그리고 주행중 스마트폰으로 촬영한 이미지인데 각각의 이미지들이 데이터가 많지 않아 정확도가 더 떨어지는 것 같습니다. 주말에 이미지들을 다시 모은 후 Training을 해볼 계획입니다.


그 밖에 관련 논문 및 이전에 공부했던 Youtube 머신러닝 강좌와 Coursera 딥 러닝 강좌를 다시 보고 있습니다. 다시 보면서 현재 상황에 제가 어떤 기술이 도움이 될지 공부하고 있습니다.

'Project > Bus Traffic Light Detection' 카테고리의 다른 글

Presentation(1)  (0) 2019.05.20
19/04/15 진행 상황  (0) 2019.04.16
19/04/10 진행 상황  (0) 2019.04.10
프로젝트 로드맵  (0) 2019.03.28
Project proposal  (0) 2019.03.28

정렬(2)

시간 복잡도가 O(N*log2N)인 정렬 방법을 정리합니다.

퀵 정렬

Divide & Conquer 알고리즘.

최악의 경우 속도가 O(N2)가 될 수 있다.(정렬된 데이터에 pivot을 맨 우측으로 잡을 경우)

재귀 전 작업 때문에 재귀 오버헤드가 크다.

  1. 배열의 한 원소를 고른다. (pivot이라고 부른다)
  2. pivot보다 작은 원소는 pivot의 왼쪽으로, 큰 요소는 오른쪽으로 옮긴다.
  3. pivot의 왼쪽 배열과 오른쪽 배열을 다시 1, 2 과정을 거치게 한다.
  4. 배열의 크기가 0이나 1이 될때까지 반복한다.
void Quick_sort(int ary[], int low, int high) {
    if (low < high) {
        int pivot = Partition(ary, low, high);
        Quick_sort(ary, low, pivot - 1);
        Quick_sort(ary, pivot + 1, high);
    }
}
int Partition(int ary[], int low, int high) {
    int left = low, right = high;
    int pivot = ary[left];  // pivot을 가장 왼쪽으로 선택하기로 한다.
    while (left < right) {
        // pivot보다 큰 원소가 나올 때까지 left를 증가시킨다.
        while (ary[left] <= pivot)
            left++;
        // pivot보다 작은 원소가 나올 때까지 right를 감소시킨다.
        while (ary[right] > pivot)
            right--;
        if (left < right)
            swap(ary[left], ary[right]);
    }
    swap(ary[right], ary[low]);
    return right;
}

병합 정렬

공간복잡도가 O(N)이다. 공간이 더 필요하다.

퀵 정렬은 Big -> Small Scale로 정렬하지만, 병합 정렬은 Small -> Big Scale로 정렬하기 때문에 재귀 오버헤드가 없다.

결국에 하나씩 비교하기 때문에 입력 데이터의 사전 정렬에 영향을 받지 않는다.

  1. 배열을 크기가 1이 될 때 까지 반으로 나눈다.
  2. 반으로 나뉘어진 배열을 비교하면서 합친다.
void Merge_sort(int ary[], int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
        Merge_sort(ary, left, mid);
        Merge_sort(ary, mid + 1, right);
        Merge(ary, left, mid, right);
    }
}
void Merge(int ary[], int left, int mid, int right) {
    int i = left, j = mid + 1, k = left;
    int temp[SIZE];
    while (i <= mid && j <= right) {
        if (ary[i] <= ary[j])
            temp[k++] = ary[i++];
        else
            temp[k++] = ary[j++];
    }
    if (i > mid) {
        for (int l = j; l <= right; l++)
            temp[k++] = ary[l];
    } else {
        for (int l = i; l <= mid; l++)
            temp[k++] = ary[l];
    }
    for (int l = left; l <= right; l++)
        ary[l] = temp[l];
}

힙 정렬

우선순위 큐를 이용한 정렬 방법이다.

하나의 삽입, 삭제 과정이 O(logN)의 시간이 걸린다.

전체 데이터 삽입, 삭제 과정은 O(NlogN)의 시간이 걸린다.

'알고리즘 & SQL > 개념' 카테고리의 다른 글

[정렬] 버블 정렬, 선택 정렬, 삽입 정렬  (0) 2019.03.28

계획(로드맵)

Traffic Light(hereinafter referred to as TL)의 종류가 엄청 다양하기 때문에, Bus-only TL을 Detection을 하는데는 한 단계 기술을 거치는 것으로는 충분하지 않다. TL을 검출해내고, Traffic Sign의 글자도 인식해야 한다.

  1. TL Detection

    • class 0 : General TL
      • 2단계로 넘어간다.
    • class 1 : Bus-shaped TL
      • Detection 끝.
    • class 2 : TL with Sign
    • Real-time processing에 적합한 YOLO를 사용할 것으로 예상된다.
  2. Traffic Sign Detection

    • 신호등과 가까운 표지판을 찾아내야한다. 대개 해당 신호등의 위쪽에 있다.
    • 그 표지판에 적힌 글자에 버스 전용, 중앙 차선이 포함되어 있는지 확인해내야한다.
    • 저해상도 이미지의 깨진 글자를 인식해낼수 있어야 한다.
    • 깨진 글자를 해결할 수 있는 기술이 필요하다
      • up-scaling
    • Tesseract OCR, SVM
    • 참고 링크

예상되는 한계점 : Real-Time Image Processing이기 때문에 Input Image의 화질이 좋지 않다.
horizontal TL에 대해서만 고려하고, 검출하는 모델을 만들었기 때문에 vertical TL에 대한 성능은 확신할 수 없다.

'Project > Bus Traffic Light Detection' 카테고리의 다른 글

Presentation(1)  (0) 2019.05.20
19/04/15 진행 상황  (0) 2019.04.16
19/04/10 진행 상황  (0) 2019.04.10
19/04/01 진행 상황  (0) 2019.04.01
Project proposal  (0) 2019.03.28

+ Recent posts