]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tidl/tidl-api.git/blob - examples/classification/main.cpp
Add mnist example with low compute
[tidl/tidl-api.git] / examples / classification / main.cpp
1 /******************************************************************************
2  * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
3  *   All rights reserved.
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions are met:
7  *       * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *       * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *       * Neither the name of Texas Instruments Incorporated nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  *   THE POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 #include <signal.h>
29 #include <getopt.h>
30 #include <iostream>
31 #include <iomanip>
32 #include <fstream>
33 #include <cassert>
34 #include <string>
35 #include <functional>
36 #include <queue>
37 #include <algorithm>
38 #include <time.h>
39 #include <memory.h>
40 #include <string.h>
42 #include "executor.h"
43 #include "execution_object.h"
44 #include "execution_object_pipeline.h"
45 #include "configuration.h"
46 #include "avg_fps_window.h"
47 #include "imgutil.h"
49 #include "opencv2/core.hpp"
50 #include "opencv2/imgproc.hpp"
51 #include "opencv2/highgui.hpp"
52 #include "opencv2/videoio.hpp"
55 //#define TWO_ROIs
56 #define LIVE_DISPLAY
57 #define PERF_VERBOSE
58 //#define RMT_GST_STREAMER
60 #define MAX_NUM_ROI 4
62 int live_input = 1;
63 char video_clip[320];
65 #ifdef TWO_ROIs
66 #define RES_X 400
67 #define RES_Y 300
68 #define NUM_ROI_X 2
69 #define NUM_ROI_Y 1
70 #define X_OFFSET 0
71 #define X_STEP   176
72 #define Y_OFFSET 52
73 #define Y_STEP   224
74 #else
75 #define RES_X 480
76 #define RES_Y 480
77 #define NUM_ROI_X 1
78 #define NUM_ROI_Y 1
79 #define X_OFFSET 10
80 #define X_STEP   460
81 #define Y_OFFSET 10
82 #define Y_STEP   460
83 #endif
85 #define NUM_ROI (NUM_ROI_X * NUM_ROI_Y)
87 //Temporal averaging
88 int TOP_CANDIDATES = 3;
90 using namespace tidl;
91 using namespace cv;
93 #ifdef LIVE_DISPLAY
94 char imagenet_win[160];
95 char tmp_classwindow_string[160];
96 Mat  classlist_image;
98 void imagenetCallBackFunc(int event, int x, int y, int flags, void* userdata)
99 {
100     if  ( event == EVENT_RBUTTONDOWN )
101     {
102         std::cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << " ... prepare to exit!" << std::endl;
103         exit(0);
104     }
106 #endif
108 Mat in_image, image, r_image, cnn_image, show_image, bgr_frames[3];
109 Mat to_stream;
110 Rect rectCrop[NUM_ROI];
111 // Report average FPS across a sliding window of 16 frames
112 AvgFPSWindow fps_window(16);
114 static int tf_postprocess(uchar *in, int size, int roi_idx, int frame_idx, int f_id);
115 static int ShowRegion(int roi_history[]);
116 // from most recent to oldest at top indices
117 static int selclass_history[MAX_NUM_ROI][3];
119 bool RunConfiguration(const std::string& config_file, int num_layers_groups,
120                       uint32_t num_dsps, uint32_t num_eves);
121 bool CreateExecutionObjectPipelines(uint32_t num_eves, uint32_t num_dsps,
122                                     Configuration& configuration,
123                                     uint32_t num_layers_groups,
124                                     Executor*& e_eve, Executor*& e_dsp,
125                                   std::vector<ExecutionObjectPipeline*>& eops);
126 void AllocateMemory(const std::vector<ExecutionObjectPipeline*>& eops);
127 void SetupLiveDisplay(uint32_t num_eves, uint32_t num_dsps);
128 bool SetupInput(VideoCapture& cap, VideoWriter& writer);
129 bool ReadFrame(ExecutionObjectPipeline* eop, const Configuration& c,
130                int frame_idx, VideoCapture &cap, VideoWriter& writer);
131 void DisplayFrame(const ExecutionObjectPipeline* eop, VideoWriter& writer,
132                   uint32_t frame_idx, uint32_t num_eops,
133                   uint32_t num_eves, uint32_t num_dsps);
134 static void ProcessArgs(int argc, char *argv[],
135                         std::string& config_file,
136                         uint32_t & num_dsps, uint32_t &num_eves,
137                         int & num_layers_groups);
139 static void DisplayHelp();
140 extern std::string labels_classes[];
141 extern int IMAGE_CLASSES_NUM;
142 extern int selected_items_size;
143 extern int selected_items[];
144 extern int populate_selected_items (char *filename);
145 extern void populate_labels (char *filename);
147 bool verbose = false;
149 int main(int argc, char *argv[])
151     // Catch ctrl-c to ensure a clean exit
152     signal(SIGABRT, exit);
153     signal(SIGTERM, exit);
155     // If there are no devices capable of offloading TIDL on the SoC, exit
156     uint32_t num_eves = Executor::GetNumDevices(DeviceType::EVE);
157     uint32_t num_dsps = Executor::GetNumDevices(DeviceType::DSP);
158     int num_layers_groups = 1;
160     if (num_eves == 0 && num_dsps == 0)
161     {
162         std::cout << "TI DL not supported on this SoC." << std::endl;
163         return EXIT_SUCCESS;
164     }
166     // Process arguments
167     std::string config_file;
168     ProcessArgs(argc, argv, config_file, num_dsps, num_eves, num_layers_groups);
170     bool status = false;
171     if (!config_file.empty()) {
172         std::cout << "Run single configuration: " << config_file << std::endl;
173         status = RunConfiguration(config_file, num_layers_groups, num_dsps, num_eves);
174     }
176     if (!status)
177     {
178         std::cout << "tidl FAILED" << std::endl;
179         return EXIT_FAILURE;
180     }
182     std::cout << "tidl PASSED" << std::endl;
183     return EXIT_SUCCESS;
186 bool RunConfiguration(const std::string& config_file, int num_layers_groups, uint32_t num_dsps, uint32_t num_eves)
189     // Read the TI DL configuration file
190     Configuration configuration;
191     if (!configuration.ReadFromFile(config_file))
192         return false;
194     if (verbose)
195         configuration.enableApiTrace = true;
197     try
198     {
199         // Create ExecutionObjectPipelines
200         Executor *e_eve = nullptr;
201         Executor *e_dsp = nullptr;
202         std::vector<ExecutionObjectPipeline *> eops;
203         if (! CreateExecutionObjectPipelines(num_eves, num_dsps, configuration,
204                                         num_layers_groups, e_eve, e_dsp, eops))
205             return false;
207         // Allocate input/output memory for each EOP
208         AllocateMemory(eops);
210         // Setup Live Display
211         SetupLiveDisplay(num_eves, num_dsps);
213         // Setup Input
214         VideoCapture cap;
215         VideoWriter writer;  // gstreamer
216         if (! SetupInput(cap, writer))  return false;
218         // More initialization
219         for (int k = 0; k < NUM_ROI; k++)
220             for(int i = 0; i < 3; i ++)
221                 selclass_history[k][i] = -1;
222         std::cout << "About to start ProcessFrame loop!!" << std::endl;
224         // Process frames with available EOPs in a pipelined manner
225         // additional num_eops iterations to flush the pipeline (epilogue)
226         int num_eops = eops.size();
227         for (int frame_idx = 0;
228              frame_idx < configuration.numFrames + num_eops; frame_idx++)
229         {
230             ExecutionObjectPipeline* eop = eops[frame_idx % num_eops];
232             // Wait for previous frame on the same eo to finish processing
233             if (eop->ProcessFrameWait())
234             {
235                  DisplayFrame(eop, writer, frame_idx, num_eops,
236                               num_eves, num_dsps);
237             }
238             fps_window.Tick();
240             if (ReadFrame(eop, configuration, frame_idx, cap, writer))
241                 eop->ProcessFrameStartAsync();
242         }
244         // Cleanup
245         for (auto eop : eops)
246         {
247             free(eop->GetInputBufferPtr());
248             free(eop->GetOutputBufferPtr());
249             delete eop;
250         }
251         if (e_dsp) delete e_dsp;
252         if (e_eve) delete e_eve;
253     }
254     catch (tidl::Exception &e)
255     {
256         std::cerr << e.what() << std::endl;
257         return false;
258     }
260     return true;
264 bool CreateExecutionObjectPipelines(uint32_t num_eves, uint32_t num_dsps,
265                                     Configuration& configuration,
266                                     uint32_t num_layers_groups,
267                                     Executor*& e_eve, Executor*& e_dsp,
268                                     std::vector<ExecutionObjectPipeline*>& eops)
270     DeviceIds ids_eve, ids_dsp;
271     for (uint32_t i = 0; i < num_eves; i++)
272         ids_eve.insert(static_cast<DeviceId>(i));
273     for (uint32_t i = 0; i < num_dsps; i++)
274         ids_dsp.insert(static_cast<DeviceId>(i));
275     const uint32_t buffer_factor = 2;
277     switch(num_layers_groups)
278     {
279     case 1: // Single layers group
280         e_eve = num_eves == 0 ? nullptr :
281                 new Executor(DeviceType::EVE, ids_eve, configuration);
282         e_dsp = num_dsps == 0 ? nullptr :
283                 new Executor(DeviceType::DSP, ids_dsp, configuration);
285         configuration.runFullNet = true; //Force all layers to be in the same group
287         // Construct ExecutionObjectPipeline with single Execution Object to
288         // process each frame. This is parallel processing of frames with
289         // as many DSP and EVE cores that we have on hand.
290         // If buffer_factor == 2, duplicating EOPs for double buffering
291         // and overlapping host pre/post-processing with device processing
292         for (uint32_t j = 0; j < buffer_factor; j++)
293         {
294             for (uint32_t i = 0; i < num_eves; i++)
295                 eops.push_back(new ExecutionObjectPipeline({(*e_eve)[i]}));
296             for (uint32_t i = 0; i < num_dsps; i++)
297                 eops.push_back(new ExecutionObjectPipeline({(*e_dsp)[i]}));
298         }
299         break;
301     case 2: // Two layers group
302         // Create Executors with the approriate core type, number of cores
303         // and configuration specified
304         // EVE will run layersGroupId 1 in the network, while
305         // DSP will run layersGroupId 2 in the network
306         e_eve = num_eves == 0 ? nullptr :
307                 new Executor(DeviceType::EVE, ids_eve, configuration, 1);
308         e_dsp = num_dsps == 0 ? nullptr :
309                 new Executor(DeviceType::DSP, ids_dsp, configuration, 2);
311         // Construct ExecutionObjectPipeline that utilizes multiple
312         // ExecutionObjects to process a single frame, each ExecutionObject
313         // processes one layerGroup of the network
314         // If buffer_factor == 2, duplicating EOPs for pipelining at
315         // EO level rather than at EOP level, in addition to double buffering
316         // and overlapping host pre/post-processing with device processing
317         for (uint32_t j = 0; j < buffer_factor; j++)
318         {
319             for (uint32_t i = 0; i < std::max(num_eves, num_dsps); i++)
320                 eops.push_back(new ExecutionObjectPipeline(
321                                 {(*e_eve)[i%num_eves], (*e_dsp)[i%num_dsps]}));
322         }
323         break;
325     default:
326         std::cout << "Layers groups can be either 1 or 2!" << std::endl;
327         return false;
328         break;
329     }
331     return true;
334 void AllocateMemory(const std::vector<ExecutionObjectPipeline*>& eops)
336     for (auto eop : eops)
337     {
338        size_t in_size  = eop->GetInputBufferSizeInBytes();
339        size_t out_size = eop->GetOutputBufferSizeInBytes();
340        void*  in_ptr   = malloc(in_size);
341        void*  out_ptr  = malloc(out_size);
342        assert(in_ptr != nullptr && out_ptr != nullptr);
344        ArgInfo in(in_ptr,   in_size);
345        ArgInfo out(out_ptr, out_size);
346        eop->SetInputOutputBuffer(in, out);
347     }
350 void SetupLiveDisplay(uint32_t num_eves, uint32_t num_dsps)
352 #ifdef LIVE_DISPLAY
353     sprintf(imagenet_win, "Imagenet_EVEx%d_DSPx%d", num_eves, num_dsps);
355     if(NUM_ROI > 1)
356     {
357       for(int i = 0; i < NUM_ROI; i ++) {
358         char tmp_string[80];
359         sprintf(tmp_string, "ROI[%02d]", i);
360         namedWindow(tmp_string, WINDOW_AUTOSIZE | CV_GUI_NORMAL);
361       }
362     }
363     Mat sw_stack_image = imread(
364           "/usr/share/ti/tidl/examples/classification/tidl-sw-stack-small.png",
365           IMREAD_COLOR); // Read the file
366     if( sw_stack_image.empty() )                      // Check for invalid input
367     {
368       std::cout <<  "Could not open or find the tidl-sw-stack-small image"
369                 << std::endl ;
370     } else {
371       // Create a window for display.
372       namedWindow( "TIDL SW Stack", WINDOW_AUTOSIZE | CV_GUI_NORMAL );
373       // Show our image inside it.
374       cv::imshow( "TIDL SW Stack", sw_stack_image );
375     }
377     namedWindow("ClassList", WINDOW_AUTOSIZE | CV_GUI_NORMAL);
378     namedWindow(imagenet_win, WINDOW_AUTOSIZE | CV_GUI_NORMAL);
379     //set the callback function for any mouse event
380     setMouseCallback(imagenet_win, imagenetCallBackFunc, NULL);
382     classlist_image = cv::Mat::zeros(40 + selected_items_size * 20, 220,
383                                      CV_8UC3);
384     //Erase window
385     classlist_image.setTo(Scalar::all(0));
387     for (int i = 0; i < selected_items_size; i ++)
388     {
389       sprintf(tmp_classwindow_string, "%2d) %12s", 1+i,
390               labels_classes[selected_items[i]].c_str());
391       cv::putText(classlist_image, tmp_classwindow_string,
392                   cv::Point(5, 40 + i * 20),
393                   cv::FONT_HERSHEY_COMPLEX_SMALL,
394                   0.75,
395                   cv::Scalar(255,255,255), 1, 8);
396     }
397     cv::imshow("ClassList", classlist_image);
398 #endif
401 bool SetupInput(VideoCapture& cap, VideoWriter& writer)
403    if(live_input >= 0)
404    {
405       cap.open(live_input);
407       const double fps = cap.get(CAP_PROP_FPS);
408       const int width  = cap.get(CAP_PROP_FRAME_WIDTH);
409       const int height = cap.get(CAP_PROP_FRAME_HEIGHT);
410       std::cout << "Capture camera with " << fps << " fps, " << width << "x"
411                 << height << " px" << std::endl;
413 #ifdef RMT_GST_STREAMER
414       writer.open(" appsrc ! videoconvert ! video/x-raw, format=(string)NV12, width=(int)640, height=(int)480, framerate=(fraction)30/1 ! \
415                 ducatih264enc bitrate=2000 ! queue ! h264parse config-interval=1 ! \
416                 mpegtsmux ! udpsink host=192.168.1.2 sync=false port=5000",
417                 0,fps,Size(640,480),true);
419       if (!writer.isOpened()) {
420         cap.release();
421         std::cerr << "Can't create gstreamer writer. "
422                   << "Do you have the correct version installed?" << std::endl;
423         std::cerr << "Print out OpenCV build information" << std::endl;
424         std::cout << getBuildInformation() << std::endl;
425         return false;
426       }
427 #endif
428    } else {
429      std::cout << "Video input clip: " << video_clip << std::endl;
430      cap.open(std::string(video_clip));
431       const double fps = cap.get(CAP_PROP_FPS);
432       const int width  = cap.get(CAP_PROP_FRAME_WIDTH);
433       const int height = cap.get(CAP_PROP_FRAME_HEIGHT);
434       std::cout << "Clip with " << fps << " fps, " << width << "x"
435                 << height << " px" << std::endl;
436    }
438    if (!cap.isOpened()) {
439       std::cout << "Video input not opened!" << std::endl;
440       return false;
441    }
443    for (int y = 0; y < NUM_ROI_Y; y ++) {
444       for (int x = 0; x < NUM_ROI_X; x ++) {
445          rectCrop[y * NUM_ROI_X + x] = Rect(X_OFFSET + x * X_STEP,
446                                             Y_OFFSET + y * Y_STEP, X_STEP, Y_STEP);
447          std::cout << "Rect[" << X_OFFSET + x * X_STEP << ", "
448                    << Y_OFFSET + y * Y_STEP << "]" << std::endl;
449       }
450    }
452    return true;
455 bool ReadFrame(ExecutionObjectPipeline* eop, const Configuration& c,
456                int frame_idx, VideoCapture &cap, VideoWriter& writer)
459     if (cap.grab() && frame_idx < c.numFrames)
460     {
461         if (cap.retrieve(in_image))
462         {
463             if(live_input >= 0)
464             { //Crop central square portion
465               int loc_xmin = (in_image.size().width - in_image.size().height) / 2; //Central position
466               int loc_ymin = 0;
467               int loc_w = in_image.size().height;
468               int loc_h = in_image.size().height;
470               cv::resize(in_image(Rect(loc_xmin, loc_ymin, loc_w, loc_h)), image, Size(RES_X, RES_Y));
471             } else {
472               if((in_image.size().width != RES_X) || (in_image.size().height != RES_Y))
473               {
474                 cv::resize(in_image, image, Size(RES_X,RES_Y));
475               }
476             }
478             r_image = Mat(image, rectCrop[frame_idx % NUM_ROI]);
480 #ifdef LIVE_DISPLAY
481             if(NUM_ROI > 1)
482             {
483                char tmp_string[80];
484                sprintf(tmp_string, "ROI[%02d]", frame_idx % NUM_ROI);
485                cv::imshow(tmp_string, r_image);
486             }
487 #endif
488             imgutil::PreprocessImage(r_image, eop->GetInputBufferPtr(), c);
489             eop->SetFrameIndex(frame_idx);
491 #ifdef RMT_GST_STREAMER
492             cv::resize(Mat(image, Rect(0,32,640,448)), to_stream,
493                        Size(640,480));
494             writer << to_stream;
495 #endif
497 #ifdef LIVE_DISPLAY
498                 //waitKey(2);
499             image.copyTo(show_image);
500 #endif
501             return true;
502         }
503     } else {
504         if(live_input == -1) {
505             //Rewind!
506             cap.release();
507             cap.open(std::string(video_clip));
508         }
509     }
511     return false;
515 void DisplayFrame(const ExecutionObjectPipeline* eop, VideoWriter& writer,
516                   uint32_t frame_idx, uint32_t num_eops,
517                   uint32_t num_eves, uint32_t num_dsps)
519     int f_id = eop->GetFrameIndex();
520     int curr_roi = f_id % NUM_ROI;
521     int is_object = tf_postprocess((uchar*) eop->GetOutputBufferPtr(),
522                                  IMAGE_CLASSES_NUM, curr_roi, frame_idx, f_id);
523     selclass_history[curr_roi][2] = selclass_history[curr_roi][1];
524     selclass_history[curr_roi][1] = selclass_history[curr_roi][0];
525     selclass_history[curr_roi][0] = is_object;
526     for (int r = 0; r < NUM_ROI; r ++)
527     {
528         int rpt_id =  ShowRegion(selclass_history[r]);
529         if(rpt_id >= 0)
530         {
531             // overlay the display window, if ball seen during last two times
532             cv::putText(show_image, labels_classes[rpt_id].c_str(),
533                 cv::Point(rectCrop[r].x + 5,rectCrop[r].y + 20), // Coordinates
534                 cv::FONT_HERSHEY_COMPLEX_SMALL, // Font
535                 1.0, // Scale. 2.0 = 2x bigger
536                 cv::Scalar(0,0,255), // Color
537                 1, // Thickness
538                 8); // Line type
539             cv::rectangle(show_image, rectCrop[r], Scalar(255,0,0), 3);
540             std::cout << "ROI(" << r << ")(" << rpt_id << ")="
541                       << labels_classes[rpt_id].c_str() << std::endl;
543             classlist_image.setTo(Scalar::all(0));
544             for (int k = 0; k < selected_items_size; k ++)
545             {
546                sprintf(tmp_classwindow_string, "%2d) %12s", 1+k,
547                        labels_classes[selected_items[k]].c_str());
548                cv::putText(classlist_image, tmp_classwindow_string,
549                            cv::Point(5, 40 + k * 20),
550                            cv::FONT_HERSHEY_COMPLEX_SMALL,
551                            0.75,
552                            selected_items[k] == rpt_id ? cv::Scalar(0,0,255) :
553                                                 cv::Scalar(255,255,255), 1, 8);
554             }
556             double avg_fps = fps_window.UpdateAvgFPS();
557             sprintf(tmp_classwindow_string, "FPS:%5.2lf", avg_fps );
559 #ifdef PERF_VERBOSE
560             std::cout << "Device:" << eop->GetDeviceName() << " eops("
561                       << num_eops << "), EVES(" << num_eves << ") DSPS("
562                       << num_dsps << ") FPS:" << avg_fps << std::endl;
563 #endif
564             cv::putText(classlist_image, tmp_classwindow_string,
565                        cv::Point(5, 20),
566                        cv::FONT_HERSHEY_COMPLEX_SMALL,
567                        0.75,
568                        cv::Scalar(0,255,0), 1, 8);
569             cv::imshow("ClassList", classlist_image);
570         }
571     }
573 #ifdef LIVE_DISPLAY
574     cv::imshow(imagenet_win, show_image);
575 #endif
577 #ifdef RMT_GST_STREAMER
578     cv::resize(show_image, to_stream, cv::Size(640,480));
579     writer << to_stream;
580 #endif
582 #ifdef LIVE_DISPLAY
583     waitKey(2);
584 #endif
587 // Function to process all command line arguments
588 void ProcessArgs(int argc, char *argv[], std::string& config_file,
589                  uint32_t & num_dsps, uint32_t & num_eves, int & num_layers_groups )
591     const struct option long_options[] =
592     {
593         {"labels_classes_file", required_argument, 0, 'l'},
594         {"selected_classes_file", required_argument, 0, 's'},
595         {"config_file", required_argument, 0, 'c'},
596         {"num_dsps", required_argument, 0, 'd'},
597         {"num_eves", required_argument, 0, 'e'},
598         {"num_layers_groups", required_argument, 0, 'g'},
599         {"help",        no_argument,       0, 'h'},
600         {"verbose",     no_argument,       0, 'v'},
601         {0, 0, 0, 0}
602     };
604     int option_index = 0;
606     while (true)
607     {
608         int c = getopt_long(argc, argv, "l:c:s:i:d:e:g:hv", long_options, &option_index);
610         if (c == -1)
611             break;
613         switch (c)
614         {
615             case 'l': populate_labels(optarg);
616                       break;
618             case 's': populate_selected_items(optarg);
619                       break;
621             case 'i': if(strlen(optarg) == 1)
622                       {
623                         live_input = atoi(optarg);
624                       } else {
625                         live_input = -1;
626                         strcpy(video_clip, optarg);
627                       }
628                       break;
630             case 'c': config_file = optarg;
631                       break;
633             case 'g': num_layers_groups = atoi(optarg);
634                       assert(num_layers_groups >= 1 && num_layers_groups <= 2);
635                       break;
637             case 'd': num_dsps = atoi(optarg);
638                       assert (num_dsps >= 0 && num_dsps <= 2);
639                       break;
641             case 'e': num_eves = atoi(optarg);
642                       assert (num_eves >= 0 && num_eves <= 4);
643                       break;
645             case 'v': verbose = true;
646                       break;
648             case 'h': DisplayHelp();
649                       exit(EXIT_SUCCESS);
650                       break;
652             case '?': // Error in getopt_long
653                       exit(EXIT_FAILURE);
654                       break;
656             default:
657                       std::cerr << "Unsupported option: " << c << std::endl;
658                       break;
659         }
660     }
662     // if no eves available, we can only run full net as one layer group
663     if (num_eves == 0)  num_layers_groups = 1;
666 void DisplayHelp()
668     std::cout << "Usage: tidl_classification\n"
669                  "  Will run all available networks if tidl is invoked without"
670                  " any arguments.\n  Use -c to run a single network.\n"
671                  "Optional arguments:\n"
672                  " -c                   Path to the configuration file\n"
673                  " -d <number of DSP cores> Number of DSP cores to use (0 - 2)\n"
674                  " -e <number of EVE cores> Number of EVE cores to use (0 - 2)\n"
675                  " -g <1|2>             Number of layer groups\n"
676                  " -l                   List of label strings (of all classes in model)\n"
677                  " -s                   List of strings with selected classes\n"
678                  " -i                   Video input (for camera:0,1 or video clip)\n"
679                  " -v                   Verbose output during execution\n"
680                  " -h                   Help\n";
683 // Function to filter all the reported decisions
684 bool tf_expected_id(int id)
686    // Filter out unexpected IDs
687    for (int i = 0; i < selected_items_size; i ++)
688    {
689        if(id == selected_items[i]) return true;
690    }
691    return false;
694 int tf_postprocess(uchar *in, int size, int roi_idx, int frame_idx, int f_id)
696   //prob_i = exp(TIDL_Lib_output_i) / sum(exp(TIDL_Lib_output))
697   // sort and get k largest values and corresponding indices
698   const int k = TOP_CANDIDATES;
699   int rpt_id = -1;
701   typedef std::pair<uchar, int> val_index;
702   auto constexpr cmp = [](val_index &left, val_index &right) { return left.first > right.first; };
703   std::priority_queue<val_index, std::vector<val_index>, decltype(cmp)> queue(cmp);
704   // initialize priority queue with smallest value on top
705   for (int i = 0; i < k; i++) {
706     queue.push(val_index(in[i], i));
707   }
708   // for rest input, if larger than current minimum, pop mininum, push new val
709   for (int i = k; i < size; i++)
710   {
711     if (in[i] > queue.top().first)
712     {
713       queue.pop();
714       queue.push(val_index(in[i], i));
715     }
716   }
718   // output top k values in reverse order: largest val first
719   std::vector<val_index> sorted;
720   while (! queue.empty())
721    {
722     sorted.push_back(queue.top());
723     queue.pop();
724   }
726   for (int i = 0; i < k; i++)
727   {
728       int id = sorted[i].second;
730       if (tf_expected_id(id))
731       {
732         std::cout << "Frame:" << frame_idx << "," << f_id << " ROI[" << roi_idx << "]: rank="
733                   << k-i << ", outval=" << (float)sorted[i].first / 255 << ", "
734                   << labels_classes[sorted[i].second] << std::endl;
735         rpt_id = id;
736       }
737   }
738   return rpt_id;
741 int ShowRegion(int roi_history[])
743   if((roi_history[0] >= 0) && (roi_history[0] == roi_history[1])) return roi_history[0];
744   if((roi_history[0] >= 0) && (roi_history[0] == roi_history[2])) return roi_history[0];
745   if((roi_history[1] >= 0) && (roi_history[1] == roi_history[2])) return roi_history[1];
746   return -1;