├── COCO_labels.txt ├── James.mp4 ├── LICENSE ├── MobileNetV1.cpp ├── README.md ├── TestTensorFlow_Lite.cbp └── detect.tflite /COCO_labels.txt: -------------------------------------------------------------------------------- 1 | unlabeled 2 | person 3 | bicycle 4 | car 5 | motorcycle 6 | airplane 7 | bus 8 | train 9 | truck 10 | boat 11 | trafficlight 12 | firehydrant 13 | streetsign 14 | stopsign 15 | parkingmeter 16 | bench 17 | bird 18 | cat 19 | dog 20 | horse 21 | sheep 22 | cow 23 | elephant 24 | bear 25 | zebra 26 | giraffe 27 | hat 28 | backpack 29 | umbrella 30 | shoe 31 | eyeglasses 32 | handbag 33 | tie 34 | suitcase 35 | frisbee 36 | skis 37 | snowboard 38 | sportsball 39 | kite 40 | baseballbat 41 | baseballglove 42 | skateboard 43 | surfboard 44 | tennisracket 45 | bottle 46 | plate 47 | wineglass 48 | cup 49 | fork 50 | knife 51 | spoon 52 | bowl 53 | banana 54 | apple 55 | sandwich 56 | orange 57 | broccoli 58 | carrot 59 | hotdog 60 | pizza 61 | donut 62 | cake 63 | chair 64 | couch 65 | pottedplant 66 | bed 67 | mirror 68 | diningtable 69 | window 70 | desk 71 | toilet 72 | door 73 | tv 74 | laptop 75 | mouse 76 | remote 77 | keyboard 78 | cellphone 79 | microwave 80 | oven 81 | toaster 82 | sink 83 | refrigerator 84 | blender 85 | book 86 | clock 87 | vase 88 | scissors 89 | teddybear 90 | hairdrier 91 | toothbrush -------------------------------------------------------------------------------- /James.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qengineering/TensorFlow_Lite_SSD_Jetson-Nano/36e55a03be6994159ca9627157692ec896955246/James.mp4 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Q-engineering 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MobileNetV1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "tensorflow/lite/interpreter.h" 9 | #include "tensorflow/lite/kernels/register.h" 10 | #include "tensorflow/lite/string_util.h" 11 | #include "tensorflow/lite/model.h" 12 | #include 13 | 14 | /// Besides your regular TensorFlow Lite and flatbuffers library, 15 | /// you must also compiled TensorFlow Lite from scratch by bazel 16 | /// with the option GPU delegate set, before you can use the GPU delegates 17 | /// see https://qengineering.eu/install-tensorflow-2-lite-on-jetson-nano.html 18 | /// note also, it will not bring any speed improvement. 19 | //#define GPU_DELEGATE //remove comment to deploy GPU delegates 20 | 21 | #ifdef GPU_DELEGATE 22 | #include "tensorflow/lite/delegates/gpu/delegate.h" 23 | #endif // GPU_DELEGATE 24 | 25 | using namespace cv; 26 | using namespace std; 27 | 28 | int model_width; 29 | int model_height; 30 | int model_channels; 31 | 32 | std::vector Labels; 33 | std::unique_ptr interpreter; 34 | //----------------------------------------------------------------------------------------------------------------------- 35 | static bool getFileContent(std::string fileName) 36 | { 37 | 38 | // Open the File 39 | std::ifstream in(fileName.c_str()); 40 | // Check if object is valid 41 | if(!in.is_open()) return false; 42 | 43 | std::string str; 44 | // Read the next line from File untill it reaches the end. 45 | while (std::getline(in, str)) 46 | { 47 | // Line contains string of length > 0 then save it in vector 48 | if(str.size()>0) Labels.push_back(str); 49 | } 50 | // Close The File 51 | in.close(); 52 | return true; 53 | } 54 | //----------------------------------------------------------------------------------------------------------------------- 55 | void detect_from_video(Mat &src) 56 | { 57 | Mat image; 58 | int cam_width =src.cols; 59 | int cam_height=src.rows; 60 | 61 | // copy image to input as input tensor 62 | cv::resize(src, image, Size(model_width,model_height),INTER_NEAREST); 63 | memcpy(interpreter->typed_input_tensor(0), image.data, image.total() * image.elemSize()); 64 | 65 | interpreter->Invoke(); // run your model 66 | 67 | const float* detection_locations = interpreter->tensor(interpreter->outputs()[0])->data.f; 68 | const float* detection_classes=interpreter->tensor(interpreter->outputs()[1])->data.f; 69 | const float* detection_scores = interpreter->tensor(interpreter->outputs()[2])->data.f; 70 | const int num_detections = *interpreter->tensor(interpreter->outputs()[3])->data.f; 71 | 72 | //there are ALWAYS 10 detections no matter how many objects are detectable 73 | // cout << "number of detections: " << num_detections << "\n"; 74 | 75 | const float confidence_threshold = 0.5; 76 | for(int i = 0; i < num_detections; i++){ 77 | if(detection_scores[i] > confidence_threshold){ 78 | int det_index = (int)detection_classes[i]+1; 79 | float y1=detection_locations[4*i ]*cam_height; 80 | float x1=detection_locations[4*i+1]*cam_width; 81 | float y2=detection_locations[4*i+2]*cam_height; 82 | float x2=detection_locations[4*i+3]*cam_width; 83 | 84 | Rect rec((int)x1, (int)y1, (int)(x2 - x1), (int)(y2 - y1)); 85 | rectangle(src,rec, Scalar(0, 0, 255), 1, 8, 0); 86 | putText(src, format("%s", Labels[det_index].c_str()), Point(x1, y1-5) ,FONT_HERSHEY_SIMPLEX,0.5, Scalar(0, 0, 255), 1, 8, 0); 87 | } 88 | } 89 | } 90 | //----------------------------------------------------------------------------------------------------------------------- 91 | int main(int argc,char ** argv) 92 | { 93 | float f; 94 | float FPS[16]; 95 | int i, Fcnt=0; 96 | Mat frame; 97 | chrono::steady_clock::time_point Tbegin, Tend; 98 | 99 | for(i=0;i<16;i++) FPS[i]=0.0; 100 | 101 | // Load model 102 | std::unique_ptr model = tflite::FlatBufferModel::BuildFromFile("detect.tflite"); 103 | 104 | // Build the interpreter 105 | tflite::ops::builtin::BuiltinOpResolver resolver; 106 | tflite::InterpreterBuilder(*model.get(), resolver)(&interpreter); 107 | 108 | #ifdef GPU_DELEGATE 109 | TfLiteDelegate *MyDelegate = NULL; 110 | 111 | const TfLiteGpuDelegateOptionsV2 options = { 112 | .is_precision_loss_allowed = 1, //FP16, 113 | .inference_preference = TFLITE_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER, 114 | .inference_priority1 = TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY, 115 | .inference_priority2 = TFLITE_GPU_INFERENCE_PRIORITY_AUTO, 116 | .inference_priority3 = TFLITE_GPU_INFERENCE_PRIORITY_AUTO, 117 | }; 118 | MyDelegate = TfLiteGpuDelegateV2Create(&options); 119 | 120 | if(interpreter->ModifyGraphWithDelegate(MyDelegate) != kTfLiteOk) { 121 | cerr << "ERROR: Unable to use delegate" << endl; 122 | return 0; 123 | } 124 | #endif // GPU_DELEGATE 125 | 126 | interpreter->AllocateTensors(); 127 | interpreter->SetAllowFp16PrecisionForFp32(true); 128 | interpreter->SetNumThreads(4); //quad core 129 | 130 | // Get input dimension from the input tensor metadata 131 | // Assuming one input only 132 | int In = interpreter->inputs()[0]; 133 | model_height = interpreter->tensor(In)->dims->data[1]; 134 | model_width = interpreter->tensor(In)->dims->data[2]; 135 | model_channels = interpreter->tensor(In)->dims->data[3]; 136 | cout << "height : "<< model_height << endl; 137 | cout << "width : "<< model_width << endl; 138 | cout << "channels : "<< model_channels << endl; 139 | 140 | // Get the names 141 | bool result = getFileContent("COCO_labels.txt"); 142 | if(!result) 143 | { 144 | cout << "loading labels failed"; 145 | exit(-1); 146 | } 147 | 148 | VideoCapture cap("James.mp4"); 149 | if (!cap.isOpened()) { 150 | cerr << "ERROR: Unable to open the camera" << endl; 151 | return 0; 152 | } 153 | 154 | cout << "Start grabbing, press ESC on Live window to terminate" << endl; 155 | while(1){ 156 | // frame=imread("Traffic.jpg"); //need to refresh frame before dnn class detection 157 | cap >> frame; 158 | if (frame.empty()) { 159 | cerr << "ERROR: Unable to grab from the camera" << endl; 160 | break; 161 | } 162 | 163 | Tbegin = chrono::steady_clock::now(); 164 | 165 | detect_from_video(frame); 166 | 167 | Tend = chrono::steady_clock::now(); 168 | //calculate frame rate 169 | f = chrono::duration_cast (Tend - Tbegin).count(); 170 | if(f>0.0) FPS[((Fcnt++)&0x0F)]=1000.0/f; 171 | for(f=0.0, i=0;i<16;i++){ f+=FPS[i]; } 172 | putText(frame, format("FPS %0.2f", f/16),Point(10,20),FONT_HERSHEY_SIMPLEX,0.6, Scalar(0, 0, 255)); 173 | 174 | //show output 175 | imshow("Jetson Nano", frame); 176 | 177 | char esc = waitKey(5); 178 | if(esc == 27) break; 179 | } 180 | 181 | cout << "Closing the camera" << endl; 182 | destroyAllWindows(); 183 | 184 | #ifdef GPU_DELEGATE 185 | interpreter.reset(); 186 | TfLiteGpuDelegateV2Delete(MyDelegate); 187 | #endif // GPU_DELEGATE 188 | 189 | cout << "Bye!" << endl; 190 | 191 | return 0; 192 | } 193 | //----------------------------------------------------------------------------------------------------------------------- 194 | 195 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TensorFlow_Lite_SSD_Jetson-Nano 2 | ![output image]( https://qengineering.eu/images/SSD_Jetson.webp )
3 | ## TensorFlow Lite SSD running on a Jetson Nano
4 | [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)

5 | 6 | A fast C++ implementation of TensorFlow Lite SSD on a Jetson Nano.
7 | Once overclocked to 2015 MHz, the app runs at 28.5 FPS.
8 | 9 | https://arxiv.org/abs/1611.10012
10 | Training set: COCO
11 | Size: 300x300
12 | 13 | ## Benchmark. 14 | | CPU 2015 MHz | GPU 2015 MHz | CPU 1479 MHz | GPU 1479 MHZ | RPi 4 64os 1950 MHz | 15 | | :------------: | :-------------: | :-------------: | :-------------: | :-------------: | 16 | | 28.5 FPS | -- FPS | 21.8 FPS | -- FPS | 24 FPS | 17 | 18 | Special made for a Jetson Nano see [Q-engineering deep learning examples](https://qengineering.eu/deep-learning-examples-on-raspberry-32-64-os.html)
19 |
20 | ## Dependencies. 21 | To run the application, you have to: 22 | - TensorFlow Lite framework installed. [Install TensorFlow Lite](https://qengineering.eu/install-tensorflow-2-lite-on-jetson-nano.html)
23 | - Optional OpenCV installed. [Install OpenCV 4.5](https://qengineering.eu/install-opencv-4.5-on-jetson-nano.html)
24 | - Code::Blocks installed. (```$ sudo apt-get install codeblocks```) 25 | ## Running the app. 26 | To extract and run the network in Code::Blocks
27 | $ mkdir *MyDir*
28 | $ cd *MyDir*
29 | $ wget https://github.com/Qengineering/TensorFlow_Lite_SSD_Jetson-Nano/archive/refs/heads/main.zip
30 | $ unzip -j master.zip
31 | Remove master.zip, LICENSE and README.md as they are no longer needed.
32 | $ rm master.zip
33 | $ rm README.md

34 | Your *MyDir* folder must now look like this:
35 | James.mp4
36 | COCO_labels.txt
37 | detect.tflite
38 | TestTensorFlow_Lite.cpb
39 | MobileNetV1.cpp
40 |
41 | Run TestTensorFlow_Lite.cpb with Code::Blocks.
42 | You may need to adapt the specified library locations in *TestTensorFlow_Lite.cpb* to match your directory structure.

43 | With the `#define GPU_DELEGATE` uncommented, the TensorFlow Lite will deploy GPU delegates, if you have, of course, the appropriate libraries compiled by bazel. [Install GPU delegates](https://qengineering.eu/install-tensorflow-2-lite-on-jetson-nano.html)

44 | See the RPi 4 movie at: https://vimeo.com/393889226 45 | 46 | ------------ 47 | 48 | [![paypal](https://qengineering.eu/images/TipJarSmall4.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CPZTM5BB3FCYL) 49 | 50 | 51 | -------------------------------------------------------------------------------- /TestTensorFlow_Lite.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 59 | 60 | -------------------------------------------------------------------------------- /detect.tflite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qengineering/TensorFlow_Lite_SSD_Jetson-Nano/36e55a03be6994159ca9627157692ec896955246/detect.tflite --------------------------------------------------------------------------------