[Object Detection / YOLO DARKNET] object detection code review :: read_data_cfg -[1]
[Object Detection / YOLO DARKNET] object detection code review :: read_data_cfg -[2]
이번 포스팅은 char *name_list = option_find_str에 대한 코드 리뷰를 진행하겠습니다.
1. Concept Overview
2. test_detector :: examples/detector.c
현재 우리는 YOLO Darknet 코드 상에서 detector.c의 test_detector 파트만 코드 리뷰를 하고 있는 중입니다.
test_detector 파트의 코드는 아래와 같습니다.
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; int j; float nms=.3; 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]; box *boxes = calloc(l.w*l.h*l.n, sizeof(box)); float **probs = calloc(l.w*l.h*l.n, sizeof(float *)); for(j = 0; j < l.w*l.h*l.n; ++j) probs[j] = calloc(l.classes + 1, sizeof(float *)); float **masks = 0; if (l.coords > 4){ masks = calloc(l.w*l.h*l.n, sizeof(float*)); for(j = 0; j < l.w*l.h*l.n; ++j) masks[j] = calloc(l.coords-4, sizeof(float *)); } 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); get_region_boxes(l, im.w, im.h, net->w, net->h, thresh, probs, boxes, masks, 0, 0, hier_thresh, 1); //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms); if (nms) do_nms_sort(boxes, probs, l.w*l.h*l.n, l.classes, nms); draw_detections(im, l.w*l.h*l.n, thresh, boxes, probs, masks, names, alphabet, l.classes); if(outfile){ save_image(im, outfile); } else{ save_image(im, "predictions"); #ifdef OPENCV cvNamedWindow("predictions", CV_WINDOW_NORMAL); if(fullscreen){ cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN); } show_image(im, "predictions"); cvWaitKey(0); cvDestroyAllWindows(); #endif } free_image(im); free_image(sized); free(boxes); free_ptrs((void **)probs, l.w*l.h*l.n); if (filename) break; } }
여기서 저번 포스팅까지는 1번째 라인의 list *options = read_data_cfg(datacfg) 에 대한 코드 리뷰를 진행하였습니다.
이번 포스팅은 그 아래 2번째 라인의 char *name_list = option_find_str(options, "names", "data/names.list") 함수에 대해서 리뷰하도록 하겠습니다.
3. option_find_str :: src/option_list.c
option_find_str의 구성은 다음과 같습니다.
char *option_find_str(list *l, char *key, char *def) { char *v = option_find(l, key); if(v) return v; if(def) fprintf(stderr, "%s: Using default '%s'\n", key, def); return def; }
1. list 구조체 l과 key값을 인자로 option_find함수를 실행하여, 반환값을 char *타입의 변수 v에 넣습니다.
2. 만약에 v에 값이 있다면 v를 반환하고 함수를 종료합니다.
3. 만약에 v에 값이 없다면 default값을 사용한다는 알람을 출력하고 나서, def값을 반환하고 함수를 종료합니다.
4. option_find : src/option_list.c
option_find의 구성은 아래와 같습니다.
char *option_find(list *l, char *key) { node *n = l->front; while(n){ kvp *p = (kvp *)n->val; if(strcmp(p->key, key) == 0){ p->used = 1; return p->val; } n = n->next; } return 0; }
1. node 구조체 포인터 n을 생성한 후에, 파라미터로 받은 리스트 구조체의 멤버 front를 대입합니다.
2. n이 존재한다면 계속 순회를 돕니다.
3. kvp 구조체 포인터 p를 생성하고, node구조체의 val값을 kvp 구조체 포인터로 캐스팅하여 대입합니다.
4. kvp 구조체 포인터 p의 멤버 key와 함수 파라미터로 받은 key값, 즉 문자열이 같다면 kvp 구조체 멤버의 p값의 used를 사용했다는 값인 1로 변경해주고 kvp 구조체의 멤버 val값을 돌려주고 함수를 종료합니다.
5. kvp 구조체 포인터 p의 멤버 key와 함수 파라미터로 받은 key값, 즉 문자열이 같지 않다면 node 구조체 포인터의 값을 다음 노드의 값으로 변경합니다.
6. 순회를 모두 돌았는데, 해당하는 option을 찾을 수도 없다면 0을 반환하고 함수를 종료합니다.