├── .gitattributes ├── .gitignore ├── README.md ├── example └── main.cpp └── wrapper ├── darknet.cpp ├── darknet.h ├── darknet_detector.c └── darknet_detector.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Darknet C++ Wrapper 2 | A small C++ wrapper for detecting objects using pjreddie/darknet detector (yolo v2), for use in UTAT project. 3 | 4 | # Installation: 5 | 1. **Download and make sure you can compile and run darknet yolo.
** 6 | Links:
7 | http://pjreddie.com/darknet/yolo/
8 | https://github.com/pjreddie/darknet 9 | 10 | Note: OpenCV and GPU(CUDA) must be enabled when compiling.
11 | 12 | 2. **Make a copy of the darknet source code, including the make file.
** 13 | The following steps are performed on this copy, unless stated otherwise. 14 | 15 | 3. **Remove or rename the main function in the darknet source code.
** 16 | There is a main function in the original darknet. In order to use darknet as a library, this function must be removed or renamed. For example, rename this function to _main instead of main.
17 | The function is located in `src/darknet.c`. 18 | 19 | 4. **Copy the content inside `wrapper` folder to somewhere near the source file.
** 20 | This location will need to be manually added to the make file in later steps. 21 | 22 | 5. **Add your own C++ file in the same location, include `darknet.h`, and use the `Darknet` class.
** 23 | See `example/main.cpp` for example usage. 24 | 25 | 6. **Add your source code / folder to the make file manually.
** 26 | Make sure to use g++ instead of gcc for compiling the .cpp files. 27 | 28 | 7. **Compile and run!** 29 | 30 | 8. **To train the network, use the original darknet application.** 31 | 32 | # Reference: 33 | ## Darknet class 34 | ### Example: 35 | See `example.cpp` for an example program that reads image from the webcam using OpenCV, detects objects using darknet, and visualizes the detection. 36 | 37 | ### Methods: 38 | * **static Darknet\* get_current()
** 39 | Returns the current instance of darknet.
40 | Returns `nullptr` if none are instantiated. 41 | 42 | * **Darknet()
** 43 | Default constructor.
44 | The `initialize` method must be called before darknet is used.
45 | Note: Only one instance can be constructed. 46 | 47 | * **~Darknet()
** 48 | Default destructor. 49 | 50 | * **void initialize(int gpu_id = 0)
** 51 | Initializes darknet with the given `gpu_id`.
52 | This method cannot be called more than once. 53 | 54 | **Parameters:** 55 | * **int gpu_id
** 56 | The default GPU id to be used in computation. 57 | 58 | * **void load_command_args(int argc, char\*\* argv)
** 59 | Sets the object properties of darknet using command line arguments in the command format of the original darknet application. 60 | 61 | See original darknet documentation for detail. 62 | 63 | **Parameters:** 64 | * **int argc
** 65 | Number of arguments. 66 | 67 | * **char\*\* argv
** 68 | list of arguments in the form of an array of C-style strings. 69 | 70 | * **void load_command_args(const std::vector& args)
** 71 | This is an overloaded method. Instead of using C-style command arguments, this method parses a `std::vector` list of C++ strings for convenience. 72 | 73 | * **void run()
** 74 | Runs the darknet application using the object properties as parameters.
75 | Depending on the `operation` property, the behavior of this method may vary.
76 | This method cannot be called more than once. 77 | 78 | * **void process(cv::Mat& image, process_func_ptr process_func = nullptr)
** 79 | If `module` is set to "detector" and `operation` is set to "detect", calling this function will process `image` by detecting objects using darknet's neural network and calling `process_func` with the detected data, including object names, positions and bounding boxes, and confidences (probabilities).
80 | If `module` and `operation` is in other configurations, this method has no effect.
81 | `run` must be called before this method. 82 | 83 | **Parameters:** 84 | * **cv::Mat& image
** 85 | The OpenCV image to be processed. 86 | 87 | * **process_func_ptr process_func
** 88 | The callback function to be used in processing the data.
89 | Format of the callback function:
90 | void process_func(int num, const char** names, box* boxes, float* probs) 91 | 92 | **Parameters:** 93 | * **int num
** 94 | Number of objects detected. 95 | 96 | * **const char\*\* names
** 97 | An array of C-styled strings. Length is `num`.
98 | Contains names of the objects detected. 99 | 100 | * **box\* boxes
** 101 | An array of `box`. Length is `num`.
102 | Contains bounding boxes of the object detected.
103 | `box` is a struct with 4 properties: 104 | * **x: x coordinate of the center.** 105 | * **y: y coordinate of the center.** 106 | * **w: width of the bounding box.** 107 | * **h: height of the bounding box.** 108 | 109 | All properties are in the range of 0.0 to 1.0, where 1.0 is the full width/height of the image. 110 | 111 | * **float* probs
** 112 | An array of floats. Length is `num`.
113 | Contains the confidence/probability of the objects detected. 114 | 115 | ### Properties: 116 | * **std::string module
** 117 | The darknet module/option to use.
118 | Corresponds to the first argument in darknet command.
119 | Valid values: 120 | * **"detector"** 121 | 122 | * **std::string operation
** 123 | The detector operation to use.
124 | Corresponds to the second argument in darknet command.
125 | Valid values: 126 | * **"detect"** 127 | * **"test"** 128 | * **"train"** 129 | * **"valid"** 130 | * **"recall"** 131 | 132 | * **std::string datacfg
** 133 | The path to the data config file.
134 | Example: "cfg/coco.data" 135 | 136 | * **std::string cfg
** 137 | The path to the neural network config file.
138 | Example: "cfg/yolo.cfg" 139 | 140 | * **std::string weights
** 141 | The path to the trained weights file.
142 | Example: "yolo.weights" 143 | 144 | * **std::string prefix
** 145 | If this property is not an empty string, visualization of each frame processed will be saved to hard drive, with this property being the prefix for the name of the files.
146 | (Untested) 147 | 148 | * **float thresh
** 149 | The confidence threshold for detection. Any detected objects with confidence (probably) lower than this property will be discarded.
150 | Default: 0.24. 151 | 152 | * **int frame_skip
** 153 | (Unknown) 154 | 155 | * **bool visualize
** 156 | If true, a window will be opened that shows detected objects in each frame processed. 157 | 158 | * **bool multithread
** 159 | If true, multi-threading will be used to improve performance.
160 | Note: this will make each process call processes the second last image passed in.
161 | (Experimental) 162 | 163 | * **std::string gpu_list
** 164 | A list of GPUs to use in computation. Separate the GPU indexes with commas.
165 | (Untested) 166 | 167 | * **bool clear
** 168 | (Unknown) 169 | 170 | -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | #include "darknet.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | using namespace cv; 11 | 12 | VideoCapture camera; 13 | 14 | void process_func(int num, const char** names, box* boxes, float* probs) 15 | { 16 | for (int i = 0; i < num; ++i){ 17 | const char* name = names[i]; 18 | box bound = boxes[i]; 19 | float prob = probs[i]; 20 | printf("%s \t%f,%f,%f,%f \t%f\n", name, bound.x, bound.y, bound.w, bound.h, prob); 21 | } 22 | } 23 | 24 | Darknet darknet; 25 | 26 | int main(int argc, char **argv) 27 | { 28 | Mat img, img_out; 29 | 30 | // - Setup sharpening kernel 31 | Mat sharpen_kernel; 32 | sharpen_kernel = (Mat_(3, 3) << 0, -1, 0, 33 | -1, 5, -1, 34 | 0, -1, 0); 35 | 36 | // - Open the default camera 37 | camera.open(0); 38 | if (!camera.isOpened()) throw "Camera cannot be opened."; 39 | 40 | // - Initialize darknet 41 | darknet.initialize(0); 42 | 43 | // - Using vector to load commands: 44 | /* 45 | vector args = {"darknet", "detector", "detect", "-v", "cfg/coco.data", "cfg/yolo.cfg", "yolo.weights"}; 46 | darknet.load_command_args(args); 47 | */ 48 | 49 | // - Manually setting properties: 50 | /* 51 | darknet.module = "detector"; 52 | darknet.operation = "detect"; 53 | darknet.visualize = true; 54 | darknet.datacfg = "cfg/coco.data"; 55 | darknet.cfg = "cfg/yolo.cfg"; 56 | darknet.weights = "yolo.weights"; 57 | */ 58 | 59 | // - Load commands with traditional command line arguments format: 60 | darknet.load_command_args(argc, argv); 61 | darknet.run(); 62 | 63 | while(true){ 64 | // - Read from camera 65 | camera >> img; 66 | 67 | // - Sharpen the image with OpenCV 68 | filter2D(img, img_out, img.depth(), sharpen_kernel); 69 | 70 | // - Process the image with darknet 71 | darknet.process(img_out, process_func); 72 | 73 | waitKey(30); 74 | } 75 | 76 | return 0; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /wrapper/darknet.cpp: -------------------------------------------------------------------------------- 1 | #include "darknet.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | void show_error(char* msg) 10 | { 11 | std::cerr << msg << std::endl; 12 | throw msg; 13 | } 14 | 15 | char* c_str_copy(const std::string& str) 16 | { 17 | if (!str.size()) return nullptr; 18 | 19 | char* result = new char[str.size() + 1]; 20 | strcpy(result, str.c_str()); 21 | return result; 22 | } 23 | 24 | 25 | Darknet* Darknet::m_current = nullptr; 26 | cv::Mat* Darknet::m_mat = nullptr; 27 | 28 | Darknet* Darknet::get_current() 29 | { 30 | return Darknet::m_current; 31 | } 32 | 33 | Darknet::Darknet() 34 | { 35 | if (Darknet::m_current == nullptr){ 36 | Darknet::m_current = this; 37 | 38 | m_initialized = false; 39 | 40 | this->module = "detector"; 41 | this->thresh = 0.24f; 42 | this->frame_skip = 0; 43 | this->visualize = false; 44 | this->multithread = false; 45 | this->clear = false; 46 | } 47 | else { 48 | show_error("Darknet cannot be instantiated more than once."); 49 | } 50 | } 51 | 52 | Darknet::~Darknet() 53 | { 54 | 55 | } 56 | 57 | void Darknet::initialize(int gpu_id) 58 | { 59 | if (m_initialized) show_error("Darknet cannot be initialized more than once."); 60 | m_initialized = true; 61 | 62 | detector_initialize(gpu_id); 63 | } 64 | 65 | void Darknet::validate_initialized() 66 | { 67 | if (!m_initialized) show_error("Darknet needs to be initialized before use."); 68 | } 69 | 70 | void Darknet::validate_running() 71 | { 72 | if (!m_running) show_error("Darknet needs to be running."); 73 | } 74 | 75 | void Darknet::load_command_args(int argc, char** argv) 76 | { 77 | validate_initialized(); 78 | 79 | if (argc < 2) { 80 | fprintf(stderr, "usage: %s \n", argv[0]); 81 | return; 82 | } 83 | if(argc < 4){ 84 | fprintf(stderr, "detector usage: %s %s [train/test/valid] [cfg] [weights (optional)]\n", argv[0], argv[1]); 85 | return; 86 | } 87 | 88 | // TODO what happens when std::string is met with a nullptr? 89 | // std::cout << "hello" << std::endl; 90 | this->prefix = std::string(find_char_arg(argc, argv, "-prefix", "")); 91 | this->thresh = find_float_arg(argc, argv, "-thresh", .24); 92 | this->frame_skip = find_int_arg(argc, argv, "-s", 0); 93 | this->visualize = find_arg(argc, argv, "-v"); 94 | this->multithread = find_arg(argc, argv, "-m"); 95 | this->gpu_list = std::string(find_char_arg(argc, argv, "-gpus", "")); 96 | this->clear = find_arg(argc, argv, "-clear"); 97 | 98 | this->module = argv[1]; 99 | if (this->module == "detector"){ 100 | this->operation = argv[2]; 101 | this->datacfg = argv[3]; 102 | this->cfg = argv[4]; 103 | this->weights = (argc > 5 && argv[5]) ? argv[5] : ""; 104 | // this->filename = (argc > 6 && argv[6]) ? argv[6] : ""; 105 | } 106 | else { 107 | fprintf(stderr, "Not an option: %s\n", this->module.c_str()); 108 | } 109 | } 110 | 111 | void Darknet::load_command_args(const std::vector& args) 112 | { 113 | int argc = args.size(); 114 | char** argv = new char*[argc]; 115 | 116 | for (int i = 0; i < argc; ++i){ 117 | const std::string& str = args[i]; 118 | 119 | char* arg = new char[str.size() + 1]; 120 | strcpy(arg, str.c_str()); 121 | 122 | argv[i] = arg; 123 | } 124 | 125 | load_command_args(argc, argv); 126 | 127 | for (int i = 0; i < argc; ++i){ 128 | delete argv[i]; 129 | } 130 | delete[] argv; 131 | } 132 | 133 | void Darknet::run() 134 | { 135 | validate_initialized(); 136 | 137 | if (m_running) show_error("Darknet is already running."); 138 | m_running = true; 139 | 140 | if (this->module == "detector") { 141 | // TODO: make temp c_str from c++ string 142 | char* module = c_str_copy(this->module); 143 | char* operation = c_str_copy(this->operation); 144 | char* datacfg = c_str_copy(this->datacfg); 145 | char* cfg = c_str_copy(this->cfg); 146 | char* weights = c_str_copy(this->weights); 147 | // char* filename = c_str_copy(this->filename); 148 | char* prefix = c_str_copy(this->prefix); 149 | char* gpu_list = c_str_copy(this->gpu_list); 150 | 151 | detector_main(module, operation, datacfg, cfg, weights, 0, prefix, this->thresh, this->frame_skip, gpu_list, this->clear, this->visualize, this->multithread); 152 | 153 | // TODO: delete those temp stuffs OR NOT CUZ WE MIGHT NEED IT 154 | /* delete module; 155 | delete operation; 156 | delete datacfg; 157 | delete cfg; 158 | delete weights; 159 | delete filename; 160 | delete prefix; 161 | delete gpu_list; */ 162 | } 163 | else { 164 | fprintf(stderr, "Not an option: %s\n", this->module.c_str()); 165 | } 166 | } 167 | 168 | void Darknet::mat_to_image(image* img) 169 | { 170 | if (!m_mat) return; 171 | 172 | CV_Assert(m_mat->depth() == CV_8U); 173 | 174 | const int h = m_mat->rows; 175 | const int w = m_mat->cols; 176 | const int channels = m_mat->channels(); 177 | 178 | *img = make_image(w, h, 3); 179 | 180 | int count = 0; 181 | 182 | switch(channels){ 183 | case 1:{ 184 | cv::MatIterator_ it, end; 185 | for (it = m_mat->begin(), end = m_mat->end(); it != end; ++it){ 186 | img->data[count] = img->data[w*h + count] = img->data[w*h*2 + count] = (float)(*it)/255.0; 187 | 188 | ++count; 189 | } 190 | break; 191 | } 192 | 193 | case 3:{ 194 | cv::MatIterator_ it, end; 195 | for (it = m_mat->begin(), end = m_mat->end(); it != end; ++it){ 196 | img->data[count] = (float)(*it)[2]/255.0; 197 | img->data[w*h + count] = (float)(*it)[1]/255.0; 198 | img->data[w*h*2 + count] = (float)(*it)[0]/255.0; 199 | 200 | ++count; 201 | } 202 | break; 203 | } 204 | 205 | default: 206 | show_error("Channel number not supported."); 207 | break; 208 | } 209 | } 210 | 211 | void Darknet::process(cv::Mat& image, process_func_ptr process_func) 212 | { 213 | validate_initialized(); 214 | validate_running(); 215 | 216 | m_mat = ℑ 217 | 218 | detector_update(process_func, mat_to_image); 219 | } 220 | -------------------------------------------------------------------------------- /wrapper/darknet.h: -------------------------------------------------------------------------------- 1 | #ifndef DARKNET_CPP 2 | #define DARKNET_CPP 3 | 4 | extern "C" { 5 | #include "darknet_detector.h" 6 | } 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class Darknet 13 | { 14 | public: 15 | static Darknet* get_current(); 16 | 17 | Darknet(); 18 | ~Darknet(); 19 | 20 | void initialize(int gpu_id = 0); 21 | void load_command_args(int argc, char** argv); 22 | void load_command_args(const std::vector& args); 23 | void run(); 24 | void process(cv::Mat& image, process_func_ptr process_func = nullptr); 25 | 26 | std::string module; 27 | std::string operation; 28 | std::string datacfg; 29 | std::string cfg; 30 | std::string weights; 31 | // std::string filename; 32 | std::string prefix; 33 | 34 | float thresh; 35 | int frame_skip; 36 | bool visualize; 37 | bool multithread; 38 | std::string gpu_list; 39 | bool clear; 40 | 41 | private: 42 | static Darknet* m_current; 43 | 44 | bool m_initialized, m_running; 45 | // process_func_ptr m_process_func; 46 | 47 | static cv::Mat* m_mat; 48 | 49 | static void mat_to_image(image* img); 50 | 51 | void validate_initialized(); 52 | void validate_running(); 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /wrapper/darknet_detector.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "detection_layer.h" 3 | #include "region_layer.h" 4 | #include "cost_layer.h" 5 | #include "utils.h" 6 | #include "parser.h" 7 | #include "box.h" 8 | #include "image.h" 9 | #include "option_list.h" 10 | 11 | #include "darknet_detector.h" 12 | //#include 13 | // #include 14 | // #include 15 | // #include "gettimeofday.h" 16 | 17 | #include "cuda.h" 18 | 19 | #define FRAMES 3 20 | 21 | #ifdef OPENCV 22 | #include "opencv2/highgui/highgui_c.h" 23 | #include "opencv2/imgproc/imgproc_c.h" 24 | image get_image_from_stream(CvCapture *cap); 25 | 26 | static char **demo_names; 27 | static image **demo_alphabet; 28 | static int demo_classes; 29 | 30 | static int count; 31 | 32 | static int num; 33 | static int num_out = 0; 34 | 35 | /* static int running = 0; */ 36 | 37 | static const char** names_out; 38 | 39 | static process_func_ptr process_func; 40 | static fetch_func_ptr fetch_func; 41 | 42 | static float **probs; 43 | static float* probs_out; 44 | static box *boxes; 45 | static box* boxes_out; 46 | static network net; 47 | static image in ; 48 | static image in_s ; 49 | static image det ; 50 | static image det_s; 51 | static image disp = {0}; 52 | static CvCapture * cap; 53 | // static float fps = 0; 54 | static float demo_thresh = 0; 55 | 56 | static pthread_t fetch_thread; 57 | static pthread_t detect_thread; 58 | static pthread_t process_thread; 59 | 60 | static float *predictions[FRAMES]; 61 | static int demo_index = 0; 62 | static image images[FRAMES]; 63 | static float *avg; 64 | 65 | static char* demo_prefix; 66 | static int demo_frame_skip; 67 | static char* window_name; 68 | 69 | static int delay; 70 | 71 | static int visualize = 0; 72 | static int multithread = 0; 73 | 74 | static int updatable = 0; 75 | 76 | extern void train_detector(char *datacfg, char *cfgfile, char *weightfile, int *gpus, int ngpus, int clear); 77 | extern void validate_detector(char *datacfg, char *cfgfile, char *weightfile); 78 | extern void validate_detector_recall(char *cfgfile, char *weightfile); 79 | extern void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh); 80 | 81 | void *fetch_thread_func(void *ptr) 82 | { 83 | if (fetch_func) fetch_func(&in); 84 | /* in = get_image_from_stream(cap); */ 85 | if(!in.data){ 86 | /* error("Stream closed."); */ 87 | error("Invalid image."); 88 | } 89 | in_s = resize_image(in, net.w, net.h); 90 | 91 | return 0; 92 | } 93 | 94 | void *detect_thread_func(void *ptr) 95 | { 96 | float nms = .4; 97 | 98 | layer l = net.layers[net.n-1]; 99 | float *X = det_s.data; 100 | float *prediction = network_predict(net, X); 101 | 102 | memcpy(predictions[demo_index], prediction, l.outputs*sizeof(float)); 103 | mean_arrays(predictions, FRAMES, l.outputs, avg); 104 | l.output = avg; 105 | 106 | free_image(det_s); 107 | if(l.type == DETECTION){ 108 | get_detection_boxes(l, 1, 1, demo_thresh, probs, boxes, 0); 109 | } else if (l.type == REGION){ 110 | get_region_boxes(l, 1, 1, demo_thresh, probs, boxes, 0, 0); 111 | } else { 112 | error("Last layer must produce detections\n"); 113 | } 114 | if (nms > 0) do_nms(boxes, probs, num, l.classes, nms); 115 | // printf("\033[2J"); 116 | // printf("\033[1;1H"); 117 | // printf("\nFPS:%.1f\n",fps); 118 | // printf("Objects:\n\n"); 119 | 120 | images[demo_index] = det; 121 | det = images[(demo_index + FRAMES/2 + 1)%FRAMES]; 122 | demo_index = (demo_index + 1)%FRAMES; 123 | 124 | if (visualize) draw_detections(det, num, demo_thresh, boxes, probs, demo_names, demo_alphabet, demo_classes); 125 | 126 | return 0; 127 | } 128 | 129 | void *process_thread_func(void *ptr) 130 | { 131 | if (process_func) { 132 | /* if (process_func(num_out, names_out, boxes_out, probs_out)) running = 0; */ 133 | process_func(num_out, names_out, boxes_out, probs_out); 134 | } 135 | return 0; 136 | } 137 | 138 | /* double get_wall_time() 139 | { 140 | struct timeval time; 141 | if (gettimeofday(&time,NULL)){ 142 | return 0; 143 | } 144 | return (double)time.tv_sec + (double)time.tv_usec * .000001; 145 | } */ 146 | 147 | void detector_run(char *cfgfile, char *weightfile, float thresh, int cam_index, const char *filename, char **names, int classes, int frame_skip, char *prefix) 148 | { 149 | //skip = frame_skip; 150 | image **alphabet = load_alphabet(); 151 | delay = frame_skip; 152 | demo_names = names; 153 | demo_alphabet = alphabet; 154 | demo_classes = classes; 155 | demo_thresh = thresh; 156 | /* printf("Demo\n"); */ 157 | net = parse_network_cfg(cfgfile); 158 | if(weightfile){ 159 | load_weights(&net, weightfile); 160 | } 161 | set_batch_network(&net, 1); 162 | 163 | srand(2222222); 164 | 165 | demo_frame_skip = frame_skip; 166 | demo_prefix = prefix; 167 | 168 | /* if(filename){ 169 | printf("video file: %s\n", filename); 170 | cap = cvCaptureFromFile(filename); 171 | }else{ 172 | cap = cvCaptureFromCAM(cam_index); 173 | } 174 | 175 | if(!cap) error("Couldn't connect to webcam.\n"); */ 176 | 177 | layer l = net.layers[net.n-1]; 178 | int j; 179 | 180 | num = l.w*l.h*l.n; 181 | 182 | avg = (float *) calloc(l.outputs, sizeof(float)); 183 | for(j = 0; j < FRAMES; ++j) predictions[j] = (float *) calloc(l.outputs, sizeof(float)); 184 | for(j = 0; j < FRAMES; ++j) images[j] = make_image(1,1,3); 185 | 186 | names_out = (char**)calloc(num, sizeof(char*)); 187 | 188 | boxes = (box *)calloc(num, sizeof(box)); 189 | boxes_out = (box*)calloc(num, sizeof(box)); 190 | 191 | probs = (float **)calloc(num, sizeof(float *)); 192 | for(j = 0; j < num; ++j) probs[j] = (float *)calloc(l.classes, sizeof(float *)); 193 | 194 | probs_out = (float**)calloc(num, sizeof(float*)); 195 | 196 | 197 | /* fetch_thread_func(0); 198 | det = in; 199 | det_s = in_s; 200 | 201 | fetch_thread_func(0); 202 | detect_thread_func(0); 203 | disp = det; 204 | det = in; 205 | det_s = in_s; 206 | 207 | for(j = 0; j < FRAMES/2; ++j){ 208 | fetch_thread_func(0); 209 | detect_thread_func(0); 210 | disp = det; 211 | det = in; 212 | det_s = in_s; 213 | } */ 214 | 215 | window_name = "Display"; 216 | 217 | count = 0; 218 | if(!prefix && visualize){ 219 | cvNamedWindow(window_name, CV_WINDOW_NORMAL); 220 | cvMoveWindow(window_name, 0, 0); 221 | cvResizeWindow(window_name, 1352, 1013); 222 | } 223 | 224 | // double before = get_wall_time(); 225 | 226 | /* running = 1; */ 227 | 228 | /* while(running){ 229 | detector_update(); 230 | } */ 231 | } 232 | 233 | void detector_update(process_func_ptr process_func_in, fetch_func_ptr fetch_func_in) 234 | { 235 | if (0 == updatable) return; 236 | 237 | process_func = process_func_in; 238 | fetch_func = fetch_func_in; 239 | 240 | printf("frame: %d\n", count); 241 | ++count; 242 | if(multithread){ 243 | if(pthread_create(&fetch_thread, 0, fetch_thread_func, 0)) error("Thread creation failed"); 244 | if (det.data){ 245 | if(pthread_create(&detect_thread, 0, detect_thread_func, 0)) error("Thread creation failed"); 246 | if(pthread_create(&process_thread, 0, process_thread_func, 0)) error("Thread creation failed"); 247 | } 248 | 249 | pthread_join(fetch_thread, 0); 250 | if (det.data){ 251 | pthread_join(detect_thread, 0); 252 | pthread_join(process_thread, 0); 253 | 254 | if(delay == 0){ 255 | free_image(disp); 256 | disp = det; 257 | } 258 | 259 | num_out = 0; 260 | 261 | for(int i = 0; i < num; ++i){ 262 | int class = max_index(probs[i], demo_classes); 263 | char* name = demo_names[class]; 264 | box bound = boxes[i]; 265 | float prob = probs[i][class]; 266 | if(prob > demo_thresh){ 267 | names_out[num_out] = name; 268 | boxes_out[num_out] = bound; 269 | probs_out[num_out] = prob; 270 | 271 | ++num_out; 272 | } 273 | } 274 | 275 | if(!demo_prefix){ 276 | if (visualize && disp.data) show_image(disp, window_name); 277 | int c = cvWaitKey(1); 278 | if (c == 10){ 279 | if(demo_frame_skip == 0) demo_frame_skip = 60; 280 | else if(demo_frame_skip == 60) demo_frame_skip = 4; 281 | else if(demo_frame_skip == 4) demo_frame_skip = 0; 282 | else demo_frame_skip = 0; 283 | } 284 | } 285 | else{ 286 | char buff[256]; 287 | sprintf(buff, "%s_%08d", demo_prefix, count); 288 | save_image(disp, buff); 289 | } 290 | 291 | } 292 | 293 | det = in; 294 | det_s = in_s; 295 | } 296 | else { 297 | fetch_thread_func(0); 298 | 299 | det = in; 300 | det_s = in_s; 301 | 302 | detect_thread_func(0); 303 | 304 | num_out = 0; 305 | 306 | for(int i = 0; i < num; ++i){ 307 | int class = max_index(probs[i], demo_classes); 308 | char* name = demo_names[class]; 309 | box bound = boxes[i]; 310 | float prob = probs[i][class]; 311 | if(prob > demo_thresh){ 312 | // box.x and box.y is the center position in [0, 1]. 313 | names_out[num_out] = name; 314 | boxes_out[num_out] = bound; 315 | probs_out[num_out] = prob; 316 | 317 | ++num_out; 318 | } 319 | } 320 | 321 | process_thread_func(0); 322 | 323 | if(delay == 0){ 324 | free_image(disp); 325 | disp = det; 326 | } 327 | 328 | if(!demo_prefix){ 329 | if (visualize && disp.data) show_image(disp, window_name); 330 | int c = cvWaitKey(1); 331 | if (c == 10){ 332 | if(demo_frame_skip == 0) demo_frame_skip = 60; 333 | else if(demo_frame_skip == 60) demo_frame_skip = 4; 334 | else if(demo_frame_skip == 4) demo_frame_skip = 0; 335 | else demo_frame_skip = 0; 336 | } 337 | } 338 | else{ 339 | char buff[256]; 340 | sprintf(buff, "%s_%08d", demo_prefix, count); 341 | save_image(disp, buff); 342 | } 343 | 344 | } 345 | 346 | --delay; 347 | if(delay < 0){ 348 | delay = demo_frame_skip; 349 | 350 | /* double after = get_wall_time(); 351 | float curr = 1./(after - before); 352 | fps = curr; 353 | before = after; */ 354 | } 355 | } 356 | 357 | void detector_main(char* module, char* operation, char* datacfg, char* cfg, char* weights, char* filename, char* prefix, float thresh, int frame_skip, char* gpu_list, int clear, int visualize_in, int multithread_in) 358 | { 359 | /* 360 | arguments: 361 | char* module = argv[1]; 362 | char* operation = argv[2]; 363 | char* datacfg = argv[3]; 364 | char* cfg = argv[4]; 365 | char* weights = (argc > 5) ? argv[5] : 0; 366 | char* filename = (argc > 6) ? argv[6]: 0; 367 | char* prefix = -prefix, default 0 368 | float thresh = -thresh, default 0.24 369 | int cam_index (not used) = -c, default 0 370 | int frame_skip = -s, default 0 371 | char* gpu_list = -gpus, default 0 372 | separated by , 373 | bool clear = -clear 374 | bool visualize = -v 375 | bool multithread = -m 376 | */ 377 | /* char *prefix = find_char_arg(argc, argv, "-prefix", 0); */ 378 | /* float thresh = find_float_arg(argc, argv, "-thresh", .24); */ 379 | /* int cam_index = find_int_arg(argc, argv, "-c", 0); */ 380 | /* int frame_skip = find_int_arg(argc, argv, "-s", 0); */ 381 | visualize = visualize_in; 382 | multithread = multithread_in; 383 | /* if(argc < 4){ 384 | fprintf(stderr, "usage: %s %s [train/test/valid] [cfg] [weights (optional)]\n", argv[0], argv[1]); 385 | return; 386 | } */ 387 | /* char *gpu_list = find_char_arg(argc, argv, "-gpus", 0); */ 388 | int *gpus = 0; 389 | int gpu = 0; 390 | int ngpus = 0; 391 | if(gpu_list){ 392 | printf("%s\n", gpu_list); 393 | int len = strlen(gpu_list); 394 | ngpus = 1; 395 | int i; 396 | for(i = 0; i < len; ++i){ 397 | if (gpu_list[i] == ',') ++ngpus; 398 | } 399 | gpus = calloc(ngpus, sizeof(int)); 400 | for(i = 0; i < ngpus; ++i){ 401 | gpus[i] = atoi(gpu_list); 402 | gpu_list = strchr(gpu_list, ',')+1; 403 | } 404 | } else { 405 | gpu = gpu_index; 406 | gpus = &gpu; 407 | ngpus = 1; 408 | } 409 | 410 | /* int clear = find_arg(argc, argv, "-clear"); */ 411 | 412 | /* char* operation = argv[1]; */ 413 | /* char* module = argv[2]; */ 414 | /* char *datacfg = argv[3]; */ 415 | /* char *cfg = argv[4]; */ 416 | /* char *weights = (argc > 5) ? argv[5] : 0; */ 417 | /* char *filename = (argc > 6) ? argv[6]: 0; */ 418 | if(0==strcmp(operation, "test")) test_detector(datacfg, cfg, weights, filename, thresh); 419 | else if(0==strcmp(operation, "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear); 420 | else if(0==strcmp(operation, "valid")) validate_detector(datacfg, cfg, weights); 421 | else if(0==strcmp(operation, "recall")) validate_detector_recall(cfg, weights); 422 | else if(0==strcmp(operation, "detect")) { 423 | list *options = read_data_cfg(datacfg); 424 | int classes = option_find_int(options, "classes", 20); 425 | char *name_list = option_find_str(options, "names", "data/names.list"); 426 | char **names = get_labels(name_list); 427 | updatable = 1; 428 | detector_run(cfg, weights, thresh, 0, filename, names, classes, frame_skip, prefix); 429 | } 430 | } 431 | 432 | void detector_initialize(int gpu_id) 433 | { 434 | gpu_index = gpu_id; 435 | 436 | #ifndef GPU 437 | gpu_index = -1; 438 | #else 439 | if (gpu_index >= 0) { 440 | cuda_set_device(gpu_index); 441 | } 442 | #endif 443 | } 444 | 445 | #endif 446 | 447 | -------------------------------------------------------------------------------- /wrapper/darknet_detector.h: -------------------------------------------------------------------------------- 1 | #ifndef DARKNET_DETECTOR 2 | #define DARKNET_DETECTOR 3 | 4 | #include "utils.h" 5 | #include "box.h" 6 | #include "image.h" 7 | 8 | typedef void (*process_func_ptr)(int num, const char** names, box* boxes, float* probs); 9 | typedef void (*fetch_func_ptr)(image* img); 10 | 11 | void detector_process(char *cfgfile, char *weightfile, float thresh, int cam_index, const char *filename, char **names, int classes, int frame_skip, char *prefix); 12 | 13 | void detector_update(process_func_ptr process_func_in, fetch_func_ptr fetch_func_in); 14 | 15 | void detector_main(char* module, char* operation, char* datacfg, char* cfg, char* weights, char* filename, char* prefix, float thresh, int frame_skip, char* gpu_list, int clear, int visualize_in, int multithread_in); 16 | 17 | void detector_initialize(int gpu_id); 18 | 19 | #endif 20 | --------------------------------------------------------------------------------