saurus2
Saurus2
saurus2
전체 방문자
오늘
어제
  • 분류 전체보기
    • 개발
      • AJAX
    • ML Ops
    • Profile
    • 음식점
    • 배낭여행
    • 컴퓨터공학
      • 알고리즘 공부
      • C++
      • Sever 스터디
      • Java spring
      • 알고리즘 _ 문제해결
      • 딥러닝
      • Java 정리
      • Python
      • LeetCode 1000
      • Machine Learning Study
      • Sign language Detection Pro..
      • LeetCode Solutions
    • 비콘
    • 데일리 리포트
    • 유학일기
      • 영어 공부
      • Daily
    • AI Master Degree
      • Data Mining
      • AI and Data engineering
      • Math Foundations for Decisi..
      • Natural Language Processing

블로그 메뉴

  • 홈
  • 태그
  • 미디어로그
  • 위치로그
  • 방명록

공지사항

인기 글

태그

  • Python
  • 딕셔너리
  • 파이썬
  • 알고리즘문제해결
  • DFS
  • 릿코드
  • c++
  • 리트코드
  • 개발자 취업준비
  • 취준
  • 온라인저지
  • LeetCode
  • BFS
  • 문제해결능력
  • 백준
  • two pointer
  • 취업준비
  • 알고리즘
  • 딥러닝
  • 개발자

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
saurus2

Saurus2

[Yolo v3] Object Detection 물체 인식 오픈소스 darknet 소스 분석
컴퓨터공학/딥러닝

[Yolo v3] Object Detection 물체 인식 오픈소스 darknet 소스 분석

2018. 11. 6. 23:29

안녕하세요, 나무토끼 입니다. 

새로운 프로젝트를 위해서 물체인식에 대해서 알아보려고 합니다. 


영상 처리가 필요했기 때문에 OpenCV , 딥러닝 여러 단어들을 검색하다 우연히 발견하게 된 

YOLO v3 , 이것은 다른 딥러닝 기술보다 빠르다고 하고,,, 원리나 내용은 우선 넘어갈게요.


https://github.com/pjreddie/darknet

위의 주소에서 다운로드를 받을 수 있습니다. 


웹 캡을 이용해 실시간으로 물체인식을 수행하는 것도 가능하내요! 

원리나 관련된 기술은 나중에 하는 것으로 하겠습니다. 


1. 소스 ?

YOLO v3는 C언어로 되어 있습니다. 컴파일한 실행파일에 학습 시킨 cfg 파일과 이미지 파일을 입력하면 ,

현재 280개 정도의 아이템이 인식이 되는것 같습니다. 


사람을 인식 하고 싶어서 돌려보니, 몸이 반만 나와도 인식이 되는 듯 합니다. 


1-1 인식 전 사진 :


1-2 인식 후 사진 :


가깝고 물체가 큰 사진들은 대부분 인식이 잘되는 듯 합니다.


2. 컴파일 소스 분석 :

Makefile

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
31
GPU=0
CUDNN=0
OPENCV=0
OPENMP=0
DEBUG=0
 
ARCH= -gencode arch=compute_30,code=sm_30 \
      -gencode arch=compute_35,code=sm_35 \
      -gencode arch=compute_50,code=[sm_50,compute_50] \
      -gencode arch=compute_52,code=[sm_52,compute_52]
#      -gencode arch=compute_20,code=[sm_20,sm_21] \ This one is deprecated?
 
# This is what I use, uncomment if you know your arch and want to specify
# ARCH= -gencode arch=compute_52,code=compute_52
 
VPATH=./src/:./examples
SLIB=libdarknet.so
ALIB=libdarknet.a
EXEC=darknet
OBJDIR=./obj/
 
CC=gcc
CPP=g++
NVCC=nvcc 
AR=ar
ARFLAGS=rcs
OPTS=-Ofast
LDFLAGS= -lm -pthread 
COMMON= -Iinclude/ -Isrc/
CFLAGS=-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC
 
Colored by Color Scripter
cs


컴파일을 위한 Makefile을 보자면,

경로 설정이 src 폴더와 examples 폴더로 설정 되어 있내요.

VPATH=./src/:./examples


그리고 아마 int main << 소스 파일이 구동 되는 곳은 

EXEC=darknet

./example/darknet.c 에 있을 겁니다.



3. Darknet.c (Main 소스 분석) :

Makefile 을 참고하고 Darknet 소스코드 파일을 찾으니 역시나 메인이 여기 있내요.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
int main(int argc, char **argv)
{
    //test_resize("data/bad.jpg");
    //test_box();
    //test_convolutional_layer();
    if(argc < 2){
        fprintf(stderr, "usage: %s <function>\n", argv[0]);
        return 0;
    }
    gpu_index = find_int_arg(argc, argv, "-i", 0);
    if(find_arg(argc, argv, "-nogpu")) {
        gpu_index = -1;
    }
 
#ifndef GPU
    gpu_index = -1;
#else
    if(gpu_index >= 0){
        cuda_set_device(gpu_index);
    }
#endif
 
    if (0 == strcmp(argv[1], "average")){
        average(argc, argv);
    } else if (0 == strcmp(argv[1], "yolo")){
        run_yolo(argc, argv);
    } else if (0 == strcmp(argv[1], "super")){
        run_super(argc, argv);
    } else if (0 == strcmp(argv[1], "lsd")){
        run_lsd(argc, argv);
    } else if (0 == strcmp(argv[1], "detector")){
        run_detector(argc, argv);
    } else if (0 == strcmp(argv[1], "detect")){
        float thresh = find_float_arg(argc, argv, "-thresh", .5);
        char *filename = (argc > 4) ? argv[4]: 0;
        char *outfile = find_char_arg(argc, argv, "-out", 0);
        int fullscreen = find_arg(argc, argv, "-fullscreen");
        test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);
    } else if (0 == strcmp(argv[1], "cifar")){
        run_cifar(argc, argv);
    } else if (0 == strcmp(argv[1], "go")){
        run_go(argc, argv);
    } else if (0 == strcmp(argv[1], "rnn")){
        run_char_rnn(argc, argv);
    } else if (0 == strcmp(argv[1], "coco")){
        run_coco(argc, argv);
    } else if (0 == strcmp(argv[1], "classify")){
        predict_classifier("cfg/imagenet1k.data", argv[2], argv[3], argv[4], 5);
    } else if (0 == strcmp(argv[1], "classifier")){
        run_classifier(argc, argv);
    } else if (0 == strcmp(argv[1], "regressor")){
        run_regressor(argc, argv);
    } else if (0 == strcmp(argv[1], "isegmenter")){
        run_isegmenter(argc, argv);
    } else if (0 == strcmp(argv[1], "segmenter")){
        run_segmenter(argc, argv);
    } else if (0 == strcmp(argv[1], "art")){
        run_art(argc, argv);
    } else if (0 == strcmp(argv[1], "tag")){
        run_tag(argc, argv);
    } else if (0 == strcmp(argv[1], "3d")){
        composite_3d(argv[2], argv[3], argv[4], (argc > 5) ? atof(argv[5]) : 0);
    } else if (0 == strcmp(argv[1], "test")){
        test_resize(argv[2]);
    } else if (0 == strcmp(argv[1], "nightmare")){
        run_nightmare(argc, argv);
    } else if (0 == strcmp(argv[1], "rgbgr")){
        rgbgr_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "reset")){
        reset_normalize_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "denormalize")){
        denormalize_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "statistics")){
        statistics_net(argv[2], argv[3]);
    } else if (0 == strcmp(argv[1], "normalize")){
        normalize_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "rescale")){
        rescale_net(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "ops")){
        operations(argv[2]);
    } else if (0 == strcmp(argv[1], "speed")){
        speed(argv[2], (argc > 3 && argv[3]) ? atoi(argv[3]) : 0);
    } else if (0 == strcmp(argv[1], "oneoff")){
        oneoff(argv[2], argv[3], argv[4]);
    } else if (0 == strcmp(argv[1], "oneoff2")){
        oneoff2(argv[2], argv[3], argv[4], atoi(argv[5]));
    } else if (0 == strcmp(argv[1], "print")){
        print_weights(argv[2], argv[3], atoi(argv[4]));
    } else if (0 == strcmp(argv[1], "partial")){
        partial(argv[2], argv[3], argv[4], atoi(argv[5]));
    } else if (0 == strcmp(argv[1], "average")){
        average(argc, argv);
    } else if (0 == strcmp(argv[1], "visualize")){
        visualize(argv[2], (argc > 3) ? argv[3] : 0);
    } else if (0 == strcmp(argv[1], "mkimg")){
        mkimg(argv[2], argv[3], atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), argv[7]);
    } else if (0 == strcmp(argv[1], "imtest")){
        test_resize(argv[2]);
    } else {
        fprintf(stderr, "Not an option: %s\n", argv[1]);
    }
    return 0;
}
 
 
Colored by Color Scripter
cs


YOLO 공식 홈페이지를 https://pjreddie.com/darknet/yolo/ 보면 단일 이미지 인식 명령어가 이렇게 되어 있습니다. 

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

아까 말씀 드린 것처럼 실행파일은 darknet 으로 컴파일 되어 있고 

인자에 속하는 것들이 4개가 있습니다. 


여기서 볼 것은 1번째와 4번째 인자 입니다. 


3-1. detect

이 인자는 어떤 함수를 돌릴 것인지에 대한 인자 같습니다.  공식 홈페이지에서 비디오와 이미지를 인식시킬때의 인자가 다르기 때문입니다.

./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights <video file>

보시면 이미지의 경우 detect / 그리고 동영상의 경우 detector 를 사용해야 합니다. 


즉, 첫번째 인자 "detect" 를 조건문에 걸려 돌아가게 하는 함수는 test_detector 입니다. 

else if (0 == strcmp(argv[1], "detect")){
        float thresh = find_float_arg(argc, argv, "-thresh", .5);
        char *filename = (argc > 4) ? argv[4]: 0;
        char *outfile = find_char_arg(argc, argv, "-out", 0);
        int fullscreen = find_arg(argc, argv, "-fullscreen");
        test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);


함수를 찾기 위해 저는 Atom 을 사용하여 접근이 쉽도록 하였습니다. 


4. detector.c 

test_detector 함수를 찾아보니 detector.c 파일에 존재 했습니다. 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
{
    list *options = read_data_cfg(datacfg);
    char *name_list = option_find_str(options, "names", "data/names.list");
    char **names = get_labels(name_list);
 
    image **alphabet = load_alphabet();
    network *net = load_network(cfgfile, weightfile, 0);
    set_batch_network(net, 1);
    srand(2222222);
    double time;
    char buff[256];
    char *input = buff;
    float nms=.45;
    while(1){
        if(filename){
            strncpy(input, filename, 256);
        } else {
            printf("Enter Image Path: ");
            fflush(stdout);
            input = fgets(input, 256, stdin);
            if(!input) return;
            strtok(input, "\n");
        }
        image im = load_image_color(input,0,0);
        image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
        layer l = net->layers[net->n-1];
 
 
        float *X = sized.data;
        time=what_time_is_it_now();
        network_predict(net, X);
        printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
        int nboxes = 0;
        detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
        //printf("%d\n", nboxes);
        //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
        if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
        draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
        free_detections(dets, nboxes);
        if(outfile){
            save_image(im, outfile);
        }
        else{
            save_image(im, "predictions");
#ifdef OPENCV
            make_window("predictions", 512, 512, 0);
            show_image(im, "predictions", 0);
#endif
        }
 
        free_image(im);
        free_image(sized);
        if (filename) break;
    }
}
Colored by Color Scripter
cs


물론 이정도 까지만 와서도, 다른 프로젝트에 사용 될 함수나 (단지 이미지 인식만 필요하다면,,,)

인식 프로세스 대해 알 수 있을 것 같습니다. 


4-1 filename

아까 말씀 드렸던 4번째 인자가 사진 파일의 경로이며, 이 함수에서 해당 이미지를 가지고 인식 작업을 시작합니다 .

터미널에서 출력하는 문장들을 봤을때


        float *X = sized.data;
        time=what_time_is_it_now();
        network_predict(net, X);
        printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
        int nboxes = 0;
        detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
        //printf("%d\n", nboxes);
        //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
        if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
        draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
        free_detections(dets, nboxes);

Predicted in %f seconds.

이 문장 전이 이미지를 처리시키는 부분 일 것입니다. 

사실 제가 구현하고 있는 프로젝트는 딥러닝 즉, 이미지 처리 부분까지는 들여다 볼 필요가 없습니다.

제가 필요한 함수는 draw_detections 입니다. 이미지를 처리하고 사진에 박스를 뿌려주는 함수 일텐데,

아마 박스가 가르키는 것이 물체일 것이고, 물체를 활용할 수 있는 부분이라고 생각했습니다.  



5. draw_detections

저는 여기서 소스 코드를 수정하여 이미지에 원하는 물체만 인식시키고, 원하는 갯수를 얻게끔 수정했습니다.

갯수의 출력과, 인식 물체의 이름을 바꾸기만 했습니다. 


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{
    int i,j;
 
    ////////// insert code ////////
    int offset2 = 0*123457 % classes;
    float red2 = get_color(2,offset2,classes);
    float green2 = get_color(1,offset2,classes);
    float blue2 = get_color(0,offset2,classes);
    float rgb2[3];
    //width = prob*20+2;
    rgb2[0] = red2;
    rgb2[1] = green2;
    rgb2[2] = blue2;
 
 
    char person_c[7];
    int person_cnt2 = 0;
 
    //////////////////////////////
 
 
    for(i = 0; i < num; ++i){
        char labelstr[4096] = {0};
        int class = -1;
        for(j = 0; j < classes; ++j){
            if (dets[i].prob[j] > thresh){
                if (class < 0) {
                  /////////////// insert code /////////
                  if(strcmp(names[j],"person") == 0){
                    person_cnt2++;
                    strcat(labelstr, "Smoking_person");
                  }else{
                    strcat(labelstr, names[j]);
                  }
                    class = j;
                } else {
                  /////////////// insert code /////////
                    strcat(labelstr, ", ");
                    if(strcmp(names[j],"person") == 0){
                      person_cnt2++;
                      strcat(labelstr, "Smoking_person");
                    }else{
                      strcat(labelstr, names[j]);
                    }
                }
                if(strcmp(names[j],"person") == 0){
                  printf("%s: %.0f%%\n", "Smoking_person", dets[i].prob[j]*100);
                }else{
                  printf("%s: %.0f%%\n", names[j], dets[i].prob[j]*100);
                }
 
                ///////////////
                printf("total smoking person : %d \n", person_cnt2 );
                ///////////////
            }
        }
 
        if(class >= 0){
            int width = im.h * .006;
            //remove except perso
            if(strcmp(names[class],"person") != 0)
              continue;
 
            /*
               if(0){
               width = pow(prob, 1./2.)*10+1;
               alphabet = 0;
               }
             */
 
            //printf("%d %s: %.0f%%\n", i, names[class], prob*100);
            int offset = class*123457 % classes;
            float red = get_color(2,offset,classes);
            float green = get_color(1,offset,classes);
            float blue = get_color(0,offset,classes);
            float rgb[3];
 
            //width = prob*20+2;
 
            rgb[0] = red;
            rgb[1] = green;
            rgb[2] = blue;
            box b = dets[i].bbox;
            //printf("%f %f %f %f\n", b.x, b.y, b.w, b.h);
 
            int left  = (b.x-b.w/2.)*im.w;
            int right = (b.x+b.w/2.)*im.w;
            int top   = (b.y-b.h/2.)*im.h;
            int bot   = (b.y+b.h/2.)*im.h;
 
            if(left < 0) left = 0;
            if(right > im.w-1) right = im.w-1;
            if(top < 0) top = 0;
            if(bot > im.h-1) bot = im.h-1;
 
            draw_box_width(im, left, top, right, bot, width, red, green, blue);
            if (alphabet) {
                image label = get_label(alphabet, labelstr, (im.h*.03));
                draw_label(im, top + width, left, label, rgb);
                free_image(label);
            }
            if (dets[i].mask){
                image mask = float_to_image(14, 14, 1, dets[i].mask);
                image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
                image tmask = threshold_image(resized_mask, .5);
                embed_image(tmask, im, left, top);
                free_image(mask);
                free_image(resized_mask);
                free_image(tmask);
            }
        }
    }
 
    /////////////// insert code /////////
    sprintf(person_c,"%d",person_cnt2);
    printf("this is nnn %s\n",person_c );
    if (alphabet) {
        image label = get_label(alphabet, person_c, (im.h*.03));
        draw_label(im, 0 + im.h * .006, 0, label, rgb2);
        free_image(label);
    }
}
 
Colored by Color Scripter
cs


다양한 프로젝트에 적용시킬 수 있을 것 같습니다. 물체 인식이 필요한 사진들을 구해 

학습을 시키고, 적당한 함수내에 사진에서 얻고 싶은 정보를 저장하고 서버로 전송 해주는 그런 기능들 일 것 입니다. 


여기까지 ! 

나머지 작업이 끝나면 , 총정리와 github 에 올리겠습니다. 

감사합니다. 

저작자표시 (새창열림)

'컴퓨터공학 > 딥러닝' 카테고리의 다른 글

[맥북] 딥러닝 텐서플로 part 2.  (0) 2021.04.17
[맥북] 딥러닝 텐서플로 part 1.  (0) 2021.04.02
[YOLO v3] 물체 인식 Real-Time Object Detection (Deap Learning) Darknet  (0) 2018.10.31
[골빈해커의 3분 딥러닝 텐서플로맛] Part 2. 텐서플로 설치 / 주피터 노트북  (0) 2018.10.30
[골빈해커의 3분 딥러닝 텐서플로맛] Part 1. 딥러닝 정의 그리고 텐써플로  (0) 2018.10.29
    '컴퓨터공학/딥러닝' 카테고리의 다른 글
    • [맥북] 딥러닝 텐서플로 part 2.
    • [맥북] 딥러닝 텐서플로 part 1.
    • [YOLO v3] 물체 인식 Real-Time Object Detection (Deap Learning) Darknet
    • [골빈해커의 3분 딥러닝 텐서플로맛] Part 2. 텐서플로 설치 / 주피터 노트북
    saurus2
    saurus2
    Simple is Best

    티스토리툴바