From 0d5baaae256f7c3cab15d27aa8ffbf5e6db68318 Mon Sep 17 00:00:00 2001 From: zhangmeng <775834166@qq.com> Date: 星期一, 09 十二月 2019 13:20:27 +0800 Subject: [PATCH] update --- .gitignore | 2 csrc/struct.h | 30 detector.h | 22 darknet/include/yolo.hpp | 641 +++++++++++++++++++ goyolo.go | 216 ++++++ csrc/yolo.cpp | 159 ++++ csrc/yolo.h | 42 + darknet/include/darknet.h | 812 ++++++++++++++++++++++++ darknet/lib/libdarknet.so | 0 detector.cpp | 44 + 10 files changed, 1,967 insertions(+), 1 deletions(-) diff --git a/.gitignore b/.gitignore index 8365624..faf104a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a -*.so # Folders _obj @@ -21,3 +20,4 @@ *.exe *.test +libyolo.so diff --git a/csrc/struct.h b/csrc/struct.h new file mode 100644 index 0000000..0b2e53c --- /dev/null +++ b/csrc/struct.h @@ -0,0 +1,30 @@ +#ifndef _yolo_struct_h_ +#define _yolo_struct_h_ + +typedef struct _cPOINT { + int x; + int y; +} cPOINT; + +typedef struct _cRECT { + int left; + int top; + int right; + int bottom; +} cRECT; + +typedef struct _cIMAGE{ + unsigned char *data; + int width; + int height; + int channel; +} cIMAGE; + +typedef struct _cObjInfo +{ + cRECT rcObj; + int typ; + float prob; +} cObjInfo; + +#endif \ No newline at end of file diff --git a/csrc/yolo.cpp b/csrc/yolo.cpp new file mode 100644 index 0000000..b217ff5 --- /dev/null +++ b/csrc/yolo.cpp @@ -0,0 +1,159 @@ +#include "yolo.h" + +#include "yolo.hpp" + +#include <fstream> +#include <vector> +#include <stdexcept> + +#include "struct.h" + +namespace cppyolo +{ + sdkyolo::sdkyolo(const char *cfg, const char *weights, const char *name, const int gpu) + :det_(NULL) + ,infos_(NULL) + ,obj_cnt_(0) + ,image_(NULL) + ,width_(0) + ,height_(0) + ,channel_(0) + { + names_.clear(); + if (!init(cfg, weights, name, gpu)){ + throw std::runtime_error("init yolo error"); + } + } + + sdkyolo::~sdkyolo() + { + if (det_) delete det_; + } + + static void objects_names_from_file(std::string filename, std::vector<std::string> &names){ + std::ifstream file(filename); + + if (!file.is_open()){ + printf("open %s file error\n", filename.c_str()); + return; + } + for(std::string line; getline(file, line);) names.push_back(line); + + printf("names count %d\n", names.size()); + } + + const char* sdkyolo::obj_name_by_type(const int typ)const{ + if(names_.empty() || typ < 0 || typ >= names_.size()) return NULL; + return names_.at(typ).c_str(); + } + + bool sdkyolo::init(const char *cfg, const char *weights, const char *name, const int gpu){ + if (det_) return true; + + if(!cfg || !weights || !name){ + printf("init Detector error\n"); + return false; + } + + if(names_.empty()) + objects_names_from_file(name, names_); + + det_ = new Detector(cfg, weights, gpu); + return true; + } + + int sdkyolo::buffer_to_image(const unsigned char *data, const int w, const int h, const int color_channel){ + + int size = w*h; + int size2 = size*2; + + int c = color_channel; + if (w != width_ || h != height_ || color_channel != channel_){ + if (image_){ + free(image_->data); + delete image_; + } + image_ = new image_t; + image_->h = h; + image_->w = w; + image_->c = c; + image_->data = (float*)calloc(h*w*c, sizeof(float)); + } + + // image im = make_image(w, h, c); + const unsigned char *srcData = data; + + int count = 0; + switch(c){ + case 1:{ + for (; count < size; ){ + image_->data[count] = + image_->data[w*h + count] = + image_->data[w*h*2 + count] = + (float)(srcData[count])/255.0; + + ++count; + } + break; + } + case 3:{ + float* desData = image_->data; + + for(int i = 0;i<size;i++){ + *(desData) = *(srcData + 2) /255.0f; + *(desData+size) = *(srcData + 1) /255.0f; + *(desData+size2) = *(srcData) /255.0f; + + desData++; + srcData+=3; + } + break; + } + + default: + printf("Channel number not supported.\n"); + break; + } + + return 0; + } + + int sdkyolo::detect(const cIMAGE *img, const float thrsh, const bool use_mean, void **objs, int *objCount){ + if (!det_) return -1; + + const int color_channel = img->channel; + buffer_to_image(img->data, img->width, img->height, color_channel); + + + std::vector<bbox_t> result_vec = det_->detect(*image_, thrsh, use_mean); + // det->free_image(*im); + // delete im; + + if (obj_cnt_ < result_vec.size()){ + free(infos_); + + obj_cnt_ = result_vec.size(); + infos_ = (cObjInfo*)malloc(obj_cnt_ * sizeof(cObjInfo)); + } + + int count = 0; + for(auto &i : result_vec){ + + cObjInfo info; + info.typ = i.obj_id; + info.prob = i.prob; + info.rcObj.left = i.x; + info.rcObj.top = i.y; + info.rcObj.right = i.x+i.w; + info.rcObj.bottom = i.y+i.h; + + infos_[count++] = info; + } + + *objCount = count; + *objs = infos_; + + return count; + } + +} // namespace cppyolo diff --git a/csrc/yolo.h b/csrc/yolo.h new file mode 100644 index 0000000..caf4e2b --- /dev/null +++ b/csrc/yolo.h @@ -0,0 +1,42 @@ +#ifndef _cpp_yolo_h_ +#define _cpp_yolo_h_ + +#include <vector> +#include <string> + +#include "struct.h" + +struct image_t; + +class Detector; + +namespace cppyolo +{ + class sdkyolo{ + + public: + sdkyolo(const char *cfg, const char *weights, const char *name, const int gpu); + ~sdkyolo(); + + public: + int detect(const cIMAGE *img, const float thrsh, const bool use_mean, void **objs, int *objCount); + const char* obj_name_by_type(const int typ)const; + private: + bool init(const char *cfg, const char *weights, const char *name, const int gpu); + int buffer_to_image(const unsigned char *data, const int w, const int h, const int color_channel); + + private: + Detector *det_; + cObjInfo *infos_; + int obj_cnt_; + std::vector<std::string> names_; + + image_t *image_; + int width_; + int height_; + int channel_; + }; +} // namespace cppyolo + + +#endif \ No newline at end of file diff --git a/darknet/include/darknet.h b/darknet/include/darknet.h new file mode 100755 index 0000000..c3f5628 --- /dev/null +++ b/darknet/include/darknet.h @@ -0,0 +1,812 @@ +#ifndef DARKNET_API +#define DARKNET_API +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <pthread.h> + +#define SECRET_NUM -1234 +extern int gpu_index; + +#ifdef GPU + #define BLOCK 512 + + #include "cuda_runtime.h" + #include "curand.h" + #include "cublas_v2.h" + + #ifdef CUDNN + #include "cudnn.h" + #endif +#endif + +#ifndef __cplusplus + #ifdef OPENCV + #include "opencv2/highgui/highgui_c.h" + #include "opencv2/imgproc/imgproc_c.h" + #include "opencv2/core/version.hpp" + #if CV_MAJOR_VERSION == 3 + #include "opencv2/videoio/videoio_c.h" + #include "opencv2/imgcodecs/imgcodecs_c.h" + #endif + #endif +#endif + +typedef struct{ + int classes; + char **names; +} metadata; + +metadata get_metadata(char *file); + +typedef struct{ + int *leaf; + int n; + int *parent; + int *child; + int *group; + char **name; + + int groups; + int *group_size; + int *group_offset; +} tree; +tree *read_tree(char *filename); + +typedef enum{ + LOGISTIC, RELU, RELIE, LINEAR, RAMP, TANH, PLSE, LEAKY, ELU, LOGGY, STAIR, HARDTAN, LHTAN +} ACTIVATION; + +typedef enum{ + MULT, ADD, SUB, DIV +} BINARY_ACTIVATION; + +typedef enum { + CONVOLUTIONAL, + DECONVOLUTIONAL, + CONNECTED, + MAXPOOL, + SOFTMAX, + DETECTION, + DROPOUT, + CROP, + ROUTE, + COST, + NORMALIZATION, + AVGPOOL, + LOCAL, + SHORTCUT, + ACTIVE, + RNN, + GRU, + LSTM, + CRNN, + BATCHNORM, + NETWORK, + XNOR, + REGION, + YOLO, + REORG, + UPSAMPLE, + LOGXENT, + L2NORM, + BLANK +} LAYER_TYPE; + +typedef enum{ + SSE, MASKED, L1, SEG, SMOOTH,WGAN +} COST_TYPE; + +typedef struct{ + int batch; + float learning_rate; + float momentum; + float decay; + int adam; + float B1; + float B2; + float eps; + int t; +} update_args; + +struct network; +typedef struct network network; + +struct layer; +typedef struct layer layer; + +struct layer{ + LAYER_TYPE type; + ACTIVATION activation; + COST_TYPE cost_type; + void (*forward) (struct layer, struct network); + void (*backward) (struct layer, struct network); + void (*update) (struct layer, update_args); + void (*forward_gpu) (struct layer, struct network); + void (*backward_gpu) (struct layer, struct network); + void (*update_gpu) (struct layer, update_args); + int batch_normalize; + int shortcut; + int batch; + int forced; + int flipped; + int inputs; + int outputs; + int nweights; + int nbiases; + int extra; + int truths; + int h,w,c; + int out_h, out_w, out_c; + int n; + int max_boxes; + int groups; + int size; + int side; + int stride; + int reverse; + int flatten; + int spatial; + int pad; + int sqrt; + int flip; + int index; + int binary; + int xnor; + int steps; + int hidden; + int truth; + float smooth; + float dot; + float angle; + float jitter; + float saturation; + float exposure; + float shift; + float ratio; + float learning_rate_scale; + float clip; + int softmax; + int classes; + int coords; + int background; + int rescore; + int objectness; + int joint; + int noadjust; + int reorg; + int log; + int tanh; + int *mask; + int total; + + float alpha; + float beta; + float kappa; + + float coord_scale; + float object_scale; + float noobject_scale; + float mask_scale; + float class_scale; + int bias_match; + int random; + float ignore_thresh; + float truth_thresh; + float thresh; + float focus; + int classfix; + int absolute; + + int onlyforward; + int stopbackward; + int dontload; + int dontsave; + int dontloadscales; + + float temperature; + float probability; + float scale; + + char * cweights; + int * indexes; + int * input_layers; + int * input_sizes; + int * map; + float * rand; + float * cost; + float * state; + float * prev_state; + float * forgot_state; + float * forgot_delta; + float * state_delta; + float * combine_cpu; + float * combine_delta_cpu; + + float * concat; + float * concat_delta; + + float * binary_weights; + + float * biases; + float * bias_updates; + + float * scales; + float * scale_updates; + + float * weights; + float * weight_updates; + + float * delta; + float * output; + float * loss; + float * squared; + float * norms; + + float * spatial_mean; + float * mean; + float * variance; + + float * mean_delta; + float * variance_delta; + + float * rolling_mean; + float * rolling_variance; + + float * x; + float * x_norm; + + float * m; + float * v; + + float * bias_m; + float * bias_v; + float * scale_m; + float * scale_v; + + + float *z_cpu; + float *r_cpu; + float *h_cpu; + float * prev_state_cpu; + + float *temp_cpu; + float *temp2_cpu; + float *temp3_cpu; + + float *dh_cpu; + float *hh_cpu; + float *prev_cell_cpu; + float *cell_cpu; + float *f_cpu; + float *i_cpu; + float *g_cpu; + float *o_cpu; + float *c_cpu; + float *dc_cpu; + + float * binary_input; + + struct layer *input_layer; + struct layer *self_layer; + struct layer *output_layer; + + struct layer *reset_layer; + struct layer *update_layer; + struct layer *state_layer; + + struct layer *input_gate_layer; + struct layer *state_gate_layer; + struct layer *input_save_layer; + struct layer *state_save_layer; + struct layer *input_state_layer; + struct layer *state_state_layer; + + struct layer *input_z_layer; + struct layer *state_z_layer; + + struct layer *input_r_layer; + struct layer *state_r_layer; + + struct layer *input_h_layer; + struct layer *state_h_layer; + + struct layer *wz; + struct layer *uz; + struct layer *wr; + struct layer *ur; + struct layer *wh; + struct layer *uh; + struct layer *uo; + struct layer *wo; + struct layer *uf; + struct layer *wf; + struct layer *ui; + struct layer *wi; + struct layer *ug; + struct layer *wg; + + tree *softmax_tree; + + size_t workspace_size; + +#ifdef GPU + int *indexes_gpu; + + float *z_gpu; + float *r_gpu; + float *h_gpu; + + float *temp_gpu; + float *temp2_gpu; + float *temp3_gpu; + + float *dh_gpu; + float *hh_gpu; + float *prev_cell_gpu; + float *cell_gpu; + float *f_gpu; + float *i_gpu; + float *g_gpu; + float *o_gpu; + float *c_gpu; + float *dc_gpu; + + float *m_gpu; + float *v_gpu; + float *bias_m_gpu; + float *scale_m_gpu; + float *bias_v_gpu; + float *scale_v_gpu; + + float * combine_gpu; + float * combine_delta_gpu; + + float * prev_state_gpu; + float * forgot_state_gpu; + float * forgot_delta_gpu; + float * state_gpu; + float * state_delta_gpu; + float * gate_gpu; + float * gate_delta_gpu; + float * save_gpu; + float * save_delta_gpu; + float * concat_gpu; + float * concat_delta_gpu; + + float * binary_input_gpu; + float * binary_weights_gpu; + + float * mean_gpu; + float * variance_gpu; + + float * rolling_mean_gpu; + float * rolling_variance_gpu; + + float * variance_delta_gpu; + float * mean_delta_gpu; + + float * x_gpu; + float * x_norm_gpu; + float * weights_gpu; + float * weight_updates_gpu; + float * weight_change_gpu; + + float * biases_gpu; + float * bias_updates_gpu; + float * bias_change_gpu; + + float * scales_gpu; + float * scale_updates_gpu; + float * scale_change_gpu; + + float * output_gpu; + float * loss_gpu; + float * delta_gpu; + float * rand_gpu; + float * squared_gpu; + float * norms_gpu; +#ifdef CUDNN + cudnnTensorDescriptor_t srcTensorDesc, dstTensorDesc; + cudnnTensorDescriptor_t dsrcTensorDesc, ddstTensorDesc; + cudnnTensorDescriptor_t normTensorDesc; + cudnnFilterDescriptor_t weightDesc; + cudnnFilterDescriptor_t dweightDesc; + cudnnConvolutionDescriptor_t convDesc; + cudnnConvolutionFwdAlgo_t fw_algo; + cudnnConvolutionBwdDataAlgo_t bd_algo; + cudnnConvolutionBwdFilterAlgo_t bf_algo; +#endif +#endif +}; + +void free_layer(layer); + +typedef enum { + CONSTANT, STEP, EXP, POLY, STEPS, SIG, RANDOM +} learning_rate_policy; + +typedef struct network{ + int n; + int batch; + size_t *seen; + int *t; + float epoch; + int subdivisions; + layer *layers; + float *output; + learning_rate_policy policy; + + float learning_rate; + float momentum; + float decay; + float gamma; + float scale; + float power; + int time_steps; + int step; + int max_batches; + float *scales; + int *steps; + int num_steps; + int burn_in; + + int adam; + float B1; + float B2; + float eps; + + int inputs; + int outputs; + int truths; + int notruth; + int h, w, c; + int max_crop; + int min_crop; + float max_ratio; + float min_ratio; + int center; + float angle; + float aspect; + float exposure; + float saturation; + float hue; + int random; + + int gpu_index; + tree *hierarchy; + + float *input; + float *truth; + float *delta; + float *workspace; + int train; + int index; + float *cost; + float clip; + +#ifdef GPU + float *input_gpu; + float *truth_gpu; + float *delta_gpu; + float *output_gpu; +#endif + +} network; + +typedef struct { + int w; + int h; + float scale; + float rad; + float dx; + float dy; + float aspect; +} augment_args; + +typedef struct { + int w; + int h; + int c; + float *data; +} image; + +typedef struct{ + float x, y, w, h; +} box; + +typedef struct detection{ + box bbox; + int classes; + float *prob; + float *mask; + float objectness; + int sort_class; +} detection; + +typedef struct matrix{ + int rows, cols; + float **vals; +} matrix; + + +typedef struct{ + int w, h; + matrix X; + matrix y; + int shallow; + int *num_boxes; + box **boxes; +} data; + +typedef enum { + CLASSIFICATION_DATA, DETECTION_DATA, CAPTCHA_DATA, REGION_DATA, IMAGE_DATA, COMPARE_DATA, WRITING_DATA, SWAG_DATA, TAG_DATA, OLD_CLASSIFICATION_DATA, STUDY_DATA, DET_DATA, SUPER_DATA, LETTERBOX_DATA, REGRESSION_DATA, SEGMENTATION_DATA, INSTANCE_DATA +} data_type; + +typedef struct load_args{ + int threads; + char **paths; + char *path; + int n; + int m; + char **labels; + int h; + int w; + int out_w; + int out_h; + int nh; + int nw; + int num_boxes; + int min, max, size; + int classes; + int background; + int scale; + int center; + int coords; + float jitter; + float angle; + float aspect; + float saturation; + float exposure; + float hue; + data *d; + image *im; + image *resized; + data_type type; + tree *hierarchy; +} load_args; + +typedef struct{ + int id; + float x,y,w,h; + float left, right, top, bottom; +} box_label; + + +void free_data(data d); + +typedef struct node{ + void *val; + struct node *next; + struct node *prev; +} node; + +typedef struct list{ + int size; + node *front; + node *back; +} list; + +#ifdef __cplusplus +extern "C" { // 鍛婅瘔缂栬瘧鍣ㄤ笅鍒椾唬鐮佽浠閾炬帴绾﹀畾鐨勬ā寮忚繘琛岄摼鎺� +#endif + +//#todo +network *load_network(char *cfg, char *weights, int clear); +load_args get_base_args(network *net); + +pthread_t load_data(load_args args); +list *read_data_cfg(char *filename); +list *read_cfg(char *filename); +unsigned char *read_file(char *filename); +data resize_data(data orig, int w, int h); +data *tile_data(data orig, int divs, int size); +data select_data(data *orig, int *inds); + +void forward_network(network *net); +void backward_network(network *net); +void update_network(network *net); + + +float dot_cpu(int N, float *X, int INCX, float *Y, int INCY); +void axpy_cpu(int N, float ALPHA, float *X, int INCX, float *Y, int INCY); +void copy_cpu(int N, float *X, int INCX, float *Y, int INCY); +void scal_cpu(int N, float ALPHA, float *X, int INCX); +void fill_cpu(int N, float ALPHA, float * X, int INCX); +void normalize_cpu(float *x, float *mean, float *variance, int batch, int filters, int spatial); +void softmax(float *input, int n, float temp, int stride, float *output); + +int best_3d_shift_r(image a, image b, int min, int max); + +image get_label(image **characters, char *string, int size); +void draw_label(image a, int r, int c, image label, const float *rgb); +void save_image_png(image im, const char *name); +void get_next_batch(data d, int n, int offset, float *X, float *y); +void grayscale_image_3c(image im); +void normalize_image(image p); +void matrix_to_csv(matrix m); +float train_network_sgd(network *net, data d, int n); +void rgbgr_image(image im); +data copy_data(data d); +data concat_data(data d1, data d2); +data load_cifar10_data(char *filename); +float matrix_topk_accuracy(matrix truth, matrix guess, int k); +void matrix_add_matrix(matrix from, matrix to); +void scale_matrix(matrix m, float scale); +matrix csv_to_matrix(char *filename); +float *network_accuracies(network *net, data d, int n); +float train_network_datum(network *net); +image make_random_image(int w, int h, int c); + +void denormalize_connected_layer(layer l); +void denormalize_convolutional_layer(layer l); +void statistics_connected_layer(layer l); +void rescale_weights(layer l, float scale, float trans); +void rgbgr_weights(layer l); +image *get_weights(layer l); + +void demo(char *cfgfile, char *weightfile, float thresh, int cam_index, const char *filename, char **names, int classes, int frame_skip, char *prefix, int avg, float hier_thresh, int w, int h, int fps, int fullscreen); +void get_detection_detections(layer l, int w, int h, float thresh, detection *dets); + +char *option_find_str(list *l, char *key, char *def); +int option_find_int(list *l, char *key, int def); +int option_find_int_quiet(list *l, char *key, int def); + +network *parse_network_cfg(char *filename); +void save_weights(network *net, char *filename); +void load_weights(network *net, char *filename); +void save_weights_upto(network *net, char *filename, int cutoff); +void load_weights_upto(network *net, char *filename, int start, int cutoff); + +void zero_objectness(layer l); +void get_region_detections(layer l, int w, int h, int netw, int neth, float thresh, int *map, float tree_thresh, int relative, detection *dets); +int get_yolo_detections(layer l, int w, int h, int netw, int neth, float thresh, int *map, int relative, detection *dets); +void free_network(network *net); +void set_batch_network(network *net, int b); +void set_temp_network(network *net, float t); +image load_image(char *filename, int w, int h, int c); +image load_image_color(char *filename, int w, int h); +image make_image(int w, int h, int c); +image resize_image(image im, int w, int h); +void censor_image(image im, int dx, int dy, int w, int h); +image letterbox_image(image im, int w, int h); +image crop_image(image im, int dx, int dy, int w, int h); +image center_crop_image(image im, int w, int h); +image resize_min(image im, int min); +image resize_max(image im, int max); +image threshold_image(image im, float thresh); +image mask_to_rgb(image mask); +int resize_network(network *net, int w, int h); +void free_matrix(matrix m); +void test_resize(char *filename); +void save_image(image p, const char *name); +void show_image(image p, const char *name); +image copy_image(image p); +void draw_box_width(image a, int x1, int y1, int x2, int y2, int w, float r, float g, float b); +float get_current_rate(network *net); +void composite_3d(char *f1, char *f2, char *out, int delta); +data load_data_old(char **paths, int n, int m, char **labels, int k, int w, int h); +size_t get_current_batch(network *net); +void constrain_image(image im); +image get_network_image_layer(network *net, int i); +layer get_network_output_layer(network *net); +void top_predictions(network *net, int n, int *index); +void flip_image(image a); +image float_to_image(int w, int h, int c, float *data); +void ghost_image(image source, image dest, int dx, int dy); +float network_accuracy(network *net, data d); +void random_distort_image(image im, float hue, float saturation, float exposure); +void fill_image(image m, float s); +image grayscale_image(image im); +void rotate_image_cw(image im, int times); +double what_time_is_it_now(); +image rotate_image(image m, float rad); +void visualize_network(network *net); +float box_iou(box a, box b); +data load_all_cifar10(); +box_label *read_boxes(char *filename, int *n); +box float_to_box(float *f, int stride); +void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes); + +matrix network_predict_data(network *net, data test); +image **load_alphabet(); +image get_network_image(network *net); +float *network_predict(network *net, float *input); + +int network_width(network *net); +int network_height(network *net); +float *network_predict_image(network *net, image im); +void network_detect(network *net, image im, float thresh, float hier_thresh, float nms, detection *dets); +detection *get_network_boxes(network *net, int w, int h, float thresh, float hier, int *map, int relative, int *num); +void free_detections(detection *dets, int n); + +void reset_network_state(network *net, int b); + +char **get_labels(char *filename); +void do_nms_obj(detection *dets, int total, int classes, float thresh); +void do_nms_sort(detection *dets, int total, int classes, float thresh); + +matrix make_matrix(int rows, int cols); + +void free_image(image m); +float train_network(network *net, data d); +pthread_t load_data_in_thread(load_args args); +void load_data_blocking(load_args args); +list *get_paths(char *filename); +void hierarchy_predictions(float *predictions, int n, tree *hier, int only_leaves, int stride); +void change_leaves(tree *t, char *leaf_list); + +int find_int_arg(int argc, char **argv, char *arg, int def); +float find_float_arg(int argc, char **argv, char *arg, float def); +int find_arg(int argc, char* argv[], char *arg); +char *find_char_arg(int argc, char **argv, char *arg, char *def); +char *basecfg(char *cfgfile); +void find_replace(char *str, char *orig, char *rep, char *output); +void free_ptrs(void **ptrs, int n); +char *fgetl(FILE *fp); +void strip(char *s); +float sec(clock_t clocks); +void **list_to_array(list *l); +void top_k(float *a, int n, int k, int *index); +int *read_map(char *filename); +void error(const char *s); +int max_index(float *a, int n); +int max_int_index(int *a, int n); +int sample_array(float *a, int n); +int *random_index_order(int min, int max); +void free_list(list *l); +float mse_array(float *a, int n); +float variance_array(float *a, int n); +float mag_array(float *a, int n); +void scale_array(float *a, int n, float s); +float mean_array(float *a, int n); +float sum_array(float *a, int n); +void normalize_array(float *a, int n); +int *read_intlist(char *s, int *n, int d); +size_t rand_size_t(); +float rand_normal(); +float rand_uniform(float min, float max); + +#ifdef GPU +void axpy_gpu(int N, float ALPHA, float * X, int INCX, float * Y, int INCY); +void fill_gpu(int N, float ALPHA, float * X, int INCX); +void scal_gpu(int N, float ALPHA, float * X, int INCX); +void copy_gpu(int N, float * X, int INCX, float * Y, int INCY); + +void cuda_set_device(int n); +void cuda_free(float *x_gpu); +float *cuda_make_array(float *x, size_t n); +void cuda_pull_array(float *x_gpu, float *x, size_t n); +float cuda_mag_array(float *x_gpu, size_t n); +void cuda_push_array(float *x_gpu, float *x, size_t n); + +void forward_network_gpu(network *net); +void backward_network_gpu(network *net); +void update_network_gpu(network *net); + +float train_networks(network **nets, int n, data d, int interval); +void sync_nets(network **nets, int n, int interval); +void harmless_update_network_gpu(network *net); +#endif + +#ifndef __cplusplus +#ifdef OPENCV +image get_image_from_stream(CvCapture *cap); +#endif +#endif +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/darknet/include/yolo.hpp b/darknet/include/yolo.hpp new file mode 100644 index 0000000..00c2a5b --- /dev/null +++ b/darknet/include/yolo.hpp @@ -0,0 +1,641 @@ +#pragma once +#ifdef YOLODLL_EXPORTS +#if defined(_MSC_VER) +#define YOLODLL_API __declspec(dllexport) +#else +#define YOLODLL_API __attribute__((visibility("default"))) +#endif +#else +#if defined(_MSC_VER) +#define YOLODLL_API __declspec(dllimport) +#else +#define YOLODLL_API +#endif +#endif + +struct bbox_t { + unsigned int x, y, w, h; // (x,y) - top-left corner, (w, h) - width & height of bounded box + float prob; // confidence - probability that the object was found correctly + unsigned int obj_id; // class of object - from range [0, classes-1] + unsigned int track_id; // tracking id for video (0 - untracked, 1 - inf - tracked object) + unsigned int frames_counter;// counter of frames on which the object was detected +}; + +struct image_t { + int h; // height + int w; // width + int c; // number of chanels (3 - for RGB) + float *data; // pointer to the image data +}; + +#ifdef __cplusplus +#include <memory> +#include <vector> +#include <deque> +#include <algorithm> + +#ifdef OPENCV +#include <opencv2/opencv.hpp> // C++ +#include "opencv2/highgui/highgui_c.h" // C +#include "opencv2/imgproc/imgproc_c.h" // C +#endif // OPENCV + +class Detector { + std::shared_ptr<void> detector_gpu_ptr; + std::deque<std::vector<bbox_t>> prev_bbox_vec_deque; + const int cur_gpu_id; +public: + float nms = .4; + bool wait_stream; + + YOLODLL_API Detector(std::string cfg_filename, std::string weight_filename, int gpu_id = 0); + YOLODLL_API ~Detector(); + + YOLODLL_API std::vector<bbox_t> detect(std::string image_filename, float thresh = 0.2, bool use_mean = false); + YOLODLL_API std::vector<bbox_t> detect(image_t img, float thresh = 0.2, bool use_mean = false); + static YOLODLL_API image_t load_image(std::string image_filename); + static YOLODLL_API void free_image(image_t m); + YOLODLL_API int get_net_width() const; + YOLODLL_API int get_net_height() const; + + YOLODLL_API std::vector<bbox_t> tracking_id(std::vector<bbox_t> cur_bbox_vec, bool const change_history = true, + int const frames_story = 10, int const max_dist = 150); + + std::vector<bbox_t> detect_resized(image_t img, int init_w, int init_h, float thresh = 0.2, bool use_mean = false) + { + if (img.data == NULL) + throw std::runtime_error("Image is empty"); + auto detection_boxes = detect(img, thresh, use_mean); + float wk = (float)init_w / img.w, hk = (float)init_h / img.h; + for (auto &i : detection_boxes) i.x *= wk, i.w *= wk, i.y *= hk, i.h *= hk; + return detection_boxes; + } + +#ifdef OPENCV + std::vector<bbox_t> detect(cv::Mat mat, float thresh = 0.2, bool use_mean = false) + { + if(mat.data == NULL) + throw std::runtime_error("Image is empty"); + auto image_ptr = mat_to_image_resize(mat); + return detect_resized(*image_ptr, mat.cols, mat.rows, thresh, use_mean); + } + + std::shared_ptr<image_t> mat_to_image_resize(cv::Mat mat) const + { + if (mat.data == NULL) return std::shared_ptr<image_t>(NULL); + cv::Mat det_mat; + cv::resize(mat, det_mat, cv::Size(get_net_width(), get_net_height())); + return mat_to_image(det_mat); + } + + static std::shared_ptr<image_t> mat_to_image(cv::Mat img_src) + { + cv::Mat img; + cv::cvtColor(img_src, img, cv::COLOR_RGB2BGR); + std::shared_ptr<image_t> image_ptr(new image_t, [](image_t *img) { free_image(*img); delete img; }); + std::shared_ptr<IplImage> ipl_small = std::make_shared<IplImage>(img); + *image_ptr = ipl_to_image(ipl_small.get()); + return image_ptr; + } + +private: + + static image_t ipl_to_image(IplImage* src) + { + unsigned char *data = (unsigned char *)src->imageData; + int h = src->height; + int w = src->width; + int c = src->nChannels; + int step = src->widthStep; + image_t out = make_image_custom(w, h, c); + int count = 0; + + for (int k = 0; k < c; ++k) { + for (int i = 0; i < h; ++i) { + int i_step = i*step; + for (int j = 0; j < w; ++j) { + out.data[count++] = data[i_step + j*c + k] / 255.; + } + } + } + + return out; + } + + static image_t make_empty_image(int w, int h, int c) + { + image_t out; + out.data = 0; + out.h = h; + out.w = w; + out.c = c; + return out; + } + + static image_t make_image_custom(int w, int h, int c) + { + image_t out = make_empty_image(w, h, c); + out.data = (float *)calloc(h*w*c, sizeof(float)); + return out; + } + +#endif // OPENCV + +}; + + + +#if defined(TRACK_OPTFLOW) && defined(OPENCV) && defined(GPU) + +#include <opencv2/cudaoptflow.hpp> +#include <opencv2/cudaimgproc.hpp> +#include <opencv2/cudaarithm.hpp> +#include <opencv2/core/cuda.hpp> + +class Tracker_optflow { +public: + const int gpu_count; + const int gpu_id; + const int flow_error; + + + Tracker_optflow(int _gpu_id = 0, int win_size = 9, int max_level = 3, int iterations = 8000, int _flow_error = -1) : + gpu_count(cv::cuda::getCudaEnabledDeviceCount()), gpu_id(std::min(_gpu_id, gpu_count-1)), + flow_error((_flow_error > 0)? _flow_error:(win_size*4)) + { + int const old_gpu_id = cv::cuda::getDevice(); + cv::cuda::setDevice(gpu_id); + + stream = cv::cuda::Stream(); + + sync_PyrLKOpticalFlow_gpu = cv::cuda::SparsePyrLKOpticalFlow::create(); + sync_PyrLKOpticalFlow_gpu->setWinSize(cv::Size(win_size, win_size)); // 9, 15, 21, 31 + sync_PyrLKOpticalFlow_gpu->setMaxLevel(max_level); // +- 3 pt + sync_PyrLKOpticalFlow_gpu->setNumIters(iterations); // 2000, def: 30 + + cv::cuda::setDevice(old_gpu_id); + } + + // just to avoid extra allocations + cv::cuda::GpuMat src_mat_gpu; + cv::cuda::GpuMat dst_mat_gpu, dst_grey_gpu; + cv::cuda::GpuMat prev_pts_flow_gpu, cur_pts_flow_gpu; + cv::cuda::GpuMat status_gpu, err_gpu; + + cv::cuda::GpuMat src_grey_gpu; // used in both functions + cv::Ptr<cv::cuda::SparsePyrLKOpticalFlow> sync_PyrLKOpticalFlow_gpu; + cv::cuda::Stream stream; + + std::vector<bbox_t> cur_bbox_vec; + std::vector<bool> good_bbox_vec_flags; + cv::Mat prev_pts_flow_cpu; + + void update_cur_bbox_vec(std::vector<bbox_t> _cur_bbox_vec) + { + cur_bbox_vec = _cur_bbox_vec; + good_bbox_vec_flags = std::vector<bool>(cur_bbox_vec.size(), true); + cv::Mat prev_pts, cur_pts_flow_cpu; + + for (auto &i : cur_bbox_vec) { + float x_center = (i.x + i.w / 2.0F); + float y_center = (i.y + i.h / 2.0F); + prev_pts.push_back(cv::Point2f(x_center, y_center)); + } + + if (prev_pts.rows == 0) + prev_pts_flow_cpu = cv::Mat(); + else + cv::transpose(prev_pts, prev_pts_flow_cpu); + + if (prev_pts_flow_gpu.cols < prev_pts_flow_cpu.cols) { + prev_pts_flow_gpu = cv::cuda::GpuMat(prev_pts_flow_cpu.size(), prev_pts_flow_cpu.type()); + cur_pts_flow_gpu = cv::cuda::GpuMat(prev_pts_flow_cpu.size(), prev_pts_flow_cpu.type()); + + status_gpu = cv::cuda::GpuMat(prev_pts_flow_cpu.size(), CV_8UC1); + err_gpu = cv::cuda::GpuMat(prev_pts_flow_cpu.size(), CV_32FC1); + } + + prev_pts_flow_gpu.upload(cv::Mat(prev_pts_flow_cpu), stream); + } + + + void update_tracking_flow(cv::Mat src_mat, std::vector<bbox_t> _cur_bbox_vec) + { + int const old_gpu_id = cv::cuda::getDevice(); + if (old_gpu_id != gpu_id) + cv::cuda::setDevice(gpu_id); + + if (src_mat.channels() == 3) { + if (src_mat_gpu.cols == 0) { + src_mat_gpu = cv::cuda::GpuMat(src_mat.size(), src_mat.type()); + src_grey_gpu = cv::cuda::GpuMat(src_mat.size(), CV_8UC1); + } + + update_cur_bbox_vec(_cur_bbox_vec); + + //src_grey_gpu.upload(src_mat, stream); // use BGR + src_mat_gpu.upload(src_mat, stream); + cv::cuda::cvtColor(src_mat_gpu, src_grey_gpu, CV_BGR2GRAY, 1, stream); + } + if (old_gpu_id != gpu_id) + cv::cuda::setDevice(old_gpu_id); + } + + + std::vector<bbox_t> tracking_flow(cv::Mat dst_mat, bool check_error = true) + { + if (sync_PyrLKOpticalFlow_gpu.empty()) { + std::cout << "sync_PyrLKOpticalFlow_gpu isn't initialized \n"; + return cur_bbox_vec; + } + + int const old_gpu_id = cv::cuda::getDevice(); + if(old_gpu_id != gpu_id) + cv::cuda::setDevice(gpu_id); + + if (dst_mat_gpu.cols == 0) { + dst_mat_gpu = cv::cuda::GpuMat(dst_mat.size(), dst_mat.type()); + dst_grey_gpu = cv::cuda::GpuMat(dst_mat.size(), CV_8UC1); + } + + //dst_grey_gpu.upload(dst_mat, stream); // use BGR + dst_mat_gpu.upload(dst_mat, stream); + cv::cuda::cvtColor(dst_mat_gpu, dst_grey_gpu, CV_BGR2GRAY, 1, stream); + + if (src_grey_gpu.rows != dst_grey_gpu.rows || src_grey_gpu.cols != dst_grey_gpu.cols) { + stream.waitForCompletion(); + src_grey_gpu = dst_grey_gpu.clone(); + cv::cuda::setDevice(old_gpu_id); + return cur_bbox_vec; + } + + ////sync_PyrLKOpticalFlow_gpu.sparse(src_grey_gpu, dst_grey_gpu, prev_pts_flow_gpu, cur_pts_flow_gpu, status_gpu, &err_gpu); // OpenCV 2.4.x + sync_PyrLKOpticalFlow_gpu->calc(src_grey_gpu, dst_grey_gpu, prev_pts_flow_gpu, cur_pts_flow_gpu, status_gpu, err_gpu, stream); // OpenCV 3.x + + cv::Mat cur_pts_flow_cpu; + cur_pts_flow_gpu.download(cur_pts_flow_cpu, stream); + + dst_grey_gpu.copyTo(src_grey_gpu, stream); + + cv::Mat err_cpu, status_cpu; + err_gpu.download(err_cpu, stream); + status_gpu.download(status_cpu, stream); + + stream.waitForCompletion(); + + std::vector<bbox_t> result_bbox_vec; + + if (err_cpu.cols == cur_bbox_vec.size() && status_cpu.cols == cur_bbox_vec.size()) + { + for (size_t i = 0; i < cur_bbox_vec.size(); ++i) + { + cv::Point2f cur_key_pt = cur_pts_flow_cpu.at<cv::Point2f>(0, i); + cv::Point2f prev_key_pt = prev_pts_flow_cpu.at<cv::Point2f>(0, i); + + float moved_x = cur_key_pt.x - prev_key_pt.x; + float moved_y = cur_key_pt.y - prev_key_pt.y; + + if (abs(moved_x) < 100 && abs(moved_y) < 100 && good_bbox_vec_flags[i]) + if (err_cpu.at<float>(0, i) < flow_error && status_cpu.at<unsigned char>(0, i) != 0 && + ((float)cur_bbox_vec[i].x + moved_x) > 0 && ((float)cur_bbox_vec[i].y + moved_y) > 0) + { + cur_bbox_vec[i].x += moved_x + 0.5; + cur_bbox_vec[i].y += moved_y + 0.5; + result_bbox_vec.push_back(cur_bbox_vec[i]); + } + else good_bbox_vec_flags[i] = false; + else good_bbox_vec_flags[i] = false; + + //if(!check_error && !good_bbox_vec_flags[i]) result_bbox_vec.push_back(cur_bbox_vec[i]); + } + } + + cur_pts_flow_gpu.swap(prev_pts_flow_gpu); + cur_pts_flow_cpu.copyTo(prev_pts_flow_cpu); + + if (old_gpu_id != gpu_id) + cv::cuda::setDevice(old_gpu_id); + + return result_bbox_vec; + } + +}; + +#elif defined(TRACK_OPTFLOW) && defined(OPENCV) + +//#include <opencv2/optflow.hpp> +#include <opencv2/video/tracking.hpp> + +class Tracker_optflow { +public: + const int flow_error; + + + Tracker_optflow(int win_size = 9, int max_level = 3, int iterations = 8000, int _flow_error = -1) : + flow_error((_flow_error > 0)? _flow_error:(win_size*4)) + { + sync_PyrLKOpticalFlow = cv::SparsePyrLKOpticalFlow::create(); + sync_PyrLKOpticalFlow->setWinSize(cv::Size(win_size, win_size)); // 9, 15, 21, 31 + sync_PyrLKOpticalFlow->setMaxLevel(max_level); // +- 3 pt + + } + + // just to avoid extra allocations + cv::Mat dst_grey; + cv::Mat prev_pts_flow, cur_pts_flow; + cv::Mat status, err; + + cv::Mat src_grey; // used in both functions + cv::Ptr<cv::SparsePyrLKOpticalFlow> sync_PyrLKOpticalFlow; + + std::vector<bbox_t> cur_bbox_vec; + std::vector<bool> good_bbox_vec_flags; + + void update_cur_bbox_vec(std::vector<bbox_t> _cur_bbox_vec) + { + cur_bbox_vec = _cur_bbox_vec; + good_bbox_vec_flags = std::vector<bool>(cur_bbox_vec.size(), true); + cv::Mat prev_pts, cur_pts_flow; + + for (auto &i : cur_bbox_vec) { + float x_center = (i.x + i.w / 2.0F); + float y_center = (i.y + i.h / 2.0F); + prev_pts.push_back(cv::Point2f(x_center, y_center)); + } + + if (prev_pts.rows == 0) + prev_pts_flow = cv::Mat(); + else + cv::transpose(prev_pts, prev_pts_flow); + } + + + void update_tracking_flow(cv::Mat new_src_mat, std::vector<bbox_t> _cur_bbox_vec) + { + if (new_src_mat.channels() == 3) { + + update_cur_bbox_vec(_cur_bbox_vec); + + cv::cvtColor(new_src_mat, src_grey, CV_BGR2GRAY, 1); + } + } + + + std::vector<bbox_t> tracking_flow(cv::Mat new_dst_mat, bool check_error = true) + { + if (sync_PyrLKOpticalFlow.empty()) { + std::cout << "sync_PyrLKOpticalFlow isn't initialized \n"; + return cur_bbox_vec; + } + + cv::cvtColor(new_dst_mat, dst_grey, CV_BGR2GRAY, 1); + + if (src_grey.rows != dst_grey.rows || src_grey.cols != dst_grey.cols) { + src_grey = dst_grey.clone(); + return cur_bbox_vec; + } + + if (prev_pts_flow.cols < 1) { + return cur_bbox_vec; + } + + ////sync_PyrLKOpticalFlow_gpu.sparse(src_grey_gpu, dst_grey_gpu, prev_pts_flow_gpu, cur_pts_flow_gpu, status_gpu, &err_gpu); // OpenCV 2.4.x + sync_PyrLKOpticalFlow->calc(src_grey, dst_grey, prev_pts_flow, cur_pts_flow, status, err); // OpenCV 3.x + + dst_grey.copyTo(src_grey); + + std::vector<bbox_t> result_bbox_vec; + + if (err.rows == cur_bbox_vec.size() && status.rows == cur_bbox_vec.size()) + { + for (size_t i = 0; i < cur_bbox_vec.size(); ++i) + { + cv::Point2f cur_key_pt = cur_pts_flow.at<cv::Point2f>(0, i); + cv::Point2f prev_key_pt = prev_pts_flow.at<cv::Point2f>(0, i); + + float moved_x = cur_key_pt.x - prev_key_pt.x; + float moved_y = cur_key_pt.y - prev_key_pt.y; + + if (abs(moved_x) < 100 && abs(moved_y) < 100 && good_bbox_vec_flags[i]) + if (err.at<float>(0, i) < flow_error && status.at<unsigned char>(0, i) != 0 && + ((float)cur_bbox_vec[i].x + moved_x) > 0 && ((float)cur_bbox_vec[i].y + moved_y) > 0) + { + cur_bbox_vec[i].x += moved_x + 0.5; + cur_bbox_vec[i].y += moved_y + 0.5; + result_bbox_vec.push_back(cur_bbox_vec[i]); + } + else good_bbox_vec_flags[i] = false; + else good_bbox_vec_flags[i] = false; + + //if(!check_error && !good_bbox_vec_flags[i]) result_bbox_vec.push_back(cur_bbox_vec[i]); + } + } + + prev_pts_flow = cur_pts_flow.clone(); + + return result_bbox_vec; + } + +}; +#else + +class Tracker_optflow {}; + +#endif // defined(TRACK_OPTFLOW) && defined(OPENCV) + + +#ifdef OPENCV + +static cv::Scalar obj_id_to_color(int obj_id) { + int const colors[6][3] = { { 1,0,1 },{ 0,0,1 },{ 0,1,1 },{ 0,1,0 },{ 1,1,0 },{ 1,0,0 } }; + int const offset = obj_id * 123457 % 6; + int const color_scale = 150 + (obj_id * 123457) % 100; + cv::Scalar color(colors[offset][0], colors[offset][1], colors[offset][2]); + color *= color_scale; + return color; +} + +class preview_boxes_t { + enum { frames_history = 30 }; // how long to keep the history saved + + struct preview_box_track_t { + unsigned int track_id, obj_id, last_showed_frames_ago; + bool current_detection; + bbox_t bbox; + cv::Mat mat_obj, mat_resized_obj; + preview_box_track_t() : track_id(0), obj_id(0), last_showed_frames_ago(frames_history), current_detection(false) {} + }; + std::vector<preview_box_track_t> preview_box_track_id; + size_t const preview_box_size, bottom_offset; + bool const one_off_detections; +public: + preview_boxes_t(size_t _preview_box_size = 100, size_t _bottom_offset = 100, bool _one_off_detections = false) : + preview_box_size(_preview_box_size), bottom_offset(_bottom_offset), one_off_detections(_one_off_detections) + {} + + void set(cv::Mat src_mat, std::vector<bbox_t> result_vec) + { + size_t const count_preview_boxes = src_mat.cols / preview_box_size; + if (preview_box_track_id.size() != count_preview_boxes) preview_box_track_id.resize(count_preview_boxes); + + // increment frames history + for (auto &i : preview_box_track_id) + i.last_showed_frames_ago = std::min((unsigned)frames_history, i.last_showed_frames_ago + 1); + + // occupy empty boxes + for (auto &k : result_vec) { + bool found = false; + // find the same (track_id) + for (auto &i : preview_box_track_id) { + if (i.track_id == k.track_id) { + if (!one_off_detections) i.last_showed_frames_ago = 0; // for tracked objects + found = true; + break; + } + } + if (!found) { + // find empty box + for (auto &i : preview_box_track_id) { + if (i.last_showed_frames_ago == frames_history) { + if (!one_off_detections && k.frames_counter == 0) break; // don't show if obj isn't tracked yet + i.track_id = k.track_id; + i.obj_id = k.obj_id; + i.bbox = k; + i.last_showed_frames_ago = 0; + break; + } + } + } + } + + // draw preview box (from old or current frame) + for (size_t i = 0; i < preview_box_track_id.size(); ++i) + { + // get object image + cv::Mat dst = preview_box_track_id[i].mat_resized_obj; + preview_box_track_id[i].current_detection = false; + + for (auto &k : result_vec) { + if (preview_box_track_id[i].track_id == k.track_id) { + if (one_off_detections && preview_box_track_id[i].last_showed_frames_ago > 0) { + preview_box_track_id[i].last_showed_frames_ago = frames_history; break; + } + bbox_t b = k; + cv::Rect r(b.x, b.y, b.w, b.h); + cv::Rect img_rect(cv::Point2i(0, 0), src_mat.size()); + cv::Rect rect_roi = r & img_rect; + if (rect_roi.width > 1 || rect_roi.height > 1) { + cv::Mat roi = src_mat(rect_roi); + cv::resize(roi, dst, cv::Size(preview_box_size, preview_box_size), cv::INTER_NEAREST); + preview_box_track_id[i].mat_obj = roi.clone(); + preview_box_track_id[i].mat_resized_obj = dst.clone(); + preview_box_track_id[i].current_detection = true; + preview_box_track_id[i].bbox = k; + } + break; + } + } + } + } + + + void draw(cv::Mat draw_mat, bool show_small_boxes = false) + { + // draw preview box (from old or current frame) + for (size_t i = 0; i < preview_box_track_id.size(); ++i) + { + auto &prev_box = preview_box_track_id[i]; + + // draw object image + cv::Mat dst = prev_box.mat_resized_obj; + if (prev_box.last_showed_frames_ago < frames_history && + dst.size() == cv::Size(preview_box_size, preview_box_size)) + { + cv::Rect dst_rect_roi(cv::Point2i(i * preview_box_size, draw_mat.rows - bottom_offset), dst.size()); + cv::Mat dst_roi = draw_mat(dst_rect_roi); + dst.copyTo(dst_roi); + + cv::Scalar color = obj_id_to_color(prev_box.obj_id); + int thickness = (prev_box.current_detection) ? 5 : 1; + cv::rectangle(draw_mat, dst_rect_roi, color, thickness); + + unsigned int const track_id = prev_box.track_id; + std::string track_id_str = (track_id > 0) ? std::to_string(track_id) : ""; + putText(draw_mat, track_id_str, dst_rect_roi.tl() - cv::Point2i(-4, 5), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.9, cv::Scalar(0, 0, 0), 2); + + std::string size_str = std::to_string(prev_box.bbox.w) + "x" + std::to_string(prev_box.bbox.h); + putText(draw_mat, size_str, dst_rect_roi.tl() + cv::Point2i(0, 12), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cv::Scalar(0, 0, 0), 1); + + if (!one_off_detections && prev_box.current_detection) { + cv::line(draw_mat, dst_rect_roi.tl() + cv::Point2i(preview_box_size, 0), + cv::Point2i(prev_box.bbox.x, prev_box.bbox.y + prev_box.bbox.h), + color); + } + + if (one_off_detections && show_small_boxes) { + cv::Rect src_rect_roi(cv::Point2i(prev_box.bbox.x, prev_box.bbox.y), + cv::Size(prev_box.bbox.w, prev_box.bbox.h)); + unsigned int const color_history = (255 * prev_box.last_showed_frames_ago) / frames_history; + color = cv::Scalar(255 - 3 * color_history, 255 - 2 * color_history, 255 - 1 * color_history); + if (prev_box.mat_obj.size() == src_rect_roi.size()) { + prev_box.mat_obj.copyTo(draw_mat(src_rect_roi)); + } + cv::rectangle(draw_mat, src_rect_roi, color, thickness); + putText(draw_mat, track_id_str, src_rect_roi.tl() - cv::Point2i(0, 10), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cv::Scalar(0, 0, 0), 1); + } + } + } + } +}; +#endif // OPENCV + +//extern "C" { +#endif // __cplusplus + +/* + // C - wrappers + YOLODLL_API void create_detector(char const* cfg_filename, char const* weight_filename, int gpu_id); + YOLODLL_API void delete_detector(); + YOLODLL_API bbox_t* detect_custom(image_t img, float thresh, bool use_mean, int *result_size); + YOLODLL_API bbox_t* detect_resized(image_t img, int init_w, int init_h, float thresh, bool use_mean, int *result_size); + YOLODLL_API bbox_t* detect(image_t img, int *result_size); + YOLODLL_API image_t load_img(char *image_filename); + YOLODLL_API void free_img(image_t m); + +#ifdef __cplusplus +} // extern "C" + +static std::shared_ptr<void> c_detector_ptr; +static std::vector<bbox_t> c_result_vec; + +void create_detector(char const* cfg_filename, char const* weight_filename, int gpu_id) { + c_detector_ptr = std::make_shared<YOLODLL_API Detector>(cfg_filename, weight_filename, gpu_id); +} + +void delete_detector() { c_detector_ptr.reset(); } + +bbox_t* detect_custom(image_t img, float thresh, bool use_mean, int *result_size) { + c_result_vec = static_cast<Detector*>(c_detector_ptr.get())->detect(img, thresh, use_mean); + *result_size = c_result_vec.size(); + return c_result_vec.data(); +} + +bbox_t* detect_resized(image_t img, int init_w, int init_h, float thresh, bool use_mean, int *result_size) { + c_result_vec = static_cast<Detector*>(c_detector_ptr.get())->detect_resized(img, init_w, init_h, thresh, use_mean); + *result_size = c_result_vec.size(); + return c_result_vec.data(); +} + +bbox_t* detect(image_t img, int *result_size) { + return detect_custom(img, 0.24, true, result_size); +} + +image_t load_img(char *image_filename) { + return static_cast<Detector*>(c_detector_ptr.get())->load_image(image_filename); +} +void free_img(image_t m) { + static_cast<Detector*>(c_detector_ptr.get())->free_image(m); +} + +#endif // __cplusplus +*/ diff --git a/darknet/lib/libdarknet.so b/darknet/lib/libdarknet.so new file mode 100755 index 0000000..e4a12c9 --- /dev/null +++ b/darknet/lib/libdarknet.so Binary files differ diff --git a/detector.cpp b/detector.cpp new file mode 100644 index 0000000..9701a90 --- /dev/null +++ b/detector.cpp @@ -0,0 +1,44 @@ +#ifdef __cplusplus +extern "C"{ +#endif + +#include "detector.h" + +#ifdef __cplusplus +} +#endif + +#include "csrc/yolo.h" + +#include "csrc/struct.h" + +#include "csrc/yolo.cpp" + +using namespace cppyolo; + +void* init(const char *cfg, const char *weights, const char *name, const int gpu){ + return new sdkyolo(cfg, weights, name, gpu); +} + +void release(void *handle){ + if (handle){ + sdkyolo *h = (sdkyolo*)handle; + delete h; + } +} + +int detect(void *handle, + const void *data, const int w, const int h, const int c, + const float thrsh, const int use_mean, + void **objInfos, int *objCount){ + + sdkyolo *y = (sdkyolo*)handle; + cIMAGE img{(unsigned char*)data, w, h, c}; + return y->detect(&img, thrsh, use_mean, objInfos, objCount); +} + +const char* obj_name_by_type(void *handle, const int typ){ + sdkyolo *h = (sdkyolo*)handle; + return h->obj_name_by_type(typ); +} + diff --git a/detector.h b/detector.h new file mode 100644 index 0000000..c9eb31e --- /dev/null +++ b/detector.h @@ -0,0 +1,22 @@ +#ifndef _c_yolo_h_ +#define _c_yolo_h_ + +#ifdef __cplusplus +extern "C"{ +#endif + +void* init(const char *cfg, const char *weights, const char *name, const int gpu); +void release(void *handle); + +int detect(void *handle, + const void *data, const int w, const int h, const int c, + const float thrsh, const int use_mean, + void **objInfos, int *objCount); + +const char* obj_name_by_type(void *handle, const int typ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/goyolo.go b/goyolo.go new file mode 100644 index 0000000..fe1634d --- /dev/null +++ b/goyolo.go @@ -0,0 +1,216 @@ +package main + +/* +#cgo CFLAGS: -I${SRCDIR}/darknet/include -I/usr/local/cuda-8.0/include -w -g +#cgo CXXFLAGS: -I${SRCDIR}/darknet/include -I/usr/local/cuda-8.0/include -w -g -std=c++11 +#cgo LDFLAGS: -L/usr/local/cuda-8.0/lib64 -L${SRCDIR}/darknet/lib +#cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/darknet/lib +#cgo LDFLAGS: -ldarknet -lcudart -lcublas -lcurand -lcudnn -lrt -ldl -lpthread +#include <stdlib.h> +#include "detector.h" +*/ +import "C" +import "unsafe" + +// CPOINT pt +type CPOINT struct { + X int32 + Y int32 +} + +// CRECT rc +type CRECT struct { + Left int32 + Top int32 + Right int32 + Bottom int32 +} + +// CIMAGE img +type CIMAGE struct { + Data *uint8 + Width int32 + Height int32 + Channel int32 + Pad_cgo_0 [4]byte +} + +// CObjInfo yolo +type CObjInfo struct { + RcObj CRECT + Typ int32 + Prob float32 +} + +// CObjTrackInfo track yolo objs info +type CObjTrackInfo struct { + ObjInfo CObjInfo + ID uint64 +} + +// YoloHandle wrap C +type YoloHandle struct { + handle unsafe.Pointer + LastYoloObjs []CObjTrackInfo //yolo璺熻釜鐨勪笂涓�甯т俊鎭� + LastTrackID uint64 //yolo 琚娇鐢ㄧ殑ID +} + +// RatioInterTrack 璺熻釜鍒ゆ柇閲嶅彔闃堝�� +const RatioInterTrack = 50 //璺熻釜鍒ゆ柇閲嶅彔闃堝�� + +// SDKImage sdk image +type SDKImage struct { + Data []byte + Width int + Height int +} + +// NewYolo init yolo sdk +func NewYolo(fc, fw, fn string, gi int) *YoloHandle { + + c := C.CString(fc) + defer C.free(unsafe.Pointer(c)) + w := C.CString(fw) + defer C.free(unsafe.Pointer(w)) + n := C.CString(fn) + defer C.free(unsafe.Pointer(n)) + + g := C.int(gi) + + p := C.init(c, w, n, g) + return &YoloHandle{handle: p} +} + +// Free free +func (y *YoloHandle) Free() { + if y != nil { + if y.handle != nil { + C.release(y.handle) + } + } +} + +// CYoloObjInfoArrayToGoArray convert cObjInfo array to go +func CYoloObjInfoArrayToGoArray(cArray unsafe.Pointer, count int) (goArray []CObjInfo) { + p := uintptr(cArray) + + for i := 0; i < count; i++ { + j := *(*CObjInfo)(unsafe.Pointer(p)) + goArray = append(goArray, j) + p += unsafe.Sizeof(j) + } + return +} + +// YoloDetect yolo detect +func (y *YoloHandle) YoloDetect(img SDKImage, thrsh float32, umns int) []CObjInfo { + + data := img.Data + w := img.Width + h := img.Height + + var count C.int + var cobjinfo unsafe.Pointer + + ret := C.detect(y.handle, + unsafe.Pointer(&data[0]), C.int(w), C.int(h), 3, + C.float(thrsh), C.int(umns), + &cobjinfo, &count) + + if ret == 0 { + return CYoloObjInfoArrayToGoArray(unsafe.Pointer(cobjinfo), int(count)) + } + return nil +} + +// YoloObjName obj name by type +func (y *YoloHandle) YoloObjName(typ int) string { + p := C.obj_name_by_type(y.handle, C.int(typ)) + + return C.GoString(p) +} + +func max(a, b int32) int32 { + if a < b { + return b + } + return a +} + +func min(a, b int32) int32 { + if a < b { + return a + } + return b +} + +func countInterAreaOfTwoRect(rect1 CRECT, rect2 CRECT) int32 { + xMin := min(rect1.Left, rect2.Left) + yMin := min(rect1.Top, rect2.Top) + xMax := max(rect1.Right, rect2.Right) + yMax := max(rect1.Bottom, rect2.Bottom) + + wRect1 := rect1.Right - rect1.Left + hRect1 := rect1.Bottom - rect1.Top + + wRect2 := rect2.Right - rect2.Left + hRect2 := rect2.Bottom - rect2.Top + + wInter := wRect1 + wRect2 - (xMax - xMin) + hInter := hRect1 + hRect2 - (yMax - yMin) + + if (wInter <= 0) || (hInter <= 0) { + return 0 + } + + areaInter := wInter * hInter + areaRect1 := wRect1 * hRect1 + areaRect2 := wRect2 * hRect2 + ratio := areaInter * 100 / min(areaRect1, areaRect2) + + return ratio +} + +// YoloDetectTrack yolo detect (鍙瘑鍒汉) +func (y *YoloHandle) YoloDetectTrack(img SDKImage, thrsh float32, umns int) (allObjs []CObjTrackInfo, newObjs []CObjTrackInfo) { + + var tmp CObjTrackInfo + //LastYoloObjs + detectObjs := y.YoloDetect(img, thrsh, umns) + + for _, vLast := range y.LastYoloObjs { + for i := 0; i < len(detectObjs); i++ { + //fmt.Println("vNew.Typ:", vNew.Typ) + if vLast.ObjInfo.Typ == detectObjs[i].Typ { //鍚屼竴绫诲埆锛屾瘮濡傞兘鏄汉浣� + ratio := countInterAreaOfTwoRect(vLast.ObjInfo.RcObj, detectObjs[i].RcObj) + if ratio >= RatioInterTrack { + //update LastYoloObjs + vLast.ObjInfo.RcObj = detectObjs[i].RcObj + vLast.ObjInfo.Prob = detectObjs[i].Prob + + allObjs = append(allObjs, vLast) + detectObjs = append(detectObjs[:i], detectObjs[i+1:]...) //浠庢娴嬬洰鏍囬噷鍒犻櫎宸茬粡鏌ュ埌鐨勮窡韪洰鏍� + i-- + break //涓婁竴甯ц窡韪殑鐩爣宸茬粡鎵惧埌锛屾棤闇�寰�涓嬪鐞嗗叾浠栨娴嬬洰鏍� + } + } + } + } + + //澶勭悊鏂板嚭鐜扮殑鐩爣 + if len(detectObjs) > 0 { + for _, vAdd := range detectObjs { + tmp.ObjInfo = vAdd + tmp.ID = y.LastTrackID + y.LastTrackID++ + + allObjs = append(allObjs, tmp) + newObjs = append(newObjs, tmp) + } + } + + //鍒锋柊涓婁竴甯х殑璺熻釜鐩爣 + y.LastYoloObjs = allObjs + + return allObjs, newObjs +} -- Gitblit v1.8.0