diff --git a/README.md b/README.md index 0a1ae52226a..40add052893 100644 --- a/README.md +++ b/README.md @@ -361,10 +361,12 @@ If you customize build with CMake GUI, darknet executable will be installed in y `./darknet detector test cfg/coco.data cfg/yolov4.cfg yolov4.weights -dont_show -ext_output < data/train.txt > result.txt` - To process a video and output results to a json file use: `darknet.exe detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights file.mp4 -dont_show -json_file_output results.json` - Pseudo-labelling - to process a list of images `data/new_train.txt` and save results of detection in Yolo training format for each image as label `.txt` (in this way you can increase the amount of training data) use: - `./darknet detector test cfg/coco.data cfg/yolov4.cfg yolov4.weights -thresh 0.25 -dont_show -save_labels < data/new_train.txt` -- To calculate anchors: `./darknet detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416` -- To check accuracy mAP@IoU=50: `./darknet detector map data/obj.data yolo-obj.cfg backup\yolo-obj_7000.weights` -- To check accuracy mAP@IoU=75: `./darknet detector map data/obj.data yolo-obj.cfg backup\yolo-obj_7000.weights -iou_thresh 0.75` + `darknet.exe detector test cfg/coco.data cfg/yolov4.cfg yolov4.weights -thresh 0.25 -dont_show -save_labels < data/new_train.txt` +* To calculate anchors: `darknet.exe detector calc_anchors data/obj.data -num_of_clusters 9 -width 416 -height 416` +* To check accuracy mAP@IoU=50: `darknet.exe detector map data/obj.data yolo-obj.cfg backup\yolo-obj_7000.weights` +* To check accuracy mAP@IoU=75: `darknet.exe detector map data/obj.data yolo-obj.cfg backup\yolo-obj_7000.weights -iou_thresh 0.75` +* To save the cropped image of the object detected: [`uncomment the following lines of code`](https://github.com/AlexeyAB/darknet/blob/master/src/image_opencv.cpp#L980-L996) +* To run inference on all the images in a folder: `./darknet detector test ./cfg/coco.data ./cfg/yolov4.cfg ./yolov4.weights -i 0 -thresh 0.25 --folder_inference ./result_img/` here `./result_img/` is the path of the folder in which the inference has to be done. the folder name can be anything, as long as it exists. After the inference the images will be moved to `./processed_files/`. To change the folder name or path, the changes cane be done [`here`](https://github.com/AlexeyAB/darknet/blob/master/src/detector.c#L1894). ##### For using network video-camera mjpeg-stream with any Android smartphone diff --git a/include/darknet.h b/include/darknet.h index 55ab50d5da8..7f857bfc1ae 100644 --- a/include/darknet.h +++ b/include/darknet.h @@ -1054,7 +1054,7 @@ LIB_API float *network_predict_image_letterbox(network *net, image im); LIB_API float validate_detector_map(char *datacfg, char *cfgfile, char *weightfile, float thresh_calc_avg_iou, const float iou_thresh, const int map_points, int letter_box, network *existing_net); LIB_API void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear, int dont_show, int calc_map, float thresh, float iou_thresh, int mjpeg_port, int show_imgs, int benchmark_layers, char* chart_path, int mAP_epochs); LIB_API void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, - float hier_thresh, int dont_show, int ext_output, int save_labels, char *outfile, int letter_box, int benchmark_layers); + float hier_thresh, int dont_show, int ext_output, int save_labels, char *outfile, int letter_box, int benchmark_layers, char *folder_inference); LIB_API int network_width(network *net); LIB_API int network_height(network *net); LIB_API void optimize_picture(network *net, image orig, int max_layer, float scale, float rate, float thresh, int norm); diff --git a/src/darknet.c b/src/darknet.c index 392f2e46615..adca181fb72 100644 --- a/src/darknet.c +++ b/src/darknet.c @@ -490,7 +490,8 @@ int main(int argc, char **argv) float thresh = find_float_arg(argc, argv, "-thresh", .24); int ext_output = find_arg(argc, argv, "-ext_output"); char *filename = (argc > 4) ? argv[4]: 0; - test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, 0.5, 0, ext_output, 0, NULL, 0, 0); + char *folder_inference = find_char_arg(argc, argv, "-folder_inference", 0); + test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, 0.5, 0, ext_output, 0, NULL, 0, 0, folder_inference); } else if (0 == strcmp(argv[1], "cifar")){ run_cifar(argc, argv); } else if (0 == strcmp(argv[1], "go")){ diff --git a/src/detector.c b/src/detector.c index 0fc36142904..2e628f8791e 100644 --- a/src/detector.c +++ b/src/detector.c @@ -9,6 +9,10 @@ #include "demo.h" #include "option_list.h" +#ifndef _WIN32 +#include +#endif + #ifndef __COMPAR_FN_T #define __COMPAR_FN_T typedef int (*__compar_fn_t)(const void*, const void*); @@ -19,6 +23,15 @@ typedef __compar_fn_t comparison_fn_t; #include "http_stream.h" +void removeSubstrr (char *string, char *sub) { + char *match; + int len = strlen(sub); + while ((match = strstr(string, sub))) { + *match = '\0'; + strcat(string, match+len); + } +} + static int coco_ids[] = { 1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,70,72,73,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90 }; void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear, int dont_show, int calc_map, float thresh, float iou_thresh, int mjpeg_port, int show_imgs, int benchmark_layers, char* chart_path, int mAP_epochs) @@ -95,7 +108,7 @@ void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, i } int save_after_iterations = option_find_int(options, "saveweights", (net.max_batches < 10000) ? 1000 : 10000 ); // configure when to write weights. Very useful for smaller datasets! - int save_last_weights_after = option_find_int(options, "savelast", 100); + int save_last_weights_after = option_find_int(options, "savelast", 100); printf("Weights are saved after: %d iterations. Last weights (*_last.weight) are stored every %d iterations. \n", save_after_iterations, save_last_weights_after ); @@ -1618,7 +1631,7 @@ void calc_anchors(char *datacfg, int num_of_clusters, int width, int height, int void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, - float hier_thresh, int dont_show, int ext_output, int save_labels, char *outfile, int letter_box, int benchmark_layers) + float hier_thresh, int dont_show, int ext_output, int save_labels, char *outfile, int letter_box, int benchmark_layers, char *folder_inference) { list *options = read_data_cfg(datacfg); char *name_list = option_find_str(options, "names", "data/names.list"); @@ -1654,110 +1667,270 @@ void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filenam } int j; float nms = .45; // 0.4F - while (1) { - if (filename) { - strncpy(input, filename, 256); - if (strlen(input) > 0) - if (input[strlen(input) - 1] == 0x0d) input[strlen(input) - 1] = 0; - } - else { - printf("Enter Image Path: "); - fflush(stdout); - input = fgets(input, 256, stdin); - if (!input) break; - strtok(input, "\n"); - } - //image im; - //image sized = load_image_resize(input, net.w, net.h, net.c, &im); - image im = load_image(input, 0, 0, net.c); - image sized; - if(letter_box) sized = letterbox_image(im, net.w, net.h); - else sized = resize_image(im, net.w, net.h); +#ifndef _WIN32 + if(folder_inference==NULL){ +#endif + while (1) { + if (filename) { + strncpy(input, filename, 256); + if (strlen(input) > 0) + if (input[strlen(input) - 1] == 0x0d) input[strlen(input) - 1] = 0; + } + else { + printf("Enter Image Path: "); + fflush(stdout); + input = fgets(input, 256, stdin); + if (!input) break; + strtok(input, "\n"); + } + //image im; + //image sized = load_image_resize(input, net.w, net.h, net.c, &im); + image im = load_image(input, 0, 0, net.c); + image sized; + if(letter_box) sized = letterbox_image(im, net.w, net.h); + else sized = resize_image(im, net.w, net.h); + + layer l = net.layers[net.n - 1]; + int k; + for (k = 0; k < net.n; ++k) { + layer lk = net.layers[k]; + if (lk.type == YOLO || lk.type == GAUSSIAN_YOLO || lk.type == REGION) { + l = lk; + printf(" Detection layer: %d - type = %d \n", k, l.type); + } + } - layer l = net.layers[net.n - 1]; - int k; - for (k = 0; k < net.n; ++k) { - layer lk = net.layers[k]; - if (lk.type == YOLO || lk.type == GAUSSIAN_YOLO || lk.type == REGION) { - l = lk; - printf(" Detection layer: %d - type = %d \n", k, l.type); + //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] = (float*)xcalloc(l.classes, sizeof(float)); + + float *X = sized.data; + + //time= what_time_is_it_now(); + double time = get_time_point(); + network_predict(net, X); + //network_predict_image(&net, im); letterbox = 1; + printf("%s: Predicted in %lf milli-seconds.\n", input, ((double)get_time_point() - time) / 1000); + //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, letter_box); + if (nms) { + if (l.nms_kind == DEFAULT_NMS) do_nms_sort(dets, nboxes, l.classes, nms); + else diounms_sort(dets, nboxes, l.classes, nms, l.nms_kind, l.beta_nms); + } + draw_detections_v3(im, dets, nboxes, thresh, names, alphabet, l.classes, ext_output); + save_image(im, "predictions"); + if (!dont_show) { + show_image(im, "predictions"); } - } - //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] = (float*)xcalloc(l.classes, sizeof(float)); + if (json_file) { + if (json_buf) { + char *tmp = ", \n"; + fwrite(tmp, sizeof(char), strlen(tmp), json_file); + } + ++json_image_id; + json_buf = detection_to_json(dets, nboxes, l.classes, names, json_image_id, input); - float *X = sized.data; + fwrite(json_buf, sizeof(char), strlen(json_buf), json_file); + free(json_buf); + } - //time= what_time_is_it_now(); - double time = get_time_point(); - network_predict(net, X); - //network_predict_image(&net, im); letterbox = 1; - printf("%s: Predicted in %lf milli-seconds.\n", input, ((double)get_time_point() - time) / 1000); - //printf("%s: Predicted in %f seconds.\n", input, (what_time_is_it_now()-time)); + // pseudo labeling concept - fast.ai + if (save_labels) + { + char labelpath[4096]; + replace_image_to_label(input, labelpath); + + FILE* fw = fopen(labelpath, "wb"); + int i; + for (i = 0; i < nboxes; ++i) { + char buff[1024]; + int class_id = -1; + float prob = 0; + for (j = 0; j < l.classes; ++j) { + if (dets[i].prob[j] > thresh && dets[i].prob[j] > prob) { + prob = dets[i].prob[j]; + class_id = j; + } + } + if (class_id >= 0) { + sprintf(buff, "%d %2.4f %2.4f %2.4f %2.4f\n", class_id, dets[i].bbox.x, dets[i].bbox.y, dets[i].bbox.w, dets[i].bbox.h); + fwrite(buff, sizeof(char), strlen(buff), fw); + } + } + fclose(fw); + } - int nboxes = 0; - detection *dets = get_network_boxes(&net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes, letter_box); - if (nms) { - if (l.nms_kind == DEFAULT_NMS) do_nms_sort(dets, nboxes, l.classes, nms); - else diounms_sort(dets, nboxes, l.classes, nms, l.nms_kind, l.beta_nms); - } - draw_detections_v3(im, dets, nboxes, thresh, names, alphabet, l.classes, ext_output); - save_image(im, "predictions"); - if (!dont_show) { - show_image(im, "predictions"); + free_detections(dets, nboxes); + free_image(im); + free_image(sized); + + if (!dont_show) { + wait_until_press_key_cv(); + destroy_all_windows_cv(); + } + + if (filename) break; } if (json_file) { - if (json_buf) { - char *tmp = ", \n"; - fwrite(tmp, sizeof(char), strlen(tmp), json_file); - } - ++json_image_id; - json_buf = detection_to_json(dets, nboxes, l.classes, names, json_image_id, input); + char *tmp = "\n]"; + fwrite(tmp, sizeof(char), strlen(tmp), json_file); + fclose(json_file); + } - fwrite(json_buf, sizeof(char), strlen(json_buf), json_file); - free(json_buf); + // free memory + free_ptrs((void**)names, net.layers[net.n - 1].classes); + free_list_contents_kvp(options); + free_list(options); + + int i; + const int nsize = 8; + for (j = 0; j < nsize; ++j) { + for (i = 32; i < 127; ++i) { + free_image(alphabet[j][i]); + } + free(alphabet[j]); } + free(alphabet); - // pseudo labeling concept - fast.ai - if (save_labels) - { - char labelpath[4096]; - replace_image_to_label(input, labelpath); + free_network(net); +#ifndef _WIN32 + } + else{ + + DIR *folder; + struct dirent *entry; + int files = 0; + + while (1) { + folder = opendir(folder_inference); + if(folder){ + while( (entry=readdir(folder)) != NULL){ + char str1[1024] = ""; + strncpy(str1,folder_inference,strlen(folder_inference)); + char cwd[100]=""; + strncpy(cwd,entry->d_name,strlen(entry->d_name)); + if(strcmp(cwd,".")==0 || strcmp(cwd,"..")==0){ + continue; + } - FILE* fw = fopen(labelpath, "wb"); - int i; - for (i = 0; i < nboxes; ++i) { - char buff[1024]; - int class_id = -1; - float prob = 0; - for (j = 0; j < l.classes; ++j) { - if (dets[i].prob[j] > thresh && dets[i].prob[j] > prob) { - prob = dets[i].prob[j]; - class_id = j; + strcat(str1, entry->d_name); + strncpy(input, str1, 256); + //closedir(folder); + if (strlen(input) > 0) + if (input[strlen(input) - 1] == 0x0d) input[strlen(input) - 1] = 0; + + + //image im; + //image sized = load_image_resize(input, net.w, net.h, net.c, &im); + image im = load_image(input, 0, 0, net.c); + image sized; + if(letter_box) sized = letterbox_image(im, net.w, net.h); + else sized = resize_image(im, net.w, net.h); + + layer l = net.layers[net.n - 1]; + int k; + for (k = 0; k < net.n; ++k) { + layer lk = net.layers[k]; + if (lk.type == YOLO || lk.type == GAUSSIAN_YOLO || lk.type == REGION) { + l = lk; + printf(" Detection layer: %d - type = %d \n", k, l.type); + } + } + + //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] = (float*)xcalloc(l.classes, sizeof(float)); + + float *X = sized.data; + + //time= what_time_is_it_now(); + double time = get_time_point(); + network_predict(net, X); + //network_predict_image(&net, im); letterbox = 1; + printf("%s: Predicted in %lf milli-seconds.\n", input, ((double)get_time_point() - time) / 1000); + //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, letter_box); + if (nms) { + if (l.nms_kind == DEFAULT_NMS) do_nms_sort(dets, nboxes, l.classes, nms); + else diounms_sort(dets, nboxes, l.classes, nms, l.nms_kind, l.beta_nms); } + draw_detections_v3(im, dets, nboxes, thresh, names, alphabet, l.classes, ext_output); + save_image(im, "predictions"); + if (!dont_show) { + show_image(im, "predictions"); + } + + if (json_file) { + if (json_buf) { + char *tmp = ", \n"; + fwrite(tmp, sizeof(char), strlen(tmp), json_file); + } + ++json_image_id; + json_buf = detection_to_json(dets, nboxes, l.classes, names, json_image_id, input); + + fwrite(json_buf, sizeof(char), strlen(json_buf), json_file); + free(json_buf); + } + + // pseudo labeling concept - fast.ai + if (save_labels){ + char labelpath[4096]; + replace_image_to_label(input, labelpath); + + FILE* fw = fopen(labelpath, "wb"); + int i; + for (i = 0; i < nboxes; ++i) { + char buff[1024]; + int class_id = -1; + float prob = 0; + for (j = 0; j < l.classes; ++j) { + if (dets[i].prob[j] > thresh && dets[i].prob[j] > prob) { + prob = dets[i].prob[j]; + class_id = j; + } + } + if (class_id >= 0) { + sprintf(buff, "%d %2.4f %2.4f %2.4f %2.4f\n", class_id, dets[i].bbox.x, dets[i].bbox.y, dets[i].bbox.w, dets[i].bbox.h); + fwrite(buff, sizeof(char), strlen(buff), fw); + } + } + fclose(fw); + } + + + free_detections(dets, nboxes); + free_image(im); + free_image(sized); + + if (dont_show) { + wait_until_press_key_cv(); + destroy_all_windows_cv(); } - if (class_id >= 0) { - sprintf(buff, "%d %2.4f %2.4f %2.4f %2.4f\n", class_id, dets[i].bbox.x, dets[i].bbox.y, dets[i].bbox.w, dets[i].bbox.h); - fwrite(buff, sizeof(char), strlen(buff), fw); + char newname[100]; + removeSubstrr(str1, folder_inference); + sprintf(newname, "./processed_files/%s",str1); + rename (input, newname); } + closedir(folder); } - fclose(fw); } - free_detections(dets, nboxes); - free_image(im); - free_image(sized); - - if (!dont_show) { - wait_until_press_key_cv(); - destroy_all_windows_cv(); + if (json_file) { + char *tmp = "\n]"; + fwrite(tmp, sizeof(char), strlen(tmp), json_file); + fclose(json_file); } - if (filename) break; - } + // free memory + free_ptrs((void**)names, net.layers[net.n - 1].classes); + free_list_contents_kvp(options); + free_list(options); if (json_file) { char *tmp = "\n]"; @@ -1772,6 +1945,8 @@ void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filenam free_alphabet(alphabet); free_network(net); } +#endif +} #if defined(OPENCV) && defined(GPU) @@ -1966,6 +2141,7 @@ void run_detector(int argc, char **argv) char *json_file_output = find_char_arg(argc, argv, "-json_file_output", 0); char *outfile = find_char_arg(argc, argv, "-out", 0); char *prefix = find_char_arg(argc, argv, "-prefix", 0); + char *folder_inference = find_char_arg(argc, argv, "-folder_inference", 0); float thresh = find_float_arg(argc, argv, "-thresh", .25); // 0.24 float iou_thresh = find_float_arg(argc, argv, "-iou_thresh", .5); // 0.5 for mAP float hier_thresh = find_float_arg(argc, argv, "-hier", .5); @@ -2018,8 +2194,8 @@ void run_detector(int argc, char **argv) if (strlen(weights) > 0) if (weights[strlen(weights) - 1] == 0x0d) weights[strlen(weights) - 1] = 0; char *filename = (argc > 6) ? argv[6] : 0; - if (0 == strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, dont_show, ext_output, save_labels, outfile, letter_box, benchmark_layers); - else if (0 == strcmp(argv[2], "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear, dont_show, calc_map, thresh, iou_thresh, mjpeg_port, show_imgs, benchmark_layers, chart_path, mAP_epochs); + if (0 == strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, dont_show, ext_output, save_labels, outfile, letter_box, benchmark_layers, folder_inference); + else if (0 == strcmp(argv[2], "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear, dont_show, calc_map, thresh, iou_thresh,mjpeg_port, show_imgs, benchmark_layers, chart_path, mAP_epochs); else if (0 == strcmp(argv[2], "valid")) validate_detector(datacfg, cfg, weights, outfile); else if (0 == strcmp(argv[2], "recall")) validate_detector_recall(datacfg, cfg, weights); else if (0 == strcmp(argv[2], "map")) validate_detector_map(datacfg, cfg, weights, thresh, iou_thresh, map_points, letter_box, NULL); diff --git a/src/image_opencv.cpp b/src/image_opencv.cpp index 22e6ca53570..6d298e24734 100644 --- a/src/image_opencv.cpp +++ b/src/image_opencv.cpp @@ -996,12 +996,14 @@ extern "C" void draw_detections_cv_v3(mat_cv* mat, detection *dets, int num, flo color.val[2] = blue * 256; // you should create directory: result_img + //converting cv::Mat type to Iplimage type + //IplImage* ipltypeimg = new IplImage(*show_img); //static int copied_frame_id = -1; //static IplImage* copy_img = NULL; //if (copied_frame_id != frame_id) { // copied_frame_id = frame_id; - // if(copy_img == NULL) copy_img = cvCreateImage(cvSize(show_img->width, show_img->height), show_img->depth, show_img->nChannels); - // cvCopy(show_img, copy_img, 0); + // if(copy_img == NULL) copy_img = cvCreateImage(cvSize(ipltypeimg->width, ipltypeimg->height), ipltypeimg->depth, ipltypeimg->nChannels); + // cvCopy(ipltypeimg, copy_img, 0); //} //static int img_id = 0; //img_id++;