From bbcc33c0cfb64faac60f70a6c99f6193998b3735 Mon Sep 17 00:00:00 2001 From: Micaela Verucchi Date: Fri, 20 Mar 2020 21:14:12 +0100 Subject: [PATCH] Refactoring for detection NN Signed-off-by: Micaela Verucchi --- demo/demo/demo.cpp | 74 +++---- demo/demo/map.cpp | 2 +- include/tkDNN/CenternetDetection.h | 180 ++++++---------- include/tkDNN/DetectionNN.h | 99 +++++++++ include/tkDNN/MobilenetDetection.h | 71 ++----- include/tkDNN/Yolo3Detection.h | 93 +++------ include/tkDNN/utils.h | 2 +- src/CenternetDetection.cpp | 323 +++++++++++++---------------- src/MobilenetDetection.cpp | 240 +++++++++++---------- src/Yolo3Detection.cpp | 219 ++++++++++--------- src/utils.cpp | 12 ++ 11 files changed, 637 insertions(+), 678 deletions(-) create mode 100644 include/tkDNN/DetectionNN.h diff --git a/demo/demo/demo.cpp b/demo/demo/demo.cpp index 90ff800..ccc5c7f 100644 --- a/demo/demo/demo.cpp +++ b/demo/demo/demo.cpp @@ -31,25 +31,34 @@ int main(int argc, char *argv[]) { char ntype = 'y'; if(argc > 3) ntype = argv[3][0]; + int n_classes = 80; + if(argc > 4) + n_classes = atoi(argv[4]); tk::dnn::Yolo3Detection yolo; tk::dnn::CenternetDetection cnet; - tk::dnn::MobilenetDetection mbnet; + tk::dnn::MobilenetDetection mbnet; + + tk::dnn::DetectionNN *detNN; + switch(ntype) { case 'y': - yolo.init(net); + detNN = &yolo; break; case 'c': - cnet.init(net); + detNN = &cnet; break; case 'm': - mbnet.init(net, 512, 81); + detNN = &mbnet; + n_classes++; break; default: FatalError("Network type not allowed (3rd parameter)\n"); } + detNN->init(net, n_classes); + gRun = true; cv::VideoCapture cap(input); @@ -79,25 +88,11 @@ int main(int argc, char *argv[]) { // this will be resized to the net format dnn_input = frame.clone(); - // TODO: async infer - switch(ntype) - { - case 'y': - yolo.update(dnn_input); - frame = yolo.draw(frame); - break; - case 'c': - cnet.update(dnn_input); - frame = cnet.draw(dnn_input); - break; - case 'm': - mbnet.update(dnn_input); - frame = mbnet.draw(); - break; - default: - FatalError("Network type not allowed!\n"); - } - + + //inference + detNN->update(dnn_input); + frame = detNN->draw(frame); + cv::imshow("detection", frame); cv::waitKey(1); if(SAVE_RESULT) @@ -106,32 +101,13 @@ int main(int argc, char *argv[]) { std::cout<<"detection end\n"; double mean = 0; - switch(ntype) - { - case 'y': - std::cout<stats.begin(), detNN->stats.end())<<" ms\n"; + std::cout<<"Max: "<<*std::max_element(detNN->stats.begin(), detNN->stats.end())<<" ms\n"; + for(int i=0; istats.size(); i++) mean += detNN->stats[i]; mean /= detNN->stats.size(); + std::cout<<"Avg: "< -#include -#include -#include /* srand, rand */ -#include -#include -#include "utils.h" -#include +#ifndef CENTERNETDETECTION_H +#define CENTERNETDETECTION_H + #include "kernels.h" +#include +#include "opencv2/opencv.hpp" +#include #include #include // std::iota #include // std::sort +#include "DetectionNN.h" -#include -#include -#include -#include "opencv2/opencv.hpp" - -#include "tkdnn.h" #include "sorting.h" -namespace tk { namespace dnn { -/** - * - * @author Francesco Gatti - */ -class CenternetDetection { +namespace tk { namespace dnn { - private: - tk::dnn::NetworkRT *netRT = nullptr; - dnnType *input_d; +class CenternetDetection : public DetectionNN +{ +private: + std::vector classesNames; - int ndets = 0; - // tk::dnn::Yolo::detection *dets = nullptr; + tk::dnn::dataDim_t dim; + tk::dnn::dataDim_t dim2; + tk::dnn::dataDim_t dim_hm; + tk::dnn::dataDim_t dim_wh; + tk::dnn::dataDim_t dim_reg; + float *topk_scores; + int *topk_inds_; + float *topk_ys_; + float *topk_xs_; + int *ids_d, *ids_, *ids_2, *ids_2d; - cv::Mat imageOrig; - // std::vector< cv::cuda::GpuMat > bgr; + float *scores, *scores_d; + int *clses, *clses_d; + int *topk_inds_d; + float *topk_ys_d; + float *topk_xs_d; + int *inttopk_xs_d, *inttopk_ys_d; - // variable to test cnet on dog pictures - tk::dnn::dataDim_t dim; - tk::dnn::dataDim_t dim2; - cv::Size sz, sz_old; - const char *input_bin = "../tests/resnet101_cnet/debug/input.bin"; - cv::cuda::Stream stream; - struct threshold op; - // pre-process - tk::dnn::dataDim_t dim_hm; - tk::dnn::dataDim_t dim_wh; - tk::dnn::dataDim_t dim_reg; - float *topk_scores; - int *topk_inds_; - float *topk_ys_; - float *topk_xs_; - int *ids_d, *ids_, *ids_2, *ids_2d; - - float *scores, *scores_d; - int *clses, *clses_d; - int *topk_inds_d; - float *topk_ys_d; - float *topk_xs_d; - int *inttopk_xs_d, *inttopk_ys_d; + float *bbx0, *bby0, *bbx1, *bby1; + float *bbx0_d, *bby0_d, *bbx1_d, *bby1_d; + float *target_coords; - float *bbx0, *bby0, *bbx1, *bby1; - float *bbx0_d, *bby0_d, *bbx1_d, *bby1_d; - - float *target_coords; - - + #ifdef OPENCV_CUDA + float *mean_d; + float *stddev_d; + #else + cv::Vec mean; + cv::Vec stddev; + dnnType *input; + #endif - #ifdef OPENCV_CUDA - float *mean_d; - float *stddev_d; - #else - cv::Vec mean; - cv::Vec stddev; - dnnType *input; - #endif + float *d_ptrs; - float *d_ptrs; - - cv::Mat src; - cv::Mat dst; - cv::Mat dst2; - cv::Mat trans, trans2; - //processing - float toll = 0.000001; - int K = 100; - int width = 128;//56; // TODO + cv::Mat src; + cv::Mat dst; + cv::Mat dst2; + cv::Mat trans, trans2; + //processing + float toll = 0.000001; + int K = 100; + int width = 128;//56; // TODO + + // pointer used in the kernels + float *src_out; + int *ids_out; + + struct threshold op; - // pointer used in the kernels - float *src_out; - int *ids_out; - - void preprocess(); - public: - dnnType *rt_out[4]; - - float inp_height = 512;//224;//512; - float inp_width = 512;//224;//512; - - int classes = 80; - int num = 0; - int n_masks = 0; - float thresh = 0.3; - cv::Scalar colors[256]; - - // this is filled with results - std::vector detected; - // draw - std::vector coco_class_name; - - // keep track of inference times (ms) - std::vector stats; - - CenternetDetection() {} - - virtual ~CenternetDetection() {} - - /** - * Method used for inizialize the class - * - * @return Success of the initialization - */ - bool init(std::string tensor_path); - cv::Mat draw(cv::Mat &frame); - void update(cv::Mat &frame); +public: + CenternetDetection() {}; + ~CenternetDetection() {}; + bool init(const std::string& tensor_path, const int n_classes=80); + void preprocess(cv::Mat &frame); + void update(cv::Mat &frame); + void postprocess(dnnType **rt_out, const int n_out); + cv::Mat draw(cv::Mat &frame); }; -}} + +} // namespace dnn +} // namespace tk + + +#endif /*CENTERNETDETECTION_H*/ \ No newline at end of file diff --git a/include/tkDNN/DetectionNN.h b/include/tkDNN/DetectionNN.h new file mode 100644 index 0000000..ddc2d43 --- /dev/null +++ b/include/tkDNN/DetectionNN.h @@ -0,0 +1,99 @@ +#ifndef DETECTIONNN_H +#define DETECTIONNN_H + +#include +#include +#include /* srand, rand */ +#include +#include +#include "utils.h" + +#include +#include +#include + +#include "tkdnn.h" + +// #define OPENCV_CUDA //if OPENCV has been compiled with CUDA and contrib. + +namespace tk { namespace dnn { + +enum networkType_t{ + NETWORK_YOLO3, + NETWORK_MOBILENETSSDLITE, + NETWORK_CENTERNET +}; + +class DetectionNN { + + protected: + tk::dnn::NetworkRT *netRT = nullptr; + dnnType *input_d; + + cv::Size originalSize; + + cv::Scalar colors[256]; + +#ifdef OPENCV_CUDA + cv::cuda::GpuMat bgr[3]; + cv::cuda::GpuMat imagePreproc; +#else + cv::Mat bgr[3]; + cv::Mat imagePreproc; + dnnType *input; +#endif + + public: + int classes = 0; + float confThreshold = 0.3; /*threshold on the confidence of the boxes*/ + + std::vector detected; /*bounding boxes in output*/ + std::vector stats; /*keeps track of inference times (ms)*/ + + DetectionNN() {}; + ~DetectionNN(){}; + + /** + * Method used to inialize the class, allocate memory and compute + * needed data. + * + * @param path to the rt file og the NN. + * @return true if everything is correct, false otherwise. + */ + virtual bool init(const std::string& tensor_path, const int n_classes=80) = 0; + + /** + * This method preprocess the image, before feeding it to the NN. + * + * @param original frame to adapt for inference. + */ + virtual void preprocess(cv::Mat &frame) = 0; + + /** + * This method performs the inference of the NN. + * + * @param frame to run inference on. + */ + virtual void update(cv::Mat &frame) = 0; + + /** + * This method postprocess the output of the NN to obtain the correct + * boundig boxes. + * + * @param outputs of the inference + * @param number of outputs of the inference + */ + virtual void postprocess(dnnType **rt_out, const int n_out) = 0; + + /** + * Method to draw boundixg boxes and labels on a frame. + * + * @param orginal frame to draw bounding box on. + * @return frame with boundig boxes. + */ + virtual cv::Mat draw(cv::Mat &frame) = 0; +}; + +}} + +#endif /* DETECTIONNN_H*/ diff --git a/include/tkDNN/MobilenetDetection.h b/include/tkDNN/MobilenetDetection.h index f4bec95..44fd120 100644 --- a/include/tkDNN/MobilenetDetection.h +++ b/include/tkDNN/MobilenetDetection.h @@ -1,18 +1,15 @@ #ifndef MOBILENETDETECTION_H #define MOBILENETDETECTION_H -#include - -#include -#include #include -#include #include "opencv2/opencv.hpp" -#include "tkdnn.h" +#include "DetectionNN.h" #define N_COORDS 4 +#define N_SSDSPEC 6 +namespace tk { namespace dnn { struct SSDSpec { @@ -24,10 +21,9 @@ struct SSDSpec int ratio2 = 0; SSDSpec() {} - - SSDSpec(int feature_size, int shrinkage, int box_width, int box_height, int ratio1, int ratio2) : featureSize(feature_size), shrinkage(shrinkage), boxWidth(box_width), boxHeight(box_height), - ratio1(ratio1), ratio2(ratio2) {} - + SSDSpec(int feature_size, int shrinkage, int box_width, int box_height, int ratio1, int ratio2) : + featureSize(feature_size), shrinkage(shrinkage), boxWidth(box_width), + boxHeight(box_height), ratio1(ratio1), ratio2(ratio2) {} void setAll(int feature_size, int shrinkage, int box_width, int box_height, int ratio1, int ratio2) { this->featureSize = feature_size; @@ -37,74 +33,47 @@ struct SSDSpec this->ratio1 = ratio1; this->ratio2 = ratio2; } - void print() { - std::cout << "fsize: " << featureSize << "\tshrinkage: " << shrinkage << "\t box W:" << boxWidth << "\tbox H: " << boxHeight << "\t x ratio:" << ratio1 << "\t y ratio:" << ratio2 << std::endl; + std::cout << "fsize: " << featureSize << "\tshrinkage: " << shrinkage << + "\t box W:" << boxWidth << "\tbox H: " << boxHeight << + "\t x ratio:" << ratio1 << "\t y ratio:" << ratio2 << std::endl; } }; - -namespace tk +class MobilenetDetection : public DetectionNN { -namespace dnn -{ -class MobilenetDetection -{ - private: - tk::dnn::NetworkRT *netRT = nullptr; - - int classes; float IoUThreshold = 0.45; float centerVariance = 0.1; float sizeVariance = 0.2; - float confThreshold = 0.4; int imageSize; float *priors = nullptr; int nPriors = 0; - - cv::Mat origImg; - - float *input, *input_d; float *locations_h, *confidences_h; - tk::dnn::dataDim_t dim; - - dnnType *conf; - dnnType *loc; - - float __colors[6][3] = {{1, 0, 1}, {0, 0, 1}, {0, 1, 1}, {0, 1, 0}, {1, 1, 0}, {1, 0, 0}}; - int baseline = 0; - float fontScale = 0.5; - int thickness = 2; + std::vector classesNames; void generate_ssd_priors(const SSDSpec *specs, const int n_specs, bool clamp = true); void convert_locatios_to_boxes_and_center(); float iou(const tk::dnn::box &a, const tk::dnn::box &b); - void preprocess(); - std::vector postprocess(const int width, const int height); - float get_color2(int c, int x, int max); - cv::Scalar colors[256]; - std::vector classesNames; + public: - // keep track of inference times (ms) - std::vector stats; - std::vector detected; + MobilenetDetection() {}; + ~MobilenetDetection() {}; - MobilenetDetection() {} - ~MobilenetDetection() {} - - void init(std::string tensor_path, int input_size, int n_classes); - cv::Mat draw(); - void update(cv::Mat &img); + bool init(const std::string& tensor_path, const int n_classes); + void preprocess(cv::Mat &frame); + void update(cv::Mat &frame); + void postprocess(dnnType **rt_out, const int n_out); + cv::Mat draw(cv::Mat &frame); }; + } // namespace dnn } // namespace tk - #endif /*MOBILENETDETECTION_H*/ \ No newline at end of file diff --git a/include/tkDNN/Yolo3Detection.h b/include/tkDNN/Yolo3Detection.h index 80d179e..148a53f 100644 --- a/include/tkDNN/Yolo3Detection.h +++ b/include/tkDNN/Yolo3Detection.h @@ -1,73 +1,36 @@ -#ifndef YOLODETECTION_H -#define YOLODETECTION_H +#ifndef Yolo3Detection_H +#define Yolo3Detection_H +#include +#include "opencv2/opencv.hpp" -#include -#include -#include /* srand, rand */ -#include -#include -#include "utils.h" +#include "DetectionNN.h" -#include -#include -#include +namespace tk { namespace dnn { -#include "tkdnn.h" +class Yolo3Detection : public DetectionNN +{ +private: + int num = 0; + int nMasks = 0; + int nDets = 0; + tk::dnn::Yolo::detection *dets = nullptr; + tk::dnn::Yolo* yolo[3]; -namespace tk { namespace dnn { - -/** - * - * @author Francesco Gatti - */ -class Yolo3Detection { - - private: - tk::dnn::NetworkRT *netRT = nullptr; - tk::dnn::Yolo* yolo[3]; - dnnType *input, *input_d; - - int ndets = 0; - tk::dnn::Yolo::detection *dets = nullptr; - - cv::Mat imageF; - cv::Mat bgr[3]; - - public: - int classes = 0; - int num = 0; - int n_masks = 0; - float thresh = 0.3; - cv::Scalar colors[256]; - - // this is filled with results - std::vector detected; - - // keep track of inference times (ms) - std::vector stats; - - Yolo3Detection() {} - - virtual ~Yolo3Detection() {} - - /** - * Method used for inizialize the class - * - * @return Success of the initialization - */ - bool init(std::string tensor_path); - cv::Mat draw(cv::Mat &frame); - void update(cv::Mat &frame); - - tk::dnn::Yolo* getYoloLayer(int n=0) { - if(n<3) - return yolo[n]; - else - return nullptr; - } + tk::dnn::Yolo* getYoloLayer(int n=0); + +public: + Yolo3Detection() {}; + ~Yolo3Detection() {}; + bool init(const std::string& tensor_path, const int n_classes=80); + void preprocess(cv::Mat &frame); + void update(cv::Mat &frame); + void postprocess(dnnType **rt_out, const int n_out); + cv::Mat draw(cv::Mat &frame); }; -}} -#endif /* YOLODETECTION_H*/ +} // namespace dnn +} // namespace tk + +#endif /* Yolo3Detection_H*/ diff --git a/include/tkDNN/utils.h b/include/tkDNN/utils.h index 1a6df95..2b8ba8a 100644 --- a/include/tkDNN/utils.h +++ b/include/tkDNN/utils.h @@ -14,7 +14,6 @@ #define dnnType float -#define OPENCV_CUDA // Colored output #define COL_END "\033[0m" @@ -96,6 +95,7 @@ void downloadWeightsifDoNotExist(const std::string& input_bin, const std::string void readBinaryFile(std::string fname, int size, dnnType** data_h, dnnType** data_d, int seek = 0, bool skipLoad = false); int checkResult(int size, dnnType *data_d, dnnType *correct_d, bool device = true); void printDeviceVector(int size, dnnType* vec_d, bool device = true); +float getColor(const int c, const int x, const int max); void resize(int size, dnnType **data); void matrixTranspose(cublasHandle_t handle, dnnType* srcData, dnnType* dstData, int rows, int cols); diff --git a/src/CenternetDetection.cpp b/src/CenternetDetection.cpp index b1e8ff9..29cdec6 100644 --- a/src/CenternetDetection.cpp +++ b/src/CenternetDetection.cpp @@ -1,33 +1,19 @@ -#ifndef CENTERNETDETECTION_H -#define CENTERNETDETECTION_H +#include "CenternetDetection.h" #include "CenternetDetection.h" -#include "opencv2/imgproc/imgproc.hpp" -// #include -// #include - - namespace tk { namespace dnn { -float __colors[6][3] = { {1,0,1}, {0,0,1},{0,1,1},{0,1,0},{1,1,0},{1,0,0} }; -float get_color2(int c, int x, int max) -{ - float ratio = ((float)x/max)*5; - int i = floor(ratio); - int j = ceil(ratio); - ratio -= i; - float r = (1-ratio) * __colors[i % 6][c % 3] + ratio*__colors[j % 6][c % 3]; - //printf("%f\n", r); - return r; -} -bool CenternetDetection::init(std::string tensor_path) { +bool CenternetDetection::init(const std::string& tensor_path, const int n_classes) +{ std::cout<<(tensor_path).c_str()<<"\n"; netRT = new tk::dnn::NetworkRT(NULL, (tensor_path).c_str() ); - - dim = tk::dnn::dataDim_t(1, 3, 512, 512, 1); - const char *coco_class_name_[] = { + classes = n_classes; + + dim = netRT->input_dim; + + const char *coco_class_name[] = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", @@ -42,19 +28,24 @@ bool CenternetDetection::init(std::string tensor_path) { "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush" }; - coco_class_name = std::vector(coco_class_name_, std::end( coco_class_name_ )); + classesNames = std::vector(coco_class_name, std::end( coco_class_name)); + + for(int c=0; cinput_dim.tot())); - // dim_hm = tk::dnn::dataDim_t(1, 80, 56, 56, 1); - // dim_wh = tk::dnn::dataDim_t(1, 2, 56, 56, 1); - // dim_reg = tk::dnn::dataDim_t(1, 2, 56, 56, 1); dim_hm = tk::dnn::dataDim_t(1, 80, 128, 128, 1); dim_wh = tk::dnn::dataDim_t(1, 2, 128, 128, 1); dim_reg = tk::dnn::dataDim_t(1, 2, 128, 128, 1); @@ -79,19 +70,16 @@ bool CenternetDetection::init(std::string tensor_path) { checkCuda( cudaMallocHost(&scores, K *sizeof(float)) ); checkCuda( cudaMalloc(&scores_d, K *sizeof(float)) ); + checkCuda( cudaMallocHost(&clses, K *sizeof(int)) ); checkCuda( cudaMalloc(&clses_d, K *sizeof(int)) ); - // checkCuda( cudaMallocHost(&topk_inds, K *sizeof(int)) ); + checkCuda( cudaMalloc(&topk_inds_d, K *sizeof(int)) ); checkCuda( cudaMalloc(&topk_ys_d, K *sizeof(float)) ); checkCuda( cudaMalloc(&topk_xs_d, K *sizeof(float)) ); - // checkCuda( cudaMalloc(&intid, K *sizeof(int)) ); checkCuda( cudaMalloc(&inttopk_ys_d, K *sizeof(int)) ); checkCuda( cudaMalloc(&inttopk_xs_d, K *sizeof(int)) ); - - // checkCuda( cudaMalloc(&ids_d, dim_hm.c * K*sizeof(int)) ); - // checkCuda( cudaMallocHost(&wh_aus, dim_wh.tot()*sizeof(dnnType)) ); checkCuda( cudaMallocHost(&bbx0, K * sizeof(float)) ); checkCuda( cudaMallocHost(&bby0, K * sizeof(float)) ); checkCuda( cudaMallocHost(&bbx1, K * sizeof(float)) ); @@ -119,14 +107,11 @@ bool CenternetDetection::init(std::string tensor_path) { #endif checkCuda( cudaMalloc(&d_ptrs, dim.c * dim.h*dim.w * sizeof(float)) ); - // mean << 0.408, 0.447, 0.47; - // stddev << 0.289, 0.274, 0.278; // Alloc array used in the kernel checkCuda( cudaMalloc(&src_out, K *sizeof(float)) ); checkCuda( cudaMalloc(&ids_out, K *sizeof(int)) ); - // checkCuda( cudaFree(src_out) ); - // checkCuda( cudaFree(ids_out) ); + dst2.at(0,0)=width * 0.5; dst2.at(0,1)=width * 0.5; dst2.at(1,0)=width * 0.5; @@ -137,60 +122,17 @@ bool CenternetDetection::init(std::string tensor_path) { } -cv::Mat CenternetDetection::draw(cv::Mat &imageOrig) { - tk::dnn::box b; - int x0, w, x1, y0, h, y1; - int objClass; - std::string det_class; - int baseline = 0; - float fontScale = 0.5; - int thickness = 2; - - for(int c=0; c(0,1)=c[1]; src.at(1,0)=c[0]; src.at(1,1)=c[1] + s[0] * -0.5; - dst.at(0,0)=inp_width * 0.5; - dst.at(0,1)=inp_height * 0.5; - dst.at(1,0)=inp_width * 0.5; - dst.at(1,1)=inp_height * 0.5 + inp_width * -0.5; + dst.at(0,0)=netRT->input_dim.w * 0.5; + dst.at(0,1)=netRT->input_dim.h * 0.5; + dst.at(1,0)=netRT->input_dim.w * 0.5; + dst.at(1,1)=netRT->input_dim.h * 0.5 + netRT->input_dim.w * -0.5; src.at(2,0)=src.at(1,0) + (-src.at(0,1)+src.at(1,1) ); src.at(2,1)=src.at(1,1) + (src.at(0,0)-src.at(1,0) ); @@ -225,91 +167,87 @@ void CenternetDetection::preprocess() dst.at(2,1)=dst.at(1,1) + (dst.at(0,0)-dst.at(1,0) ); trans = cv::getAffineTransform( src, dst ); - end_t = std::chrono::steady_clock::now(); - std::cout << " TIME gett affine trans: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME gett affine trans: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; trans2 = cv::getAffineTransform( dst2, src ); - - end_t = std::chrono::steady_clock::now(); - std::cout << " TIME getAffineTrans 2: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME getAffineTrans 2: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; } sz_old = sz; #ifdef OPENCV_CUDA cv::cuda::GpuMat im_Orig; cv::cuda::GpuMat imageF1_d, imageF2_d; - im_Orig = cv::cuda::GpuMat(imageOrig); + im_Orig = cv::cuda::GpuMat(frame); cv::cuda::resize (im_Orig, imageF1_d, cv::Size(new_width, new_height)); checkCuda( cudaDeviceSynchronize() ); sz = imageF1_d.size(); std::cout<<"size: "<(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME resize: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; - cv::cuda::warpAffine(imageF1_d, imageF2_d, trans, cv::Size(inp_width, inp_height), cv::INTER_LINEAR ); + cv::cuda::warpAffine(imageF1_d, imageF2_d, trans, cv::Size(netRT->input_dim.w, netRT->input_dim.h), cv::INTER_LINEAR ); checkCuda( cudaDeviceSynchronize() ); - imageF2_d.convertTo(imageF1_d, CV_32FC3, 1/255.0); checkCuda( cudaDeviceSynchronize() ); - end_t = std::chrono::steady_clock::now(); - std::cout << " TIME convert: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME convert: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; dim2 = dim; cv::cuda::GpuMat bgr[3]; cv::cuda::split(imageF1_d,bgr);//split source - end_t = std::chrono::steady_clock::now(); - std::cout << " TIME split: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME split: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; for(int i=0; i(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME normalize: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; checkCuda(cudaMemcpy(input_d, d_ptrs, dim2.tot()*sizeof(dnnType), cudaMemcpyDeviceToDevice)); - end_t = std::chrono::steady_clock::now(); - std::cout << " TIME Memcpy to input_d: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME Memcpy to input_d: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; #else cv::Mat imageF; - resize(imageOrig, imageF, cv::Size(new_width, new_height)); + resize(frame, imageF, cv::Size(new_width, new_height)); sz = imageF.size(); std::cout<<"size: "<(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME resize: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; cv::Mat trans = cv::getAffineTransform( src, dst ); - cv::warpAffine(imageF, imageF, trans, cv::Size(inp_width, inp_height), cv::INTER_LINEAR ); - end_t = std::chrono::steady_clock::now(); - std::cout << " TIME warpAffine: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + cv::warpAffine(imageF, imageF, trans, cv::Size(netRT->input_dim.w, netRT->input_dim.h), cv::INTER_LINEAR ); + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME warpAffine: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; sz = imageF.size(); std::cout<<"size: "<(end_t - step_t).count() << " us" << std::endl; - step_t = end_t; + // end_t = std::chrono::steady_clock::now(); + // std::cout << " TIME convertto: " << std::chrono::duration_cast(end_t - step_t).count() << " us" << std::endl; + // step_t = end_t; dim2 = dim; - //split channels cv::Mat bgr[3]; cv::split(imageF,bgr);//split source - for(int i=0; i<3; i++){ bgr[i] = bgr[i] - mean[i]; bgr[i] = bgr[i] / stddev[i]; @@ -322,28 +260,20 @@ void CenternetDetection::preprocess() // std::cout<<"i: "<infer(dim2, input_d); + netRT->infer(dim, input_d); TIMER_STOP - dim2.print(); + dim.print(); } //get confidences and locations_h - conf = (dnnType *)netRT->buffersRT[3]; - loc = (dnnType *)netRT->buffersRT[4]; - - checkCuda(cudaMemcpy(confidences_h, conf, nPriors * classes * sizeof(float), cudaMemcpyDeviceToHost)); - checkCuda(cudaMemcpy(locations_h, loc, N_COORDS * nPriors * sizeof(float), cudaMemcpyDeviceToHost)); + dnnType *rt_out[2]; + rt_out[0] = (dnnType *)netRT->buffersRT[3]; + rt_out[1] = (dnnType *)netRT->buffersRT[4]; //postprocess - convert_locatios_to_boxes_and_center(); - detected = postprocess(sz.width, sz.height); + postprocess(rt_out, 2); TIMER_STOP stats.push_back(t_ns); } + +void MobilenetDetection::postprocess(dnnType **rt_out, const int n_out) +{ + checkCuda(cudaMemcpy(confidences_h, rt_out[0], nPriors * classes * sizeof(float), cudaMemcpyDeviceToHost)); + checkCuda(cudaMemcpy(locations_h, rt_out[1], N_COORDS * nPriors * sizeof(float), cudaMemcpyDeviceToHost)); + convert_locatios_to_boxes_and_center(); + + int width = originalSize.width; + int height = originalSize.height; + + float *conf_per_class; + for (int i = 1; i < classes; i++){ + conf_per_class = &confidences_h[i * nPriors]; + std::vector boxes; + for (int j = 0; j < nPriors; j++){ + + if (conf_per_class[j] > confThreshold){ + tk::dnn::box b; + b.cl = i; + b.prob = conf_per_class[j]; + b.x = locations_h[j * N_COORDS + 0]; + b.y = locations_h[j * N_COORDS + 1]; + b.w = locations_h[j * N_COORDS + 2]; + b.h = locations_h[j * N_COORDS + 3]; + + boxes.push_back(b); + } + } + std::sort(boxes.begin(), boxes.end(), boxProbCmp); + + std::vector remaining; + while (boxes.size() > 0){ + remaining.clear(); + + tk::dnn::box b; + b.cl = boxes[0].cl; + b.prob = boxes[0].prob; + b.x = boxes[0].x * width; + b.y = boxes[0].y * height; + b.w = boxes[0].w * width; + b.h = boxes[0].h * height; + detected.push_back(b); + for (size_t j = 1; j < boxes.size(); j++){ + if (iou(boxes[0], boxes[j]) <= IoUThreshold){ + remaining.push_back(boxes[j]); + } + } + boxes = remaining; + } + } +} + + +cv::Mat MobilenetDetection::draw(cv::Mat &frame) +{ + int baseline = 0; + float font_scale = 0.5; + int thickness = 2; + + tk::dnn::box b; + for (size_t i = 0; i < detected.size(); i++){ + b = detected[i]; + std::string det_class = classesNames[b.cl]; + cv::rectangle(frame, cv::Point(b.x, b.y), cv::Point(b.w, b.h), colors[b.cl], 2); + // draw label + cv::Size text_size = getTextSize(det_class, cv::FONT_HERSHEY_SIMPLEX, font_scale, thickness, &baseline); + cv::rectangle(frame, cv::Point(b.x, b.y), cv::Point((b.x + text_size.width - 2), (b.y - text_size.height - 2)), colors[b.cl], -1); + cv::putText(frame, det_class, cv::Point(b.x, (b.y - (baseline / 2))), cv::FONT_HERSHEY_SIMPLEX, font_scale, cv::Scalar(255, 255, 255), thickness); + } + return frame; +} + + } // namespace dnn } // namespace tk \ No newline at end of file diff --git a/src/Yolo3Detection.cpp b/src/Yolo3Detection.cpp index 08742c6..f94dd94 100644 --- a/src/Yolo3Detection.cpp +++ b/src/Yolo3Detection.cpp @@ -1,28 +1,14 @@ #include "Yolo3Detection.h" + namespace tk { namespace dnn { -float _colors[6][3] = { {1,0,1}, {0,0,1},{0,1,1},{0,1,0},{1,1,0},{1,0,0} }; -float get_color(int c, int x, int max) -{ - float ratio = ((float)x/max)*5; - int i = floor(ratio); - int j = ceil(ratio); - ratio -= i; - float r = (1-ratio) * _colors[i % 6][c % 3] + ratio*_colors[j % 6][c % 3]; - //printf("%f\n", r); - return r; -} - -bool Yolo3Detection::init(std::string tensor_path) { - - //const char *tensor_path = "../data/yolo3/yolo3_berkeley.rt"; +bool Yolo3Detection::init(const std::string& tensor_path, const int n_classes) { //convert network to tensorRT std::cout<<(tensor_path).c_str()<<"\n"; netRT = new tk::dnn::NetworkRT(NULL, (tensor_path).c_str() ); - if(netRT->pluginFactory->n_yolos < 2 ) { FatalError("this is not yolo3"); } @@ -31,119 +17,124 @@ bool Yolo3Detection::init(std::string tensor_path) { YoloRT *yRT = netRT->pluginFactory->yolos[i]; classes = yRT->classes; num = yRT->num; - n_masks = yRT->n_masks; + nMasks = yRT->n_masks; // make a yolo layer for interpret predictions - yolo[i] = new tk::dnn::Yolo(nullptr, classes, n_masks, ""); // yolo without input and bias - yolo[i]->mask_h = new dnnType[n_masks]; - yolo[i]->bias_h = new dnnType[num*n_masks*2]; - memcpy(yolo[i]->mask_h, yRT->mask, sizeof(dnnType)*n_masks); - memcpy(yolo[i]->bias_h, yRT->bias, sizeof(dnnType)*num*n_masks*2); + yolo[i] = new tk::dnn::Yolo(nullptr, classes, nMasks, ""); // yolo without input and bias + yolo[i]->mask_h = new dnnType[nMasks]; + yolo[i]->bias_h = new dnnType[num*nMasks*2]; + memcpy(yolo[i]->mask_h, yRT->mask, sizeof(dnnType)*nMasks); + memcpy(yolo[i]->bias_h, yRT->bias, sizeof(dnnType)*num*nMasks*2); yolo[i]->input_dim = yolo[i]->output_dim = tk::dnn::dataDim_t(1, yRT->c, yRT->h, yRT->w); yolo[i]->classesNames = yRT->classesNames; } dets = tk::dnn::Yolo::allocateDetections(tk::dnn::Yolo::MAX_DETECTIONS, classes); - +#ifndef OPENCV_CUDA checkCuda(cudaMallocHost(&input, sizeof(dnnType)*netRT->input_dim.tot())); +#endif checkCuda(cudaMalloc(&input_d, sizeof(dnnType)*netRT->input_dim.tot())); - // class colors precompute for(int c=0; cinput_dim.w, netRT->input_dim.h)); - tk::dnn::box b; - int x0, w, x1, y0, h, y1; - int objClass; - std::string det_class; - float prob; - int baseline = 0; - float fontScale = 0.5; - int thickness = 2; - // draw dets - for(int i=0; iclassesNames[b.cl]; - prob = b.prob; - - // std::cout<input_dim.w); - float yRatio = float(imageORIG.rows) / float(netRT->input_dim.h); - - resize(imageORIG, imageORIG, cv::Size(netRT->input_dim.w, netRT->input_dim.h)); - - imageORIG.convertTo(imageF, CV_32FC3, 1/255.0); + img_resized.convertTo(imagePreproc, CV_32FC3, 1/255.0); //split channels - cv::split(imageF,bgr);//split source + cv::cuda::split(imagePreproc,bgr);//split source //write channels for(int i=0; iinput_dim.c; i++) { - int idx = i*imageF.rows*imageF.cols; + std::cout<<"copio il channel"<input_dim.c-1 -i; - memcpy((void*)&input[idx], (void*)bgr[ch].data, imageF.rows*imageF.cols*sizeof(dnnType)); + checkCuda( cudaMemcpy((void*)&input_d[idx], (void*)bgr[ch].data, imagePreproc.rows*imagePreproc.cols*sizeof(dnnType), cudaMemcpyDeviceToDevice)); } +#else + cv::resize(frame, frame, cv::Size(netRT->input_dim.w, netRT->input_dim.h)); + frame.convertTo(imagePreproc, CV_32FC3, 1/255.0); + //split channels + cv::split(imagePreproc,bgr);//split source - //DO INFERENCE - dnnType *rt_out[netRT->pluginFactory->n_yolos]; + //write channels + for(int i=0; iinput_dim.c; i++) { + int idx = i*imagePreproc.rows*imagePreproc.cols; + int ch = netRT->input_dim.c-1 -i; + memcpy((void*)&input[idx], (void*)bgr[ch].data, imagePreproc.rows*imagePreproc.cols*sizeof(dnnType)); + } + checkCuda(cudaMemcpyAsync(input_d, input, netRT->input_dim.tot()*sizeof(dnnType), cudaMemcpyHostToDevice, netRT->stream)); +#endif +} + +void Yolo3Detection::update(cv::Mat &frame) +{ + TIMER_START + if(!frame.data) { + std::cout<<"YOLO: NO IMAGE DATA\n"; + return; + } + + originalSize = frame.size(); + preprocess(frame); + + //do inference tk::dnn::dataDim_t dim = netRT->input_dim; - checkCuda(cudaMemcpyAsync(input_d, input, dim.tot()*sizeof(dnnType), cudaMemcpyHostToDevice, netRT->stream)); - - printCenteredTitle(" TENSORRT inference ", '=', 30); { + + printCenteredTitle(" TENSORRT inference ", '=', 30); + { dim.print(); TIMER_START netRT->infer(dim, input_d); TIMER_STOP dim.print(); - - stats.push_back(t_ns); } - - // compute dets - ndets = 0; + + //get yolo outputs + dnnType *rt_out[netRT->pluginFactory->n_yolos]; for(int i=0; ipluginFactory->n_yolos; i++) { rt_out[i] = (dnnType*)netRT->buffersRT[i+1]; - yolo[i]->dstData = rt_out[i]; - yolo[i]->computeDetections(dets, ndets, netRT->input_dim.w, netRT->input_dim.h, thresh); } - tk::dnn::Yolo::mergeDetections(dets, ndets, classes); + + postprocess(rt_out, netRT->pluginFactory->n_yolos); + + TIMER_STOP + stats.push_back(t_ns); +} + +void Yolo3Detection::postprocess(dnnType **rt_out, const int n_out) +{ + float x_ratio = float(originalSize.width) / float(netRT->input_dim.w); + float y_ratio = float(originalSize.height) / float(netRT->input_dim.h); + + std::cout<<"RATIO:"<dstData = rt_out[i]; + yolo[i]->computeDetections(dets, nDets, netRT->input_dim.w, netRT->input_dim.h, confThreshold); + } + tk::dnn::Yolo::mergeDetections(dets, nDets, classes); // fill detected detected.clear(); - for(int j=0; j= thresh) { + if(dets[j].prob[c] >= confThreshold) { obj_class = c; prob = dets[j].prob[c]; } } if(obj_class >= 0) { - //std::cout<classesNames[b.cl]; + + // draw rectangle + cv::rectangle(frame, cv::Point(x0, y0), cv::Point(x1, y1), colors[b.cl], 2); + + // draw label + cv::Size text_size = getTextSize(det_class, cv::FONT_HERSHEY_SIMPLEX, font_scale, thickness, &baseline); + cv::rectangle(frame, cv::Point(x0, y0), cv::Point((x0 + text_size.width - 2), (y0 - text_size.height - 2)), colors[b.cl], -1); + cv::putText(frame, det_class, cv::Point(x0, (y0 - (baseline / 2))), cv::FONT_HERSHEY_SIMPLEX, font_scale, cv::Scalar(255, 255, 255), thickness); + } + return frame; +} + +tk::dnn::Yolo* Yolo3Detection::getYoloLayer(int n) +{ + if(n<3) + return yolo[n]; + else + return nullptr; } }} diff --git a/src/utils.cpp b/src/utils.cpp index 142e85f..2606741 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -129,6 +129,18 @@ int checkResult(int size, dnnType *data_d, dnnType *correct_d, bool device) { return diffs; } +float getColor(const int c, const int x, const int max) +{ + float _colors[6][3] = { {1,0,1}, {0,0,1},{0,1,1},{0,1,0},{1,1,0},{1,0,0} }; + float ratio = ((float)x/max)*5; + int i = floor(ratio); + int j = ceil(ratio); + ratio -= i; + float r = (1-ratio) * _colors[i % 6][c % 3] + ratio*_colors[j % 6][c % 3]; + return r; +} + + void resize(int size, dnnType **data) { if (*data != NULL)