Ver código fonte

add trafficlight detect mainwindows

Your Name 9 meses atrás
pai
commit
12c0fbf9a7

+ 398 - 0
src/detection/trafficlight_software/Hungarian.cpp

@@ -0,0 +1,398 @@
+//
+// Created by lqx on 20-4-23.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Hungarian.cpp: Implementation file for Class HungarianAlgorithm.
+//
+// This is a C++ wrapper with slight modification of a hungarian algorithm implementation by Markus Buehren.
+// The original implementation is a few mex-functions for use in MATLAB, found here:
+// http://www.mathworks.com/matlabcentral/fileexchange/6543-functions-for-the-rectangular-assignment-problem
+//
+// Both this code and the orignal code are published under the BSD license.
+// by Cong Ma, 2016
+//
+
+#include <math.h>
+#include <cfloat>
+#include "Hungarian.h"
+
+
+HungarianAlgorithm::HungarianAlgorithm(){}
+HungarianAlgorithm::~HungarianAlgorithm(){}
+
+
+//********************************************************//
+// A single function wrapper for solving assignment problem.
+//********************************************************//
+double HungarianAlgorithm::Solve(vector<vector<double>>& DistMatrix, vector<int>& Assignment)
+{
+    unsigned int nRows = DistMatrix.size();
+    unsigned int nCols = DistMatrix[0].size();
+
+    double *distMatrixIn = new double[nRows * nCols];
+    int *assignment = new int[nRows];
+    double cost = 0.0;
+
+    // Fill in the distMatrixIn. Mind the index is "i + nRows * j".
+    // Here the cost matrix of size MxN is defined as a double precision array of N*M elements.
+    // In the solving functions matrices are seen to be saved MATLAB-internally in row-order.
+    // (i.e. the matrix [1 2; 3 4] will be stored as a vector [1 3 2 4], NOT [1 2 3 4]).
+    for (unsigned int i = 0; i < nRows; i++)
+        for (unsigned int j = 0; j < nCols; j++)
+            distMatrixIn[i + nRows * j] = DistMatrix[i][j];
+
+    // call solving function
+    assignmentoptimal(assignment, &cost, distMatrixIn, nRows, nCols);
+
+    Assignment.clear();
+    for (unsigned int r = 0; r < nRows; r++)
+        Assignment.push_back(assignment[r]);
+
+    delete[] distMatrixIn;
+    delete[] assignment;
+    return cost;
+}
+
+
+//********************************************************//
+// Solve optimal solution for assignment problem using Munkres algorithm, also known as Hungarian Algorithm.
+//********************************************************//
+void HungarianAlgorithm::assignmentoptimal(int *assignment, double *cost, double *distMatrixIn, int nOfRows, int nOfColumns)
+{
+    double *distMatrix, *distMatrixTemp, *distMatrixEnd, *columnEnd, value, minValue;
+    bool *coveredColumns, *coveredRows, *starMatrix, *newStarMatrix, *primeMatrix;
+    int nOfElements, minDim, row, col;
+
+    /* initialization */
+    *cost = 0;
+    for (row = 0; row<nOfRows; row++)
+        assignment[row] = -1;
+
+    /* generate working copy of distance Matrix */
+    /* check if all matrix elements are positive */
+    nOfElements = nOfRows * nOfColumns;
+    distMatrix = (double *)malloc(nOfElements * sizeof(double));
+    distMatrixEnd = distMatrix + nOfElements;
+
+    for (row = 0; row<nOfElements; row++)
+    {
+        value = distMatrixIn[row];
+        if (value < 0)
+            cerr << "All matrix elements have to be non-negative." << endl;
+        distMatrix[row] = value;
+    }
+
+
+    /* memory allocation */
+    coveredColumns = (bool *)calloc(nOfColumns, sizeof(bool));
+    coveredRows = (bool *)calloc(nOfRows, sizeof(bool));
+    starMatrix = (bool *)calloc(nOfElements, sizeof(bool));
+    primeMatrix = (bool *)calloc(nOfElements, sizeof(bool));
+    newStarMatrix = (bool *)calloc(nOfElements, sizeof(bool)); /* used in step4 */
+
+    /* preliminary steps */
+    if (nOfRows <= nOfColumns)
+    {
+        minDim = nOfRows;
+
+        for (row = 0; row<nOfRows; row++)
+        {
+            /* find the smallest element in the row */
+            distMatrixTemp = distMatrix + row;
+            minValue = *distMatrixTemp;
+            distMatrixTemp += nOfRows;
+            while (distMatrixTemp < distMatrixEnd)
+            {
+                value = *distMatrixTemp;
+                if (value < minValue)
+                    minValue = value;
+                distMatrixTemp += nOfRows;
+            }
+
+            /* subtract the smallest element from each element of the row */
+            distMatrixTemp = distMatrix + row;
+            while (distMatrixTemp < distMatrixEnd)
+            {
+                *distMatrixTemp -= minValue;
+                distMatrixTemp += nOfRows;
+            }
+        }
+
+        /* Steps 1 and 2a */
+        for (row = 0; row<nOfRows; row++)
+            for (col = 0; col<nOfColumns; col++)
+                if (fabs(distMatrix[row + nOfRows*col]) < DBL_EPSILON)
+                    if (!coveredColumns[col])
+                    {
+                        starMatrix[row + nOfRows*col] = true;
+                        coveredColumns[col] = true;
+                        break;
+                    }
+    }
+    else /* if(nOfRows > nOfColumns) */
+    {
+        minDim = nOfColumns;
+
+        for (col = 0; col<nOfColumns; col++)
+        {
+            /* find the smallest element in the column */
+            distMatrixTemp = distMatrix + nOfRows*col;
+            columnEnd = distMatrixTemp + nOfRows;
+
+            minValue = *distMatrixTemp++;
+            while (distMatrixTemp < columnEnd)
+            {
+                value = *distMatrixTemp++;
+                if (value < minValue)
+                    minValue = value;
+            }
+
+            /* subtract the smallest element from each element of the column */
+            distMatrixTemp = distMatrix + nOfRows*col;
+            while (distMatrixTemp < columnEnd)
+                *distMatrixTemp++ -= minValue;
+        }
+
+        /* Steps 1 and 2a */
+        for (col = 0; col<nOfColumns; col++)
+            for (row = 0; row<nOfRows; row++)
+                if (fabs(distMatrix[row + nOfRows*col]) < DBL_EPSILON)
+                    if (!coveredRows[row])
+                    {
+                        starMatrix[row + nOfRows*col] = true;
+                        coveredColumns[col] = true;
+                        coveredRows[row] = true;
+                        break;
+                    }
+        for (row = 0; row<nOfRows; row++)
+            coveredRows[row] = false;
+
+    }
+
+    /* move to step 2b */
+    step2b(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
+
+    /* compute cost and remove invalid assignments */
+    computeassignmentcost(assignment, cost, distMatrixIn, nOfRows);
+
+    /* free allocated memory */
+    free(distMatrix);
+    free(coveredColumns);
+    free(coveredRows);
+    free(starMatrix);
+    free(primeMatrix);
+    free(newStarMatrix);
+
+    return;
+}
+
+/********************************************************/
+void HungarianAlgorithm::buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns)
+{
+    int row, col;
+
+    for (row = 0; row<nOfRows; row++)
+        for (col = 0; col<nOfColumns; col++)
+            if (starMatrix[row + nOfRows*col])
+            {
+#ifdef ONE_INDEXING
+                assignment[row] = col + 1; /* MATLAB-Indexing */
+#else
+                assignment[row] = col;
+#endif
+                break;
+            }
+}
+
+/********************************************************/
+void HungarianAlgorithm::computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows)
+{
+    int row, col;
+
+    for (row = 0; row<nOfRows; row++)
+    {
+        col = assignment[row];
+        if (col >= 0)
+            *cost += distMatrix[row + nOfRows*col];
+    }
+}
+
+/********************************************************/
+void HungarianAlgorithm::step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
+{
+    bool *starMatrixTemp, *columnEnd;
+    int col;
+
+    /* cover every column containing a starred zero */
+    for (col = 0; col<nOfColumns; col++)
+    {
+        starMatrixTemp = starMatrix + nOfRows*col;
+        columnEnd = starMatrixTemp + nOfRows;
+        while (starMatrixTemp < columnEnd){
+            if (*starMatrixTemp++)
+            {
+                coveredColumns[col] = true;
+                break;
+            }
+        }
+    }
+
+    /* move to step 3 */
+    step2b(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
+}
+
+/********************************************************/
+void HungarianAlgorithm::step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
+{
+    int col, nOfCoveredColumns;
+
+    /* count covered columns */
+    nOfCoveredColumns = 0;
+    for (col = 0; col<nOfColumns; col++)
+        if (coveredColumns[col])
+            nOfCoveredColumns++;
+
+    if (nOfCoveredColumns == minDim)
+    {
+        /* algorithm finished */
+        buildassignmentvector(assignment, starMatrix, nOfRows, nOfColumns);
+    }
+    else
+    {
+        /* move to step 3 */
+        step3(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
+    }
+
+}
+
+/********************************************************/
+void HungarianAlgorithm::step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
+{
+    bool zerosFound;
+    int row, col, starCol;
+
+    zerosFound = true;
+    while (zerosFound)
+    {
+        zerosFound = false;
+        for (col = 0; col<nOfColumns; col++)
+            if (!coveredColumns[col])
+                for (row = 0; row<nOfRows; row++)
+                    if ((!coveredRows[row]) && (fabs(distMatrix[row + nOfRows*col]) < DBL_EPSILON))
+                    {
+                        /* prime zero */
+                        primeMatrix[row + nOfRows*col] = true;
+
+                        /* find starred zero in current row */
+                        for (starCol = 0; starCol<nOfColumns; starCol++)
+                            if (starMatrix[row + nOfRows*starCol])
+                                break;
+
+                        if (starCol == nOfColumns) /* no starred zero found */
+                        {
+                            /* move to step 4 */
+                            step4(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim, row, col);
+                            return;
+                        }
+                        else
+                        {
+                            coveredRows[row] = true;
+                            coveredColumns[starCol] = false;
+                            zerosFound = true;
+                            break;
+                        }
+                    }
+    }
+
+    /* move to step 5 */
+    step5(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
+}
+
+/********************************************************/
+void HungarianAlgorithm::step4(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim, int row, int col)
+{
+    int n, starRow, starCol, primeRow, primeCol;
+    int nOfElements = nOfRows*nOfColumns;
+
+    /* generate temporary copy of starMatrix */
+    for (n = 0; n<nOfElements; n++)
+        newStarMatrix[n] = starMatrix[n];
+
+    /* star current zero */
+    newStarMatrix[row + nOfRows*col] = true;
+
+    /* find starred zero in current column */
+    starCol = col;
+    for (starRow = 0; starRow<nOfRows; starRow++)
+        if (starMatrix[starRow + nOfRows*starCol])
+            break;
+
+    while (starRow<nOfRows)
+    {
+        /* unstar the starred zero */
+        newStarMatrix[starRow + nOfRows*starCol] = false;
+
+        /* find primed zero in current row */
+        primeRow = starRow;
+        for (primeCol = 0; primeCol<nOfColumns; primeCol++)
+            if (primeMatrix[primeRow + nOfRows*primeCol])
+                break;
+
+        /* star the primed zero */
+        newStarMatrix[primeRow + nOfRows*primeCol] = true;
+
+        /* find starred zero in current column */
+        starCol = primeCol;
+        for (starRow = 0; starRow<nOfRows; starRow++)
+            if (starMatrix[starRow + nOfRows*starCol])
+                break;
+    }
+
+    /* use temporary copy as new starMatrix */
+    /* delete all primes, uncover all rows */
+    for (n = 0; n<nOfElements; n++)
+    {
+        primeMatrix[n] = false;
+        starMatrix[n] = newStarMatrix[n];
+    }
+    for (n = 0; n<nOfRows; n++)
+        coveredRows[n] = false;
+
+    /* move to step 2a */
+    step2a(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
+}
+
+/********************************************************/
+void HungarianAlgorithm::step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
+{
+    double h, value;
+    int row, col;
+
+    /* find smallest uncovered element h */
+    h = DBL_MAX;
+    for (row = 0; row<nOfRows; row++)
+        if (!coveredRows[row])
+            for (col = 0; col<nOfColumns; col++)
+                if (!coveredColumns[col])
+                {
+                    value = distMatrix[row + nOfRows*col];
+                    if (value < h)
+                        h = value;
+                }
+
+    /* add h to each covered row */
+    for (row = 0; row<nOfRows; row++)
+        if (coveredRows[row])
+            for (col = 0; col<nOfColumns; col++)
+                distMatrix[row + nOfRows*col] += h;
+
+    /* subtract h from each uncovered column */
+    for (col = 0; col<nOfColumns; col++)
+        if (!coveredColumns[col])
+            for (row = 0; row<nOfRows; row++)
+                distMatrix[row + nOfRows*col] -= h;
+
+    /* move to step 3 */
+    step3(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
+}
+

+ 36 - 0
src/detection/trafficlight_software/Hungarian.h

@@ -0,0 +1,36 @@
+//
+// Created by lqx on 20-4-23.
+//
+
+#ifndef TRACK_SORT_HUNGARIAN_H_H
+#define TRACK_SORT_HUNGARIAN_H_H
+
+#include <iostream>
+#include <vector>
+
+using namespace std;
+
+class HungarianAlgorithm
+{
+public:
+    HungarianAlgorithm();
+    ~HungarianAlgorithm();
+    double Solve(vector<vector<double>>& DistMatrix, vector<int>& Assignment);
+
+private:
+    void assignmentoptimal(int *assignment, double *cost, double *distMatrix, int nOfRows, int nOfColumns);
+    void buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns);
+    void computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows);
+    void step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix,
+                bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
+    void step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix,
+                bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
+    void step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix,
+               bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
+    void step4(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix,
+               bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim, int row, int col);
+    void step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix,
+               bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim);
+};
+
+#endif //TRACK_SORT_HUNGARIAN_H_H

+ 106 - 0
src/detection/trafficlight_software/KalmanTracker.cpp

@@ -0,0 +1,106 @@
+//
+// Created by lqx on 20-4-23.
+//
+
+///////////////////////////////////////////////////////////////////////////////
+// KalmanTracker.cpp: KalmanTracker Class Implementation Declaration
+
+#include "KalmanTracker.h"
+#include "detect_obstacle.h"
+#include <iostream>
+
+int KalmanTracker::kf_count = 0;
+
+// initialize Kalman filter
+void KalmanTracker::init_kf(StateType stateMat)
+{
+    int stateNum = 7;
+    int measureNum = 4;
+    kf = KalmanFilter(stateNum, measureNum, 0);
+
+    measurement = Mat::zeros(measureNum, 1, CV_32F);
+
+    kf.transitionMatrix = (Mat_<float>(stateNum, stateNum) <<
+                                                            1, 0, 0, 0, 1, 0, 0,
+            0, 1, 0, 0, 0, 1, 0,
+            0, 0, 1, 0, 0, 0, 1,
+            0, 0, 0, 1, 0, 0, 0,
+            0, 0, 0, 0, 1, 0, 0,
+            0, 0, 0, 0, 0, 1, 0,
+            0, 0, 0, 0, 0, 0, 1);
+
+    setIdentity(kf.measurementMatrix);
+    setIdentity(kf.processNoiseCov, Scalar::all(1e-2));
+    setIdentity(kf.measurementNoiseCov, Scalar::all(1e-1));
+    setIdentity(kf.errorCovPost, Scalar::all(1));
+
+    // initialize state vector with bounding box in [cx,cy,s,r] style
+    kf.statePost.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
+    kf.statePost.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
+    kf.statePost.at<float>(2, 0) = stateMat.area();
+    kf.statePost.at<float>(3, 0) = stateMat.width / stateMat.height;
+}
+
+// Predict the estimated bounding box.
+StateType KalmanTracker::predict()
+{
+    // predict
+    Mat p = kf.predict();
+    m_age += 1;
+
+    if (m_time_since_update > od::max_age)
+        m_hit_streak = 0;
+    m_time_since_update += 1;
+    StateType predictBox = get_rect_xysr(p.at<float>(0, 0), p.at<float>(1, 0), p.at<float>(2, 0), p.at<float>(3, 0));
+    m_history.push_back(predictBox);
+    return m_history.back();
+}
+
+// Update the state vector with observed bounding box.
+void KalmanTracker::update(StateType stateMat, int classId, float prob)
+{
+    m_time_since_update = 0;
+    m_history.clear();
+    m_hits += 1;
+    m_hit_streak += 1;
+    m_class_id = classId;
+
+    //只保留最近的5帧检测类别
+    if (m_class_history.size() >= 5)
+        m_class_history.erase(m_class_history.begin());
+    m_class_history.push_back(classId);
+
+    m_prob = prob;
+    // measurement
+    measurement.at<float>(0, 0) = stateMat.x + stateMat.width / 2;
+    measurement.at<float>(1, 0) = stateMat.y + stateMat.height / 2;
+    measurement.at<float>(2, 0) = stateMat.area();
+    measurement.at<float>(3, 0) = stateMat.width / stateMat.height;
+
+    // update
+    kf.correct(measurement);
+}
+
+// Return the current state vector
+StateType KalmanTracker::get_state()
+{
+    Mat s = kf.statePost;
+    return get_rect_xysr(s.at<float>(0, 0), s.at<float>(1, 0), s.at<float>(2, 0), s.at<float>(3, 0));
+}
+
+
+// Convert bounding box from [cx,cy,s,r] to [x,y,w,h] style.
+StateType KalmanTracker::get_rect_xysr(float cx, float cy, float s, float r)
+{
+    float w = sqrt(s * r);
+    float h = s / w;
+    float x = (cx - w / 2);
+    float y = (cy - h / 2);
+
+    if (x < 0 && cx > 0)
+        x = 0;
+    if (y < 0 && cy > 0)
+        y = 0;
+
+    return StateType(x, y, w, h);
+}

+ 90 - 0
src/detection/trafficlight_software/KalmanTracker.h

@@ -0,0 +1,90 @@
+//
+// Created by lqx on 20-4-23.
+//
+
+#ifndef TRACK_SORT_KALMANTRACKER_H
+#define TRACK_SORT_KALMANTRACKER_H
+
+///////////////////////////////////////////////////////////////////////////////
+// KalmanTracker.h: KalmanTracker Class Declaration
+
+#include "opencv2/video/tracking.hpp"
+#include "opencv2/highgui/highgui.hpp"
+
+using namespace std;
+using namespace cv;
+
+#define StateType Rect_<float>
+
+
+// This class represents the internel state of individual tracked objects observed as bounding box.
+class KalmanTracker
+{
+public:
+    KalmanTracker()
+    {
+        init_kf(StateType());
+        m_time_since_update = 0;
+        m_hits = 0;
+        m_hit_streak = 0;
+        m_age = 0;
+        m_id = kf_count;
+        //kf_count++;
+    }
+    KalmanTracker(StateType initRect)
+    {
+        init_kf(initRect);
+        m_time_since_update = 0;
+        m_hits = 0;
+        m_hit_streak = 0;
+        m_age = 0;
+        m_id = kf_count;
+        //kf_count++;
+    }
+
+    KalmanTracker(StateType initRect, int classId,float prob)
+    {
+        init_kf(initRect);
+        m_time_since_update = 0;
+        m_hits = 0;
+        m_hit_streak = 0;
+        m_age = 0;
+        m_id = kf_count;
+        kf_count++;
+        m_class_id = classId;
+        m_prob = prob;
+    }
+
+    ~KalmanTracker()
+    {
+        m_history.clear();
+        m_class_history.clear();
+    }
+
+    StateType predict();
+    void update(StateType stateMat,int classId, float prob);
+
+    StateType get_state();
+    StateType get_rect_xysr(float cx, float cy, float s, float r);
+
+    static int kf_count;
+
+    int m_time_since_update;
+    int m_hits;
+    int m_hit_streak;
+    int m_age;
+    int m_id;
+    int m_class_id;
+    std::vector<int> m_class_history;
+    float m_prob;
+
+private:
+    void init_kf(StateType stateMat);
+
+    cv::KalmanFilter kf;
+    cv::Mat measurement;
+
+    std::vector<StateType> m_history;
+};
+
+#endif //TRACK_SORT_KALMANTRACKER_H

+ 97 - 0
src/detection/trafficlight_software/calibrator.cpp

@@ -0,0 +1,97 @@
+#include "calibrator.h"
+#include "cuda_utils.h"
+#include "utils.h"
+
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <opencv2/opencv.hpp>
+#include <opencv2/dnn/dnn.hpp>
+
+cv::Mat preprocess_img(cv::Mat& img, int input_w, int input_h) {
+  int w, h, x, y;
+  float r_w = input_w / (img.cols * 1.0);
+  float r_h = input_h / (img.rows * 1.0);
+  if (r_h > r_w) {
+    w = input_w;
+    h = r_w * img.rows;
+    x = 0;
+    y = (input_h - h) / 2;
+  } else {
+    w = r_h * img.cols;
+    h = input_h;
+    x = (input_w - w) / 2;
+    y = 0;
+  }
+  cv::Mat re(h, w, CV_8UC3);
+  cv::resize(img, re, re.size(), 0, 0, cv::INTER_LINEAR);
+  cv::Mat out(input_h, input_w, CV_8UC3, cv::Scalar(128, 128, 128));
+  re.copyTo(out(cv::Rect(x, y, re.cols, re.rows)));
+  return out;
+}
+
+Int8EntropyCalibrator2::Int8EntropyCalibrator2(int batchsize, int input_w, int input_h, const char* img_dir, const char* calib_table_name, const char* input_blob_name, bool read_cache)
+    : batchsize_(batchsize),
+      input_w_(input_w),
+      input_h_(input_h),
+      img_idx_(0),
+      img_dir_(img_dir),
+      calib_table_name_(calib_table_name),
+      input_blob_name_(input_blob_name),
+      read_cache_(read_cache) {
+  input_count_ = 3 * input_w * input_h * batchsize;
+  CUDA_CHECK(cudaMalloc(&device_input_, input_count_ * sizeof(float)));
+  read_files_in_dir(img_dir, img_files_);
+}
+
+Int8EntropyCalibrator2::~Int8EntropyCalibrator2() {
+  CUDA_CHECK(cudaFree(device_input_));
+}
+
+int Int8EntropyCalibrator2::getBatchSize() const TRT_NOEXCEPT {
+  return batchsize_;
+}
+
+bool Int8EntropyCalibrator2::getBatch(void* bindings[], const char* names[], int nbBindings) TRT_NOEXCEPT {
+  if (img_idx_ + batchsize_ > (int)img_files_.size()) {
+    return false;
+  }
+
+  std::vector<cv::Mat> input_imgs_;
+  for (int i = img_idx_; i < img_idx_ + batchsize_; i++) {
+    std::cout << img_files_[i] << "  " << i << std::endl;
+    cv::Mat temp = cv::imread(img_dir_ + img_files_[i]);
+    if (temp.empty()) {
+      std::cerr << "Fatal error: image cannot open!" << std::endl;
+      return false;
+    }
+    cv::Mat pr_img = preprocess_img(temp, input_w_, input_h_);
+    input_imgs_.push_back(pr_img);
+  }
+  img_idx_ += batchsize_;
+  cv::Mat blob = cv::dnn::blobFromImages(input_imgs_, 1.0 / 255.0, cv::Size(input_w_, input_h_), cv::Scalar(0, 0, 0), true, false);
+
+  CUDA_CHECK(cudaMemcpy(device_input_, blob.ptr<float>(0), input_count_ * sizeof(float), cudaMemcpyHostToDevice));
+  assert(!strcmp(names[0], input_blob_name_));
+  bindings[0] = device_input_;
+  return true;
+}
+
+const void* Int8EntropyCalibrator2::readCalibrationCache(size_t& length) TRT_NOEXCEPT {
+  std::cout << "reading calib cache: " << calib_table_name_ << std::endl;
+  calib_cache_.clear();
+  std::ifstream input(calib_table_name_, std::ios::binary);
+  input >> std::noskipws;
+  if (read_cache_ && input.good()) {
+    std::copy(std::istream_iterator<char>(input), std::istream_iterator<char>(), std::back_inserter(calib_cache_));
+  }
+  length = calib_cache_.size();
+  return length ? calib_cache_.data() : nullptr;
+}
+
+void Int8EntropyCalibrator2::writeCalibrationCache(const void* cache, size_t length) TRT_NOEXCEPT {
+  std::cout << "writing calib cache: " << calib_table_name_ << " size: " << length << std::endl;
+  std::ofstream output(calib_table_name_, std::ios::binary);
+  output.write(reinterpret_cast<const char*>(cache), length);
+}
+

+ 39 - 0
src/detection/trafficlight_software/calibrator.h

@@ -0,0 +1,39 @@
+#pragma once
+
+#include "macros.h"
+#include <string>
+#include <vector>
+#include <opencv2/opencv.hpp>
+
+cv::Mat preprocess_img(cv::Mat& img, int input_w, int input_h);
+
+//! \class Int8EntropyCalibrator2
+//!
+//! \brief Implements Entropy calibrator 2.
+//!  CalibrationAlgoType is kENTROPY_CALIBRATION_2.
+//!
+class Int8EntropyCalibrator2 : public nvinfer1::IInt8EntropyCalibrator2 {
+ public:
+  Int8EntropyCalibrator2(int batchsize, int input_w, int input_h, const char* img_dir, const char* calib_table_name, const char* input_blob_name, bool read_cache = true);
+
+  virtual ~Int8EntropyCalibrator2();
+  int getBatchSize() const TRT_NOEXCEPT override;
+  bool getBatch(void* bindings[], const char* names[], int nbBindings) TRT_NOEXCEPT override;
+  const void* readCalibrationCache(size_t& length) TRT_NOEXCEPT override;
+  void writeCalibrationCache(const void* cache, size_t length) TRT_NOEXCEPT override;
+
+ private:
+  int batchsize_;
+  int input_w_;
+  int input_h_;
+  int img_idx_;
+  std::string img_dir_;
+  std::vector<std::string> img_files_;
+  size_t input_count_;
+  std::string calib_table_name_;
+  const char* input_blob_name_;
+  bool read_cache_;
+  void* device_input_;
+  std::vector<char> calib_cache_;
+};
+

+ 18 - 0
src/detection/trafficlight_software/cuda_utils.h

@@ -0,0 +1,18 @@
+#ifndef TRTX_CUDA_UTILS_H_
+#define TRTX_CUDA_UTILS_H_
+
+#include <cuda_runtime_api.h>
+
+#ifndef CUDA_CHECK
+#define CUDA_CHECK(callstr)\
+    {\
+        cudaError_t error_code = callstr;\
+        if (error_code != cudaSuccess) {\
+            std::cerr << "CUDA error " << error_code << " at " << __FILE__ << ":" << __LINE__;\
+            assert(0);\
+        }\
+    }
+#endif  // CUDA_CHECK
+
+#endif  // TRTX_CUDA_UTILS_H_
+

+ 259 - 0
src/detection/trafficlight_software/detect_obstacle.cpp

@@ -0,0 +1,259 @@
+
+#include <set>
+#include "detect_obstacle.h"
+
+namespace od{
+// Computes IOU between two bounding boxes
+double GetIOU(Rect_<float> bb_test, Rect_<float> bb_gt)
+{
+    float in = (bb_test & bb_gt).area();
+    float un = bb_test.area() + bb_gt.area() - in;
+
+    if (un < DBL_EPSILON)
+        return 0;
+
+    return (double)(in / un);
+}
+
+
+//tracking obstacle
+bool TrackObstacle(int frame_count,vector<KalmanTracker> &trackers,vector<bbox_t> &outs,vector<od::TrackingBox> &track_result)
+{
+    // variables used in the for-loop
+    vector<Rect_<float>> predictedBoxes;
+    vector<vector<double>> iouMatrix;
+    vector<int> assignment;
+    set<int> unmatchedDetections;
+    set<int> unmatchedTrajectories;
+    set<int> allItems;
+    set<int> matchedItems;
+    vector<cv::Point> matchedPairs;
+    unsigned int trkNum = 0;
+    unsigned int detNum = 0;
+    vector<od::DetectBox> detect_outs;
+    //bbox_t to Detect_box
+    for(unsigned int i=0;i<outs.size();i++)
+    {
+        od::DetectBox detect_temp;
+        detect_temp.class_id = outs[i].obj_id;
+        detect_temp.prob = outs[i].prob;
+        float tpx = outs[i].x;
+        float tpy = outs[i].y;
+        float tpw = outs[i].w;
+        float tph = outs[i].h;
+        //detect_temp.box = Rect_<float>(Point_<float>(tpx, tpy),Point_<float>(tpx + tpw, tpy + tph));
+        detect_temp.box = Rect_<float>(tpx,tpy,tpw,tph);
+        detect_outs.push_back(detect_temp);
+    }
+    //tracking
+    if (trackers.size() == 0) // the first frame met
+    {
+        // initialize kalman trackers using first detections.
+        for (unsigned int i = 0; i < outs.size(); i++)
+        {
+            KalmanTracker trk = KalmanTracker(detect_outs[i].box,
+                                              detect_outs[i].class_id,
+                                              detect_outs[i].prob);
+            trackers.push_back(trk);
+        }
+        return false;
+    }
+    ///////////////////////////////////////
+    // 3.1. get predicted locations from existing trackers.
+    predictedBoxes.clear();
+
+    for (auto it = trackers.begin(); it != trackers.end();)
+    {
+        Rect_<float> pBox = (*it).predict();
+        if (pBox.x >= 0 && pBox.y >= 0)
+        {
+            predictedBoxes.push_back(pBox);
+            it++;
+        }
+        else
+        {
+
+            cerr << "Box invalid at frame: " << frame_count <<" id "<<(*it).m_id+1<<endl;
+            it = trackers.erase(it);
+
+        }
+    }
+
+    if (trackers.size() == 0 || detect_outs.size() == 0) return false;
+
+    ///////////////////////////////////////
+    // 3.2. associate detections to tracked object (both represented as bounding boxes)
+    // dets : detFrameData[fi]
+    trkNum = predictedBoxes.size();
+    detNum = outs.size();
+
+    iouMatrix.clear();
+    iouMatrix.resize(trkNum, vector<double>(detNum, 0));
+
+    for (unsigned int i = 0; i < trkNum; i++) // compute iou matrix as a distance matrix
+    {
+        for (unsigned int j = 0; j < detNum; j++)
+        {
+            // use 1-iou because the hungarian algorithm computes a minimum-cost assignment.
+            iouMatrix[i][j] = 1 - GetIOU(predictedBoxes[i], detect_outs[j].box);
+        }
+    }
+    // solve the assignment problem using hungarian algorithm.
+    // the resulting assignment is [track(prediction) : detection], with len=preNum
+    HungarianAlgorithm HungAlgo;
+    assignment.clear();
+    HungAlgo.Solve(iouMatrix, assignment);
+
+    // find matches, unmatched_detections and unmatched_predictions
+    unmatchedTrajectories.clear();
+    unmatchedDetections.clear();
+    allItems.clear();
+    matchedItems.clear();
+    if (detNum > trkNum) //	there are unmatched detections
+    {
+        for (unsigned int n = 0; n < detNum; n++)
+            allItems.insert(n);
+
+        for (unsigned int i = 0; i < trkNum; ++i)
+            matchedItems.insert(assignment[i]);
+
+        set_difference(allItems.begin(), allItems.end(),
+                       matchedItems.begin(), matchedItems.end(),
+                       insert_iterator<set<int>>(unmatchedDetections, unmatchedDetections.begin()));
+    }
+    else if (detNum < trkNum) // there are unmatched trajectory/predictions
+    {
+        for (unsigned int i = 0; i < trkNum; ++i)
+            if (assignment[i] == -1) // unassigned label will be set as -1 in the assignment algorithm
+                unmatchedTrajectories.insert(i);
+    }
+    // filter out matched with low IOU
+    matchedPairs.clear();
+    for (unsigned int i = 0; i < trkNum; ++i)
+    {
+        if (assignment[i] == -1) // pass over invalid values
+            continue;
+        if (1 - iouMatrix[i][assignment[i]] < od::iouThreshold)
+        {
+            unmatchedTrajectories.insert(i);
+            unmatchedDetections.insert(assignment[i]);
+        }
+        else
+            matchedPairs.push_back(cv::Point(i, assignment[i]));
+    }
+    ///////////////////////////////////////
+    // 3.3. updating trackers
+    // update matched trackers with assigned detections.
+    // each prediction is corresponding to a tracker
+    int detIdx, trkIdx;
+    for (unsigned int i = 0; i < matchedPairs.size(); i++)
+    {
+        trkIdx = matchedPairs[i].x;
+        detIdx = matchedPairs[i].y;
+        trackers[trkIdx].update(detect_outs[detIdx].box,
+                                detect_outs[detIdx].class_id,
+                                detect_outs[detIdx].prob);
+    }
+    // create and initialise new trackers for unmatched detections
+    for (auto umd : unmatchedDetections)
+    {
+        KalmanTracker tracker = KalmanTracker(detect_outs[umd].box,
+                                              detect_outs[umd].class_id,
+                                              detect_outs[umd].prob);
+        trackers.push_back(tracker);
+    }
+
+#if 0
+    //get unique trackers,merg same trackers
+    unsigned int trackers_num = trackers.size();
+    iouMatrix.clear();
+    iouMatrix.resize(trackers_num, vector<double>(trackers_num, 0));
+    for (unsigned int i = 0; i < trackers_num; i++) // compute iou matrix as a distance matrix
+    {
+        for (unsigned int j = 0; j < trackers_num; j++)
+        {
+            // use 1-iou because the hungarian algorithm computes a minimum-cost assignment.
+            if(j==i)
+                iouMatrix[i][j] = 1;
+            else
+                iouMatrix[i][j] = 1 - GetIOU(trackers[i].get_state(), trackers[j].get_state());
+        }
+    }
+    // solve the assignment problem using hungarian algorithm.
+    // the resulting assignment is [track(prediction) : detection], with len=preNum
+    assignment.clear();
+    HungAlgo.Solve(iouMatrix, assignment);
+    // filter out matched with low IOU
+    matchedPairs.clear();
+    for (unsigned int i = 0; i < trackers_num; ++i)
+    {
+        if (assignment[i] == -1) // pass over invalid values
+            continue;
+        if (iouMatrix[i][assignment[i]] < od::iouThreshold)
+        {
+            matchedPairs.push_back(cv::Point(i, assignment[i]));
+        }
+    }
+    int index1,index2;
+    vector<int> delete_index;
+    for (unsigned int i = 0; i < matchedPairs.size(); i++)
+    {
+        index1 = matchedPairs[i].x;
+        index2 = matchedPairs[i].y;
+        if(index1 >= index2)
+            continue;
+        if((trackers[index1].m_id > trackers[index2].m_id) && (trackers[index1].m_class_history.size()>0))
+        {
+            trackers[index1].m_id = trackers[index2].m_id;
+            trackers[index1].m_class_history.insert(trackers[index1].m_class_history.begin(),
+                                                    trackers[index2].m_class_history.begin(),trackers[index2].m_class_history.end());
+            delete_index.push_back(index2);
+        }
+        else if((trackers[index2].m_id > trackers[index1].m_id) && (trackers[index2].m_class_history.size()>0))
+        {
+            trackers[index2].m_id = trackers[index1].m_id;
+            trackers[index2].m_class_history.insert(trackers[index2].m_class_history.begin(),
+                                                    trackers[index1].m_class_history.begin(),trackers[index1].m_class_history.end());
+            delete_index.push_back(index1);
+
+        }
+    }
+    for(unsigned int i = 0; i < delete_index.size(); i++)
+    {
+        int idx = delete_index[i] - i;
+        trackers.erase(trackers.begin() + idx);
+    }
+#endif
+
+    // get trackers' output
+    track_result.clear();
+    for (auto it = trackers.begin(); it != trackers.end();)
+    {
+        if (((*it).m_time_since_update <= od::max_age) &&
+                ((*it).m_hit_streak >= od::min_hits || frame_count <= od::min_hits))
+        {
+            od::TrackingBox res;
+            res.box = (*it).get_state();
+            res.id = (*it).m_id + 1;
+            res.frame = frame_count;
+            res.class_id = (*it).m_class_id;
+            res.prob = (*it).m_prob;
+            res.class_history = (*it).m_class_history;
+            track_result.push_back(res);
+            it++;
+        }
+        else
+            it ++;
+        //remove dead tracklet
+        if(it != trackers.end() && (*it).m_time_since_update > od::max_age)
+        {
+            it = trackers.erase(it);
+        }
+    }
+    if(track_result.size()>0)
+        return true;
+    else return false;
+}
+
+
+

+ 54 - 0
src/detection/trafficlight_software/detect_obstacle.h

@@ -0,0 +1,54 @@
+#ifndef DETECT_TURNSTILE_H
+#define DETECT_TURNSTILE_H
+
+#include "Hungarian.h"
+#include "KalmanTracker.h"
+
+namespace od{
+
+const int COLOR_MAP[3][3]={{0, 0, 255},{0, 255, 0},{0,255,255}};
+const int max_age = 3;
+const int min_hits = 3;
+const double iouThreshold = 0.5;
+
+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
+    float x_3d, y_3d, z_3d;        // center of object (in Meters) if ZED 3D Camera is used
+};
+
+typedef struct TrackingBox
+{
+    int frame;
+    int id;
+    int class_id;
+    float prob;
+    Rect_<float> box;
+    vector<int> class_history;
+}TrackingBox;
+
+//yolo data o DetectBox
+typedef struct DetectBox
+{
+    int class_id;
+    float prob;
+    Rect_<float> box;
+}DetectBox;
+
+//Computes IOU between two bounding boxes
+double GetIOU(Rect_<float> bb_test, Rect_<float> bb_gt);
+//画出检测框和相关信息
+void DrawBoxes(Mat &frame, vector<string> classes, int classId, int turnstileId,float conf, int left, int top, int right, int bottom);
+
+//画出检测结果,image
+void Drawer(Mat &frame, vector<bbox_t> outs, vector<string> classes);
+//画出检测结果,video
+void Drawer(Mat &frame, vector<od::TrackingBox> &track_result, vector<string> &classes);
+//tracking obstacle
+bool TrackObstacle(int frame_count,vector<KalmanTracker> &trackers,vector<bbox_t> &outs,vector<od::TrackingBox> &track_result);
+}
+
+#endif // DETECT_TURNSTILE_H

+ 673 - 0
src/detection/trafficlight_software/grabframethread.cpp

@@ -0,0 +1,673 @@
+#pragma execution_character_set("utf-8")
+#include "grabframethread.h"
+#include <QDebug>
+#include <QImage>
+
+#include<opencv2/core/core.hpp>
+#include<opencv2/highgui/highgui.hpp>
+#include <opencv2/opencv.hpp>
+
+#include "NvInfer.h"
+#include "cuda_runtime_api.h"
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <vector>
+#include <chrono>
+#include <cmath>
+#include <cassert>
+#include <algorithm>
+#include <calibrator.h>
+
+
+int frame_count = 0;
+
+#define CHECK(status) \
+    do\
+    {\
+        auto ret = (status);\
+        if (ret != 0)\
+        {\
+            std::cerr << "Cuda failure: " << ret << std::endl;\
+            abort();\
+        }\
+    } while (0)
+
+//static Logger gLogger;
+//构建Logger
+class Logger : public ILogger
+{
+    void log(Severity severity, const char* msg) noexcept override
+    {
+        // suppress info-level messages
+        if (severity <= Severity::kWARNING)
+            std::cout << msg << std::endl;
+    }
+} gLogger;
+
+
+GrabFrameThread::GrabFrameThread(QObject *parent) : QObject(parent)
+{
+
+}
+
+void GrabFrameThread::setFrameResolution(int w, int h)
+{
+    qDebug() << tr("设置分辨率:%1*%2").arg(w).arg(h);
+    if(!g_cap.set(cv::CAP_PROP_FRAME_WIDTH,w)){
+        qDebug() << tr("设置帧宽失败");
+        emit signal_ErrGrabFrameThread(2);  // 2表示设置图像分辨率失败
+    }
+    if(!g_cap.set(cv::CAP_PROP_FRAME_HEIGHT,h)){
+        qDebug() << tr("设置帧高失败");
+        emit signal_ErrGrabFrameThread(2);  // 2表示设置图像分辨率失败
+    }
+
+    std::cout<<"size: "<<g_cap.get(cv::CAP_PROP_FRAME_HEIGHT)<<std::endl;
+}
+
+void GrabFrameThread::setParameter(float conf, float nms)
+{
+    qDebug() << tr("设置检测参数:%1*%2").arg(conf).arg(nms);
+    conf_thr = conf;
+    nms_thr = nms;
+}
+
+
+void GrabFrameThread::startDetect()
+{
+    qDebug() << tr("打开检测");
+    detect_flag = true;
+}
+
+void GrabFrameThread::closeDetect()
+{
+    qDebug() << tr("关闭检测");
+    detect_flag = false;
+}
+
+ void GrabFrameThread::destroyEngine()
+ {
+     qDebug() << tr("销毁engine");
+     context->destroy();
+     engine->destroy();
+     runtime->destroy();
+ }
+
+ void GrabFrameThread::setfp16(bool flage)
+ {
+    usefp16 = flage;
+ }
+ void GrabFrameThread::setint8(bool flage)
+ {
+    useint8 = flage;
+ }
+
+void GrabFrameThread::openCamera(int camID)
+{
+    qDebug() << tr("打开摄像头%1").arg(camID);
+    if(!g_cap.isOpened()) {
+        if(!g_cap.open(camID))
+        {
+            qDebug() << tr("打开摄像头失败");
+            emit signal_ErrGrabFrameThread(1);  // 1表示打开摄像头失败
+        }
+    } else {
+        qDebug() << tr("摄像头处于打开状态");
+    }
+
+
+    if(usefp16)
+        engine_path = "./weight_fp16.engine";
+    else if(useint8)
+            engine_path = "./weight_int8.engine";
+    else engine_path = "./weight_fp32.engine";
+    if(!LoadEngine(engine_path))
+    {
+        cout<<"Build engine to "<< engine_path <<endl;
+        get_trtengine();
+        cout << "Build engine done!"<<endl;
+        cout<<"Reload engine from "<< engine_path <<endl;
+        LoadEngine(engine_path);
+    }
+
+}
+
+void GrabFrameThread::closeCamera()
+{
+    qDebug() << tr("关闭摄像头");
+    if(g_cap.isOpened())
+        g_cap.release();
+}
+
+void GrabFrameThread::init()
+{
+    qDebug() << tr("抓帧线程初始化");
+}
+
+void GrabFrameThread::refreshFrame()
+{
+    // 接收到主线程定时器的超时信号,显示新的帧
+    cv::Mat frame;
+    if(g_cap.read(frame)){
+
+        cv::Mat readimage = cv::imread("/home/nvidia/红绿灯测试/002740.png");
+        cv::resize(readimage,frame,cv::Size(frame.cols,frame.rows));
+        if(detect_flag)
+        {
+            vector<Detection> results;
+            vector<Detection>results_track;
+            //=============== infer ===========
+            cv::Mat testimage = cv::imread("/home/nvidia/红绿灯测试/003018.png");
+
+            infer(testimage,results);
+
+            od::bbox_t bbox_t_90;   //转成跟踪格式
+            vector<od::bbox_t> outs_90;
+            for (int i = 0; i < results.size(); i++)
+            {
+                //-------------判断红绿灯是否为横向,width=(x1-x2),height=(y1-y2)-----------
+                bbox_t_90.x = results.at(i).bbox[0];
+                bbox_t_90.y = results.at(i).bbox[1];
+                bbox_t_90.w = results.at(i).bbox[2];
+                bbox_t_90.h = results.at(i).bbox[3];
+                bbox_t_90.prob = results.at(i).conf;
+                bbox_t_90.obj_id = results.at(i).class_id;
+                outs_90.push_back(bbox_t_90);
+            }
+            vector<od::TrackingBox>track_result_90;
+            bool track_flag_90 = od::TrackObstacle(frame_count,trackers_90,outs_90,track_result_90);
+
+            for(unsigned int i=0;i < track_result_90.size(); i++)
+            {
+                Detection obstacle;
+                obstacle.bbox[0] = track_result_90[i].box.x;
+                obstacle.bbox[1] = track_result_90[i].box.y;
+                obstacle.bbox[2] = track_result_90[i].box.width;
+                obstacle.bbox[3] = track_result_90[i].box.height;
+
+                //通过判断5帧数输出颜色
+                vector<int> class_history;
+                class_history = track_result_90[i].class_history;
+                if(class_history.size()>0)
+                {
+                    vector<int> color_num(3);
+                    for(int j=0;j<class_history.size();j++)
+                    {
+                        int class_id = class_history[j];
+                        color_num[class_id] += 1;
+                    }
+                    std::vector<int>::iterator biggest = std::max_element(std::begin(color_num),std::end(color_num));
+                    int maxindex = std::distance(std::begin(color_num),biggest);
+                    obstacle.class_id = maxindex;
+                }
+                else {obstacle.class_id = track_result_90[i].class_id;}
+                obstacle.conf = track_result_90[i].prob;
+                results_track.push_back(obstacle);
+
+                cv::resize(testimage,frame,cv::Size(frame.cols,frame.rows));
+                draw_rect(frame,results_track);
+                frame_count ++;
+            }
+        }
+        QImage image = cvmat_to_qimage(frame);
+        emit signal_refreshFrame(image);
+    }
+}
+
+QImage GrabFrameThread::cvmat_to_qimage(const cv::Mat &img)
+{
+    QImage image(img.data,img.cols,img.rows,img.step,QImage::Format_RGB888);
+    return image.rgbSwapped();
+}
+// Creat the engine using only the API and not any parser.
+ICudaEngine* GrabFrameThread::createEngine(unsigned int maxBatchSize, IBuilder* builder, IBuilderConfig* config)
+{
+
+    INetworkDefinition* network = builder->createNetworkV2(1U); //此处重点1U为OU就有问题
+
+    IParser* parser = createParser(*network, gLogger);
+    parser->parseFromFile(onnx_path.c_str(), static_cast<int32_t>(ILogger::Severity::kWARNING));
+    //解析有错误将返回
+    for (int32_t i = 0; i < parser->getNbErrors(); ++i) { std::cout << parser->getError(i)->desc() << std::endl; }
+    std::cout << "successfully parse the onnx model" << std::endl;
+
+    // Build engine
+    builder->setMaxBatchSize(maxBatchSize);
+    config->setMaxWorkspaceSize(1 << 20);
+
+    if(usefp16)
+        config->setFlag(nvinfer1::BuilderFlag::kFP16); // 设置精度计算
+    else if(useint8)
+    {
+        std::cout << "Your platform support int8: " << (builder->platformHasFastInt8() ? "true" : "false") << std::endl;
+        assert(builder->platformHasFastInt8());
+        config->setFlag(BuilderFlag::kINT8);
+        Int8EntropyCalibrator2* calibrator = new Int8EntropyCalibrator2(1, INPUT_W, INPUT_H, "./imagedata", "int8calib.table", INPUT_BLOB_NAME);
+        config->setInt8Calibrator(calibrator);
+    }
+
+    ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);
+    std::cout << "successfully  convert onnx to  engine!!! " << std::endl;
+
+    //销毁
+    network->destroy();
+    //parser->destroy();
+
+    return engine;
+}
+
+void GrabFrameThread::APIToModel(unsigned int maxBatchSize, IHostMemory** modelStream)
+{
+
+    // Create builder
+    IBuilder* builder = createInferBuilder(gLogger);
+    IBuilderConfig* config = builder->createBuilderConfig();
+
+    // Create model to populate the network, then set the outputs and create an engine
+    ICudaEngine* engine = createEngine(maxBatchSize, builder, config);
+
+    assert(engine != nullptr);
+
+
+
+    // Serialize the engine
+    (*modelStream) = engine->serialize();
+    // Close everything down
+    engine->destroy();
+    builder->destroy();
+    config->destroy();
+
+}
+
+
+int GrabFrameThread::get_trtengine() {
+
+    IHostMemory* modelStream{ nullptr };
+    APIToModel(1, &modelStream);
+    assert(modelStream != nullptr);
+
+    std::ofstream p(engine_path, std::ios::binary);
+    if (!p)
+    {
+        std::cerr << "could not open plan output file" << std::endl;
+        return -1;
+    }
+    p.write(reinterpret_cast<const char*>(modelStream->data()), modelStream->size());
+    modelStream->destroy();
+
+    return 0;
+
+}
+
+
+void GrabFrameThread::doInference(IExecutionContext& context, float* input, float* output, int batchSize)
+{
+    const ICudaEngine& engine = context.getEngine();
+    // Pointers to input and output device buffers to pass to engine.
+    // Engine requires exactly IEngine::getNbBindings() number of buffers.
+    assert(engine.getNbBindings() == 2);
+    void* buffers[2];
+    // In order to bind the buffers, we need to know the names of the input and output tensors.
+    // Note that indices are guaranteed to be less than IEngine::getNbBindings()
+    const int inputIndex = engine.getBindingIndex(INPUT_BLOB_NAME);
+    const int outputIndex = engine.getBindingIndex(OUTPUT_BLOB_NAME);
+
+    //std::cout<<inputIndex<<" "<<outputIndex<<std::endl;
+    //const int inputIndex = 0;
+    //const int outputIndex = 1;
+    // Create GPU buffers on device
+    cudaMalloc(&buffers[inputIndex], batchSize * 3 * INPUT_H * INPUT_W * sizeof(float));
+    cudaMalloc(&buffers[outputIndex], batchSize * OUTPUT_SIZE * sizeof(float));
+    // Create stream
+    cudaStream_t stream;
+    CHECK(cudaStreamCreate(&stream));
+    // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
+    CHECK(cudaMemcpyAsync(buffers[inputIndex], input, batchSize * 3 * INPUT_H * INPUT_W * sizeof(float), cudaMemcpyHostToDevice, stream));
+    context.enqueue(batchSize, buffers, stream, nullptr);
+
+    //std::cout<<buffers[outputIndex+1]<<std::endl;
+    CHECK(cudaMemcpyAsync(output, buffers[outputIndex], batchSize * OUTPUT_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream));
+    cudaStreamSynchronize(stream);
+    // Release stream and buffers
+    cudaStreamDestroy(stream);
+    CHECK(cudaFree(buffers[inputIndex]));
+    CHECK(cudaFree(buffers[outputIndex]));
+
+}
+
+//加工图片变成拥有batch的输入, tensorrt输入需要的格式,为一个维度
+void GrabFrameThread::ProcessImage(cv::Mat image, float input_data[]) {
+    //只处理一张图片,总之结果为一维[batch*3*INPUT_W*INPUT_H]
+    //以下代码为投机取巧了
+
+    cv::Mat resize_img ;
+    cv::resize(image, resize_img, cv::Size(INPUT_W, INPUT_H), 0, 0, cv::INTER_LINEAR);
+    std::vector<cv::Mat> InputImage;
+
+    InputImage.push_back(resize_img);
+    int ImgCount = InputImage.size();
+
+    //float input_data[BatchSize * 3 * INPUT_H * INPUT_W];
+    for (int b = 0; b < ImgCount; b++) {
+        cv::Mat img = InputImage.at(b);
+        int w = img.cols;
+        int h = img.rows;
+        int i = 0;
+        for (int row = 0; row < h; ++row) {
+            uchar* uc_pixel = img.data + row * img.step;
+            for (int col = 0; col < INPUT_W; ++col) {
+                input_data[b * 3 * INPUT_H * INPUT_W + i] = (float)uc_pixel[2] / 255.0;
+                input_data[b * 3 * INPUT_H * INPUT_W + i + INPUT_H * INPUT_W] = (float)uc_pixel[1] / 255.0;
+                input_data[b * 3 * INPUT_H * INPUT_W + i + 2 * INPUT_H * INPUT_W] = (float)uc_pixel[0] / 255.0;
+                uc_pixel += 3;
+                ++i;
+            }
+        }
+
+    }
+
+}
+
+//********************************************** NMS code **********************************//
+float GrabFrameThread::iou(Bbox box1, Bbox box2) {
+
+    int x1 = max(box1.x, box2.x);
+    int y1 = max(box1.y, box2.y);
+    int x2 = min(box1.x + box1.w, box2.x + box2.w);
+    int y2 = min(box1.y + box1.h, box2.y + box2.h);
+    int w = max(0, x2 - x1);
+    int h = max(0, y2 - y1);
+    float over_area = w * h;
+    return over_area / (box1.w * box1.h + box2.w * box2.h - over_area);
+}
+
+int GrabFrameThread::get_max_index(vector<Detection> pre_detection) {
+    //获得最佳置信度的值,并返回对应的索引值
+    int index;
+    float conf;
+    if (pre_detection.size() > 0) {
+        index = 0;
+        conf = pre_detection.at(0).conf;
+        for (int i = 0; i < pre_detection.size(); i++) {
+            if (conf < pre_detection.at(i).conf) {
+                index = i;
+                conf = pre_detection.at(i).conf;
+            }
+        }
+        return index;
+    }
+    else {
+        return -1;
+    }
+
+
+}
+bool GrabFrameThread::judge_in_lst(int index, vector<int> index_lst) {
+    //若index在列表index_lst中则返回true,否则返回false
+    if (index_lst.size() > 0) {
+        for (int i = 0; i < index_lst.size(); i++) {
+            if (index == index_lst.at(i)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+vector<int> GrabFrameThread::nms(vector<Detection> pre_detection, float iou_thr)
+{
+    /*
+    返回需保存box的pre_detection对应位置索引值
+
+    */
+    int index;
+    vector<Detection> pre_detection_new;
+    //Detection det_best;
+    Bbox box_best, box;
+    float iou_value;
+    vector<int> keep_index;
+    vector<int> del_index;
+    bool keep_bool;
+    bool del_bool;
+    int rr = 0;
+    int zz = 0;
+
+    if (pre_detection.size() > 0) {
+
+        pre_detection_new.clear();
+        // 循环将预测结果建立索引
+        for (int i = 0; i < pre_detection.size(); i++) {
+            pre_detection.at(i).index = i;
+            pre_detection_new.push_back(pre_detection.at(i));
+        }
+        //循环遍历获得保留box位置索引-相对输入pre_detection位置
+        while (pre_detection_new.size() > 0) {
+            index = get_max_index(pre_detection_new);
+            if (index >= 0) {
+                keep_index.push_back(pre_detection_new.at(index).index); //保留索引位置
+
+                // 更新最佳保留box
+                box_best.x = pre_detection_new.at(index).bbox[0];
+                box_best.y = pre_detection_new.at(index).bbox[1];
+                box_best.w = pre_detection_new.at(index).bbox[2];
+                box_best.h = pre_detection_new.at(index).bbox[3];
+
+                for (int j = 0; j < pre_detection.size(); j++) {
+                    keep_bool = judge_in_lst(pre_detection.at(j).index, keep_index);
+                    del_bool = judge_in_lst(pre_detection.at(j).index, del_index);
+                    if ((!keep_bool) && (!del_bool)) { //不在keep_index与del_index才计算iou
+                        box.x = pre_detection.at(j).bbox[0];
+                        box.y = pre_detection.at(j).bbox[1];
+                        box.w = pre_detection.at(j).bbox[2];
+                        box.h = pre_detection.at(j).bbox[3];
+                        iou_value = iou(box_best, box);
+                        if (iou_value > iou_thr) {
+                            del_index.push_back(j); //记录大于阈值将删除对应的位置
+                        }
+                    }
+
+                }
+                //更新pre_detection_new
+                pre_detection_new.clear();
+                for (int j = 0; j < pre_detection.size(); j++) {
+                    keep_bool = judge_in_lst(pre_detection.at(j).index, keep_index);
+                    del_bool = judge_in_lst(pre_detection.at(j).index, del_index);
+                    if ((!keep_bool) && (!del_bool)) {
+                        pre_detection_new.push_back(pre_detection.at(j));
+                    }
+                }
+            }
+        }
+    }
+
+    del_index.clear();
+    del_index.shrink_to_fit();
+    pre_detection_new.clear();
+    pre_detection_new.shrink_to_fit();
+
+    return  keep_index;
+
+}
+void GrabFrameThread::postprocess(float* prob,vector<Detection> &results,float conf_thr=0.2,float nms_thr=0.4)
+{
+    /*
+    #####################此函数处理一张图预测结果#########################
+    prob为[x y w h  score  multi-pre] 如80类-->(1,anchor_num,85)
+
+    */
+
+    vector<Detection> pre_results;
+    vector<int> nms_keep_index;
+    bool keep_bool;
+    Detection pre_res;
+    float conf;
+    int tmp_idx;
+    float tmp_cls_score;
+    for (int i = 0; i < anchor_output_num; i++) {
+        tmp_idx = i * (cls_num + 5);
+        pre_res.bbox[0] = prob[tmp_idx + 0];
+        pre_res.bbox[1] = prob[tmp_idx + 1];
+        pre_res.bbox[2] = prob[tmp_idx + 2];
+        pre_res.bbox[3] = prob[tmp_idx + 3];
+        conf = prob[tmp_idx + 4];  //是为目标的置信度
+        tmp_cls_score = prob[tmp_idx + 5] * conf;
+        pre_res.class_id = 0;
+        pre_res.conf = tmp_cls_score;
+        for (int j = 1; j < cls_num; j++) {
+            tmp_idx = i * (cls_num + 5) + 5 + j; //获得对应类别索引
+            if (tmp_cls_score < prob[tmp_idx] * conf)
+            {
+                tmp_cls_score = prob[tmp_idx] * conf;
+                pre_res.class_id = j;
+                pre_res.conf = tmp_cls_score;
+            }
+        }
+        if (conf >= conf_thr) {
+
+            pre_results.push_back(pre_res);
+        }
+
+    }
+
+    //使用nms
+    nms_keep_index=nms(pre_results,nms_thr);
+
+    for (int i = 0; i < pre_results.size(); i++) {
+        keep_bool = judge_in_lst(i, nms_keep_index);
+        if (keep_bool) {
+            results.push_back(pre_results.at(i));
+        }
+
+    }
+
+    pre_results.clear();
+    pre_results.shrink_to_fit();
+    nms_keep_index.clear();
+    nms_keep_index.shrink_to_fit();
+
+}
+
+void GrabFrameThread::draw_rect(cv::Mat &image, vector<Detection> &results) {
+    /*
+    image 为图像
+
+    struct  Detection {
+    float bbox[4];  //center_x center_y  w h
+    float conf;  // 置信度
+    int class_id; //类别id
+    int index;    //可忽略
+    };
+
+    */
+
+    int w1 = image.cols;
+    int h1 = image.rows;
+    int w2 = INPUT_W;
+    int h2 = INPUT_H;
+
+    float ratio_w = float(w1)/float(w2);
+    float ratio_h = float(h1)/float(h2);
+
+    float x;
+    float y;
+    float w;
+    float h;
+
+    cv::Rect rect;
+    for (int i = 0; i < results.size(); i++) {
+
+        x = results.at(i).bbox[0] * ratio_w;
+        y= results.at(i).bbox[1] * ratio_h;
+        w= results.at(i).bbox[2] * ratio_w;
+        h=results.at(i).bbox[3] * ratio_h;
+
+        x = (int)(x - w / 2);
+        y = (int)(y - h / 2);
+        w = (int)w;
+        h = (int)h;
+
+        string info;
+        //info = "id:";
+        //info.append(to_string(results.at(i).class_id));
+        //info.append(classnames[results.at(i).class_id]);
+        //info.append(":");
+        info.append(to_string((int)(results.at(i).conf*100)  )   );
+        info.append("%");
+        rect= cv::Rect(x, y, w, h);
+        if(results.at(i).class_id == 0){ // red light
+            cv::rectangle(image, rect, cv::Scalar(0, 0, 255), 1, 1, 0);//矩形的两个顶点,两个顶点都包括在矩形内部
+            cv::putText(image, info, cv::Point(x, y-5), cv::FONT_HERSHEY_SIMPLEX, 0.3, cv::Scalar(0, 0, 255), 0.6, 1, false);
+        }else if(results.at(i).class_id == 1){ // green light
+            cv::rectangle(image, rect, cv::Scalar(0, 255, 0), 1, 1, 0);//矩形的两个顶点,两个顶点都包括在矩形内部
+            cv::putText(image, info, cv::Point(x, y-5), cv::FONT_HERSHEY_SIMPLEX, 0.3, cv::Scalar(0, 255, 0), 0.6, 1, false);
+        }else if(results.at(i).class_id == 2){ // yellow light
+            cv::rectangle(image, rect, cv::Scalar(0, 255, 255), 1, 1, 0);//矩形的两个顶点,两个顶点都包括在矩形内部
+            cv::putText(image, info, cv::Point(x, y-5), cv::FONT_HERSHEY_SIMPLEX, 0.3, cv::Scalar(0, 255, 255), 0.6, 1, false);
+        }else{
+            cv::rectangle(image, rect, cv::Scalar(255, 255, 255), 1, 1, 0);//矩形的两个顶点,两个顶点都包括在矩形内部
+            cv::putText(image, info, cv::Point(x, y-5), cv::FONT_HERSHEY_SIMPLEX, 0.3, cv::Scalar(255, 255, 255), 0.6, 1, false);
+        }
+
+        std::cout<<classnames[results.at(i).class_id]<<" "<<info<<std::endl;
+
+    }
+}
+
+bool GrabFrameThread::LoadEngine(const std::string engine_path){
+    //加载engine引擎
+    char* trtModelStream{ nullptr };
+    size_t size{ 0 };
+    std::ifstream file(engine_path, std::ios::binary);
+    if(!file)
+    {
+        cout<<engine_path<<" not found!"<<endl;
+        return false;
+    }
+    if (file.good()) {
+        file.seekg(0, file.end);
+        size = file.tellg();
+        file.seekg(0, file.beg);
+        trtModelStream = new char[size];
+        assert(trtModelStream);
+        file.read(trtModelStream, size);
+        file.close();
+    }
+    //反序列为engine,创建context
+    runtime = createInferRuntime(gLogger);
+    assert(runtime != nullptr);
+    engine = runtime->deserializeCudaEngine(trtModelStream, size, nullptr);
+    //assert(engine != nullptr);
+    if(engine == nullptr)
+        return false;
+    context = engine->createExecutionContext();
+    assert(context != nullptr);
+    delete[] trtModelStream;
+
+    //在主机上分配页锁定内存
+    CHECK(cudaHostAlloc((void **)&prob, OUTPUT_SIZE * sizeof(float), cudaHostAllocDefault));
+    return true;
+}
+void GrabFrameThread::infer(cv::Mat img,vector<Detection> &results) {
+
+   // 处理图片为固定输出
+    auto start = std::chrono::system_clock::now();  //时间函数
+    static float data[3 * INPUT_H * INPUT_W];
+    ProcessImage(img, data);
+    auto end = std::chrono::system_clock::now();
+    //time_read_img = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() + time_read_img;
+
+    //cout<<"read img time: "<<std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<<"ms"<<endl;
+
+    //Run inference
+    start = std::chrono::system_clock::now();  //时间函数
+    //cout<<"doinference"<<endl;
+    doInference(*context, data, prob, 1);
+    end = std::chrono::system_clock::now();
+    //time_infer = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() + time_infer;
+    std::cout <<"doinference: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
+    postprocess(prob, results, conf_thr,  nms_thr);
+    //cout << "ok" << endl;
+    //time_num++;
+}
+

+ 116 - 0
src/detection/trafficlight_software/grabframethread.h

@@ -0,0 +1,116 @@
+#ifndef GRABFRAMETHREAD_H
+#define GRABFRAMETHREAD_H
+
+#include <QObject>
+#include <opencv2/highgui/highgui.hpp>
+#include "detect_obstacle.h"
+
+// onnx转换头文件
+#include "NvOnnxParser.h"
+using namespace nvonnxparser;
+using namespace nvinfer1;
+using namespace std;
+
+//全局变量
+struct  Detection {
+    //center_x center_y  w h
+    float bbox[4];
+    float conf;  // bbox_conf * cls_conf
+    int class_id;
+    int index;
+};
+
+struct Bbox {
+    int x;
+    int y;
+    int w;
+    int h;
+};
+
+
+class GrabFrameThread : public QObject
+{
+    Q_OBJECT
+public:
+    explicit GrabFrameThread(QObject *parent = nullptr);
+
+    void setFrameResolution(int w, int h);
+    void openCamera(int camID);
+
+    void closeCamera();
+
+    void setParameter(float conf, float nms);
+
+    void startDetect();
+    void closeDetect();
+    void destroyEngine();
+
+    void setfp16(bool flage);
+    void setint8(bool flage);
+
+signals:
+    void signal_ErrGrabFrameThread(int errCode);
+    void signal_refreshFrame(const QImage &image);
+    void signal_waitCameraOpen();
+public slots:
+    void init();
+    void refreshFrame();
+
+private:
+    QImage cvmat_to_qimage(const cv::Mat &img);
+    //增加检测相关函数
+    ICudaEngine* createEngine(unsigned int maxBatchSize, IBuilder* builder, IBuilderConfig* config);
+    void APIToModel(unsigned int maxBatchSize, IHostMemory** modelStream);
+    int get_trtengine();
+    void doInference(IExecutionContext& context, float* input, float* output, int batchSize);
+    void ProcessImage(cv::Mat image, float input_data[]);
+    float iou(Bbox box1, Bbox box2);
+    int get_max_index(vector<Detection> pre_detection);
+    bool judge_in_lst(int index, vector<int> index_lst);
+    vector<int> nms(vector<Detection> pre_detection, float iou_thr);
+    void postprocess(float* prob,vector<Detection> &results,float conf_thr, float nms_thr);
+    void draw_rect(cv::Mat &image, vector<Detection> &results);
+    bool LoadEngine(const std::string engine_path);
+    void infer(cv::Mat img,vector<Detection> &results);
+    void detectlight(cv::Mat &frame);
+
+
+private:
+    int m_camId;
+    cv::VideoCapture g_cap;
+    //添加检测相关参数
+
+    bool detect_flag = false;
+    string onnx_path = "./weight.onnx"; //onnx path
+    string engine_path = "./weight_fp32.engine"; // engine paths
+
+    bool usefp16 = false;
+    bool useint8 = false;
+
+    float conf_thr = 0.5;
+    float nms_thr = 0.4;
+    // stuff we know about the network and the input/output blobs
+    static const int INPUT_H = 640;
+    static const int INPUT_W = 640;
+    static const int cls_num = 3;
+
+    //类别
+    string classnames[3] = {"Red","Green","Yellow"};
+
+    //不同输入尺寸anchor:960-->56700 | 640-->25200 | 416-->10647 | 320-->6300
+    static const int anchor_output_num = 25200;
+    static const int OUTPUT_SIZE = 1* anchor_output_num *(cls_num+5); //1000 * sizeof(Detection) / sizeof(float) + 1;
+
+    const char* INPUT_BLOB_NAME = "images";
+    const char* OUTPUT_BLOB_NAME = "output";
+
+    IExecutionContext* context;
+    ICudaEngine* engine;
+    IRuntime* runtime;
+    float* prob;
+
+    vector<KalmanTracker> trackers_90;
+
+};
+
+#endif // GRABFRAMETHREAD_H

+ 277 - 0
src/detection/trafficlight_software/int8calib.table

@@ -0,0 +1,277 @@
+TRT-8001-EntropyCalibration2
+images: 3c010a14
+130: 3c010a14
+135: 3c010a14
+140: 3c010a14
+145: 3c010a14
+150: 3c010a14
+155: 3c010a14
+160: 3c010a14
+165: 3c010a14
+166: 3c010a14
+167: 3e543ed2
+168: 3c010a14
+169: 3d93868b
+170: 3e842896
+171: 3c010a14
+172: 3dd3a94b
+173: 3e130ce5
+174: 3c009584
+175: 3d0089ea
+176: 3dafce82
+177: 3c00263f
+178: 3d2794ec
+179: 3db0a302
+180: 3c00f10b
+181: 3d2456a3
+182: 3d6cfe04
+183: 3dc9dcb4
+184: 3c021424
+185: 3d6cfe04
+186: 3d6cfe04
+187: 3d740a46
+188: 3c03cf49
+189: 3d01fe9d
+190: 3d431eae
+191: 3c00bf04
+192: 3c87e47f
+193: 3cf7713c
+194: 3bf2cdbf
+195: 3c8ffa86
+196: 3d3cd855
+197: 3bff2177
+198: 3d10c208
+199: 3d0f86cd
+200: 3bfa128a
+201: 3c6725cb
+202: 3cdb3ab4
+203: 3d40f2b2
+204: 3c007c3e
+205: 3ca6d430
+206: 3d364036
+207: 3c014639
+208: 3cd3465e
+209: 3d23ad79
+210: 3d3315e8
+211: 3bfc06c8
+212: 3cff7e4b
+213: 3d5f3000
+214: 3c016db1
+215: 3d2a3111
+216: 3d45d0f6
+217: 3d6cd852
+218: 3c00f09b
+219: 3d45d0f6
+220: 3d45d0f6
+221: 3d454f5b
+222: 3c00e5c6
+223: 3cd5cd8f
+224: 3d603f08
+225: 3c00e0a7
+226: 3cd5c134
+227: 3cf5e822
+228: 3bef3a8c
+229: 3c5ba477
+230: 3d5ba559
+231: 3bfff09f
+232: 3d264384
+233: 3d2b394e
+234: 3bfeaeb5
+235: 3c40a045
+236: 3cc07832
+237: 3d446e8d
+238: 3c01976f
+239: 3ca67024
+240: 3d4468b8
+241: 3c02dfa6
+242: 3cb100f9
+243: 3d232581
+244: 3d490ca1
+245: 3c022e35
+246: 3cd84b5c
+247: 3d76378d
+248: 3c011169
+249: 3ce937af
+250: 3d26fa6c
+251: 3d844ac8
+252: 3c0105be
+253: 3d26fa6c
+254: 3d26fa6c
+255: 3d660e8e
+256: 3c0111b7
+257: 3d03144c
+258: 3d6c0c2a
+259: 3c01096d
+260: 3cc1d266
+261: 3d7f48bf
+262: 3c00e5cc
+263: 3dbf5ca2
+264: 3dbf5ca2
+265: 3dbf5ca2
+266: 3dbf5ca2
+267: 3dbf5ca2
+268: 3d4429e3
+269: 3c005a82
+270: 3c733665
+271: 3d80eabf
+272: 3c050e19
+273: 3d01019b
+274: 3da4c2fc
+275: 3c010e5e
+276: 3d400274
+277: 3dd62449
+278: 3c02c847
+279: 3cc2a78d
+280: 3d603b25
+281: 3c00cc54
+282: 3cc2a78d
+283: 3cc2a78d
+284: 3dc832ec
+285: 3c010be8
+286: 3d028f77
+287: 3d98b748
+288: 3c01c11e
+289: 3d6cf599
+294: 3d03144c
+295: 3d03144c
+296: 3d5dd332
+297: 3c01116e
+298: 3c9c0070
+299: 3d900d3b
+300: 3c010a14
+301: 3cd64844
+302: 3d9f174b
+303: 3c0111dc
+304: 3d02b0cc
+305: 3d5ae2d1
+306: 3c00f684
+307: 3d02b0cc
+308: 3d02b0cc
+309: 3db0c2e2
+310: 3c010a14
+311: 3d2a94af
+312: 3d835e0c
+313: 3c01d1a4
+314: 3d12f86d
+319: 3cd5cd8f
+320: 3cd5cd8f
+321: 3d31533d
+322: 3c00a7a7
+323: 3c7ffe8b
+324: 3d499fbe
+325: 3bf65879
+326: 3cc223d1
+327: 3d885731
+328: 3c010891
+329: 3d8c2c1c
+330: 3dbc5e4c
+331: 3c01eb2b
+332: 3d8c2c1c
+333: 3d8c2c1c
+334: 3e1145a3
+335: 3c01f2da
+336: 3d69b77a
+337: 3d92ab55
+338: 3c0176b2
+339: 3d12f86d
+340: 3d12f86d
+341: 3d69c711
+342: 3c010242
+343: 3d007a53
+344: 3d6effbb
+345: 3c01c89a
+346: 3cec6c14
+347: 3db534a9
+348: 3c01e702
+349: 3d967b3c
+350: 3daacbdd
+351: 3c01e227
+352: 3d967b3c
+353: 3d967b3c
+354: 3e0a60e8
+355: 3c01e03d
+356: 3d6fd187
+357: 3daa801a
+358: 3c01a593
+359: 3d6cf599
+360: 3d6cf599
+361: 3d96d4aa
+362: 3c0126eb
+363: 3d8f8b00
+364: 3d82ba43
+365: 3c01a146
+366: 3d8eb77e
+367: 3db172aa
+368: 3c01f351
+369: 3d900bbe
+370: 3d44ee81
+371: 3c01e9d3
+372: 3d900bbe
+373: 3d900bbe
+374: 3ced6e3e
+375: 3c01e259
+376: 3ccb3b1b
+377: 3e22fe2c
+395: 3e22fe2c
+396: 3e22fe2c
+397: 3c01b9a0
+398: 3c00c57f
+399: 3c04d364
+400: 40a0a072
+(Unnamed Layer* 234) [Shuffle]_output: 3c810a14
+402: 3c80c57f
+(Unnamed Layer* 236) [Constant]_output: 3f1e465d
+404: 3f20a072
+(Unnamed Layer* 239) [Shuffle]_output: 3d810a14
+406: 40a0a072
+(Unnamed Layer* 242) [Shuffle]_output: 3c810a14
+408: 3c84d364
+(Unnamed Layer* 245) [Shuffle]_output: 3c810a14
+410: 3d046c83
+(Unnamed Layer* 247) [Constant]_output: 3e851265
+412: 40a0a072
+413: 40a0a072
+420: 40a0783a
+421: 3decf938
+439: 3decf938
+440: 3decf938
+441: 3c010a86
+442: 3bfff72e
+443: 3bf0c9d4
+444: 409fca47
+(Unnamed Layer* 278) [Shuffle]_output: 3c810a14
+446: 3c7ff72e
+(Unnamed Layer* 280) [Constant]_output: 3e9b4020
+448: 3e9fca47
+(Unnamed Layer* 283) [Shuffle]_output: 3e010a14
+450: 409fca47
+(Unnamed Layer* 286) [Shuffle]_output: 3c810a14
+452: 3c70c9d4
+(Unnamed Layer* 289) [Shuffle]_output: 3c810a14
+454: 3ce098a8
+(Unnamed Layer* 291) [Constant]_output: 3f6feebd
+456: 409fca47
+457: 409fca47
+464: 40a0783a
+465: 3ddacc20
+483: 3ddacc20
+484: 3ddacc20
+485: 3c013f3c
+486: 3c1bd503
+487: 3c02179a
+488: 409df3fa
+(Unnamed Layer* 322) [Shuffle]_output: 3c810a14
+490: 3c9bd503
+(Unnamed Layer* 324) [Constant]_output: 3e1533a7
+492: 3e1f7eaa
+(Unnamed Layer* 327) [Shuffle]_output: 3e810a14
+494: 409df3fa
+(Unnamed Layer* 330) [Shuffle]_output: 3c810a14
+496: 3c82179a
+(Unnamed Layer* 333) [Shuffle]_output: 3c810a14
+498: 3d0026d2
+(Unnamed Layer* 335) [Constant]_output: 403c03af
+500: 409df3fa
+501: 409df3fa
+508: 40a0783a
+output: 40a0783a

+ 29 - 0
src/detection/trafficlight_software/macros.h

@@ -0,0 +1,29 @@
+#ifndef __MACROS_H
+#define __MACROS_H
+
+#include <NvInfer.h>
+
+#ifdef API_EXPORTS
+#if defined(_MSC_VER)
+#define API __declspec(dllexport)
+#else
+#define API __attribute__((visibility("default")))
+#endif
+#else
+
+#if defined(_MSC_VER)
+#define API __declspec(dllimport)
+#else
+#define API
+#endif
+#endif  // API_EXPORTS
+
+#if NV_TENSORRT_MAJOR >= 8
+#define TRT_NOEXCEPT noexcept
+#define TRT_CONST_ENQUEUE const
+#else
+#define TRT_NOEXCEPT
+#define TRT_CONST_ENQUEUE
+#endif
+
+#endif  // __MACROS_H

+ 72 - 0
src/detection/trafficlight_software/main.cpp

@@ -0,0 +1,72 @@
+#include "mainwindow.h"
+#include <QApplication>
+
+#include <QFile>
+#include <QMessageLogContext>
+#include <QDebug>
+#include <QDateTime>
+#include <QDir>
+#include <QMutex>
+
+void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg);
+
+int main(int argc, char *argv[])
+{
+    // 安装消息处理函数
+    qInstallMessageHandler(outputMessage);
+
+    QApplication a(argc, argv);
+    MainWindow w;
+    w.show();
+
+    return a.exec();
+}
+
+void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+    static QMutex mutex;
+    mutex.lock();
+    QByteArray localMsg = msg.toLocal8Bit();
+    QString text;
+    switch (type) {
+    case QtDebugMsg:
+        text = QString("Debug:");
+        break;
+    case QtWarningMsg:
+        text = QString("Warning:");
+        break;
+    case QtCriticalMsg:
+        text = QString("Critical:");
+        break;
+    case QtFatalMsg:
+        text = QString("Fatal:");
+        break;
+    default:
+        text = QString("Debug:");
+        break;
+    }
+
+    // 输出信息格式
+    const QString context_info = QString("File:(%1)").arg(QString(context.file));
+    const QString strDataTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
+#ifdef DEBUG
+    const QString strMessage = QString("[%1] [%2]\t[%3]\t[%4]").arg(text).arg(strDataTime).arg(context_info).arg(msg);
+#else
+    const QString strMessage = QString("[%1] [%2]\t[%3]\t[%4]").arg(text).arg(strDataTime).arg(context_info).arg(msg);
+#endif
+
+    // 输出信息到文件中
+    const QString strFilePath = QString(QDir::toNativeSeparators(QApplication::applicationDirPath()) + QDir::toNativeSeparators("/log/"));
+    const QString strFileName = QString(strFilePath + QDateTime::currentDateTime().toString("yyyy-MM-dd").append("-log.txt"));
+    if(!QDir(strFilePath).exists()){
+        QDir(strFilePath).mkdir(strFilePath);
+    }
+    QFile file(strFileName);
+    file.open(QIODevice::ReadWrite | QIODevice::Append);
+    QTextStream stream(&file);
+    stream << strMessage << "\r\n";
+    file.flush();
+    file.close();
+    //解锁
+    mutex.unlock();
+}

+ 147 - 0
src/detection/trafficlight_software/mainwindow.cpp

@@ -0,0 +1,147 @@
+#pragma execution_character_set("utf-8")
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include "grabframethread.h"
+
+#include <QCameraInfo>
+#include <QThread>
+#include <QTimer>
+#include <QCursor>
+
+MainWindow::MainWindow(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::MainWindow)
+{
+    ui->setupUi(this);
+    ui->label_ShowImage->setBackgroundRole(QPalette::Dark);
+
+    on_action_FindCamera_triggered();
+
+    initParm();
+
+}
+
+MainWindow::~MainWindow()
+{
+    delete ui;
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+    if(m_thread->isRunning()){
+        m_grabFrameThread->closeCamera();
+        m_thread->quit();
+        m_thread->wait();
+    }
+}
+
+void MainWindow::on_action_FindCamera_triggered()
+{
+    ui->comboBox_CameraList->clear();
+    m_cameraList.clear();
+    m_cameraList = QCameraInfo::availableCameras();
+    for(int i=0;i<m_cameraList.size();++i){
+        ui->comboBox_CameraList->addItem(m_cameraList.at(i).description());
+    }
+}
+
+void MainWindow::on_action_OpenCamera_triggered()
+{
+    if(ui->action_OpenCamera->text() == tr("打开摄像头")){
+        if(ui->comboBox_CameraList->count() > 0){
+
+            if(!m_timerShowFrame->isActive())
+                m_timerShowFrame->start();
+            ui->action_OpenCamera->setText(tr("关闭摄像头"));
+            // 打开相机
+            m_grabFrameThread->openCamera(ui->comboBox_CameraList->currentIndex());
+            // 设置分辨率
+            on_pushButton_SetResolution_clicked();
+            //设置检测参数
+            on_pushButton_SetParam_clicked();
+            //设置计算精度
+            on_checkBox_fp16_clicked();
+            on_checkBox_int8_clicked();
+
+            QApplication::setOverrideCursor(Qt::WaitCursor);
+        } else {
+            qDebug() << tr("当前设备没有摄像头");
+        }
+
+    } else {
+        ui->action_OpenCamera->setText(tr("打开摄像头"));
+        m_grabFrameThread->closeCamera();
+        m_timerShowFrame->stop();
+        ui->label_ShowImage->clear();
+
+        // Destroy the engine
+        m_grabFrameThread->destroyEngine();
+
+    }
+}
+
+void MainWindow::refreshFrame(const QImage &image)
+{
+    if(Qt::ArrowCursor != QApplication::overrideCursor()->shape())
+        QApplication::setOverrideCursor(Qt::ArrowCursor);
+    ui->label_ShowImage->setPixmap(QPixmap::fromImage(image));
+//    ui->label_ShowImage->adjustSize();
+}
+
+void MainWindow::initParm()
+{
+
+    m_thread = new QThread;
+    m_grabFrameThread = new GrabFrameThread;
+    m_timerShowFrame = new QTimer(this);
+    m_grabFrameThread->moveToThread(m_thread);
+
+    connect(m_thread,&QThread::finished,m_thread,&QThread::deleteLater);
+    connect(m_thread,&QThread::finished,m_grabFrameThread,&GrabFrameThread::deleteLater);
+    connect(m_thread,&QThread::finished,m_grabFrameThread,&GrabFrameThread::init);
+
+    connect(m_timerShowFrame,&QTimer::timeout,m_grabFrameThread,&GrabFrameThread::refreshFrame);
+    connect(m_grabFrameThread,&GrabFrameThread::signal_refreshFrame,this,&MainWindow::refreshFrame);
+
+    m_timerShowFrame->setInterval(33);
+
+    m_thread->start();
+}
+
+void MainWindow::on_pushButton_SetResolution_clicked()
+{
+    ui->spinBox_FrameWidth->interpretText();
+    ui->spinBox_FrameHeight->interpretText();
+    const int frameWidth = ui->spinBox_FrameWidth->value();
+    const int frameHeight = ui->spinBox_FrameHeight->value();
+    m_grabFrameThread->setFrameResolution(frameWidth,frameHeight);
+}
+
+void MainWindow::on_pushButton_SetParam_clicked()
+{
+    ui->doubleSpinBox_conf->interpretText();
+    ui->doubleSpinBox_nms->interpretText();
+    const float conf_threshold = ui->doubleSpinBox_conf->value();
+    const float nms_threshold = ui->doubleSpinBox_nms->value();
+    m_grabFrameThread->setParameter(conf_threshold,nms_threshold);
+}
+
+void MainWindow::on_pushButton_StartDetec_clicked()
+{
+    m_grabFrameThread->startDetect();
+}
+
+void MainWindow::on_pushButton_EndDetec_clicked()
+{
+    m_grabFrameThread->closeDetect();
+}
+
+void MainWindow::on_checkBox_fp16_clicked()
+{
+    m_grabFrameThread->setfp16(ui->checkBox_fp16->isChecked());
+}
+
+void MainWindow::on_checkBox_int8_clicked()
+{
+    m_grabFrameThread->setint8(ui->checkBox_int8->isChecked());
+}

+ 53 - 0
src/detection/trafficlight_software/mainwindow.h

@@ -0,0 +1,53 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+namespace Ui {
+class MainWindow;
+}
+
+class QCameraInfo;
+class QThread;
+class GrabFrameThread;
+
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    explicit MainWindow(QWidget *parent = 0);
+    ~MainWindow();
+
+protected:
+    void closeEvent(QCloseEvent *event) override;
+private slots:
+    void on_action_FindCamera_triggered();
+
+    void on_action_OpenCamera_triggered();
+
+    void refreshFrame(const QImage &image);
+
+    void on_pushButton_SetResolution_clicked();
+
+    void on_pushButton_SetParam_clicked();
+
+    void on_pushButton_StartDetec_clicked();
+
+    void on_pushButton_EndDetec_clicked();
+
+    void on_checkBox_fp16_clicked();
+
+    void on_checkBox_int8_clicked();
+
+private:
+    void initParm();
+private:
+    Ui::MainWindow *ui;
+    QList<QCameraInfo> m_cameraList;
+    QThread *m_thread;
+    GrabFrameThread *m_grabFrameThread;
+    QTimer *m_timerShowFrame;
+};
+
+#endif // MAINWINDOW_H

+ 291 - 0
src/detection/trafficlight_software/mainwindow.ui

@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>960</width>
+    <height>669</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QHBoxLayout" name="horizontalLayout">
+    <item>
+     <widget class="QWidget" name="widget" native="true">
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="0">
+        <widget class="QLabel" name="label_ShowImage">
+         <property name="autoFillBackground">
+          <bool>true</bool>
+         </property>
+         <property name="text">
+          <string>No Frame</string>
+         </property>
+         <property name="scaledContents">
+          <bool>true</bool>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignCenter</set>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item>
+     <widget class="QWidget" name="widget_2" native="true">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <layout class="QVBoxLayout" name="verticalLayout_2">
+       <item>
+        <widget class="QGroupBox" name="groupBox_Cameras">
+         <property name="title">
+          <string>CameraList:</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout">
+          <item>
+           <widget class="QComboBox" name="comboBox_CameraList"/>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="title">
+          <string>Camera Resolution</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <layout class="QFormLayout" name="formLayout">
+            <item row="0" column="0">
+             <widget class="QLabel" name="label">
+              <property name="text">
+               <string>Width:</string>
+              </property>
+             </widget>
+            </item>
+            <item row="0" column="1">
+             <widget class="QSpinBox" name="spinBox_FrameWidth">
+              <property name="maximum">
+               <number>65535</number>
+              </property>
+              <property name="value">
+               <number>640</number>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="0">
+             <widget class="QLabel" name="label_2">
+              <property name="text">
+               <string>Height:</string>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="1">
+             <widget class="QSpinBox" name="spinBox_FrameHeight">
+              <property name="maximum">
+               <number>65535</number>
+              </property>
+              <property name="value">
+               <number>480</number>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <widget class="QPushButton" name="pushButton_SetResolution">
+            <property name="text">
+             <string>设置分辨率</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox_2">
+         <property name="enabled">
+          <bool>true</bool>
+         </property>
+         <property name="title">
+          <string>Parameter Setting</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_2">
+          <item row="0" column="0">
+           <layout class="QFormLayout" name="formLayout_2">
+            <item row="0" column="0">
+             <widget class="QLabel" name="label_3">
+              <property name="text">
+               <string>conf_thr</string>
+              </property>
+             </widget>
+            </item>
+            <item row="0" column="1">
+             <widget class="QDoubleSpinBox" name="doubleSpinBox_conf">
+              <property name="maximum">
+               <double>1.000000000000000</double>
+              </property>
+              <property name="singleStep">
+               <double>0.100000000000000</double>
+              </property>
+              <property name="value">
+               <double>0.500000000000000</double>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="0">
+             <widget class="QLabel" name="label_4">
+              <property name="text">
+               <string>nms_thr</string>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="1">
+             <widget class="QDoubleSpinBox" name="doubleSpinBox_nms">
+              <property name="maximum">
+               <double>1.000000000000000</double>
+              </property>
+              <property name="singleStep">
+               <double>0.100000000000000</double>
+              </property>
+              <property name="value">
+               <double>0.400000000000000</double>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item row="1" column="0">
+           <widget class="QPushButton" name="pushButton_SetParam">
+            <property name="text">
+             <string>设置检测参数</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox_3">
+         <property name="title">
+          <string>Precision Setting</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_4">
+          <item row="0" column="0">
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <widget class="QCheckBox" name="checkBox_fp32">
+              <property name="text">
+               <string>fp32</string>
+              </property>
+              <property name="checked">
+               <bool>true</bool>
+              </property>
+              <property name="autoExclusive">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QCheckBox" name="checkBox_fp16">
+              <property name="text">
+               <string>fp16</string>
+              </property>
+              <property name="autoExclusive">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QCheckBox" name="checkBox_int8">
+              <property name="text">
+               <string>int8</string>
+              </property>
+              <property name="autoExclusive">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButton_StartDetec">
+         <property name="text">
+          <string>开启检测</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="pushButton_EndDetec">
+         <property name="text">
+          <string>关闭检测</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>960</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="mainToolBar">
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+   <addaction name="action_FindCamera"/>
+   <addaction name="action_OpenCamera"/>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+  <action name="action_FindCamera">
+   <property name="text">
+    <string>查找摄像头</string>
+   </property>
+  </action>
+  <action name="action_OpenCamera">
+   <property name="text">
+    <string>打开摄像头</string>
+   </property>
+  </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>

+ 78 - 0
src/detection/trafficlight_software/trafficlight_software.pro

@@ -0,0 +1,78 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2023-05-05T10:05:00
+#
+#-------------------------------------------------
+
+QT       += core gui multimedia
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = trafficlight
+TEMPLATE = app
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which has been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+CONFIG += debug_and_release
+CONFIG(debug,debug|release){
+    DEFINES += DEBUG
+}
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+
+SOURCES += \
+        main.cpp \
+        mainwindow.cpp \
+    grabframethread.cpp \
+    Hungarian.cpp \
+    KalmanTracker.cpp \
+    detect_obstacle.cpp \
+    calibrator.cpp
+
+HEADERS += \
+        mainwindow.h \
+    grabframethread.h \
+    Hungarian.h \
+    KalmanTracker.h \
+    detect_obstacle.h \
+    calibrator.h \
+    cuda_utils.h \
+    utils.h \
+    macros.h
+
+FORMS += \
+        mainwindow.ui
+
+
+INCLUDEPATH += /usr/src/tensorrt/include \
+               /usr/include/aarch64-linux-gnu \
+               /usr/include/opencv4 \
+               /usr/local/cuda/include \
+               /usr/src/tensorrt/samples/common \
+               /usr/local/include
+
+LIBS += /usr/local/cuda/lib64/libcudart.so \
+        /usr/lib/aarch64-linux-gnu/libnvparsers.so \
+        /usr/lib/aarch64-linux-gnu/libnvinfer.so \
+        /usr/lib/aarch64-linux-gnu/libnvonnxparser.so \
+        /usr/lib/aarch64-linux-gnu/libnvinfer_plugin.so
+
+LIBS += -L"/usr/local/lib" -lprotobuf
+LIBS += -L/usr/lib/aarch64-linux-gnu -lstdc++fs
+LIBS += -L/usr/lib/aarch64-linux-gnu/ -lglog
+
+unix:INCLUDEPATH += /opt/ros/kinetic/include/opencv-3.3.1-dev
+unix:INCLUDEPATH += /usr/include/opencv4
+unix:LIBS += -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -lopencv_video -lopencv_videoio -lopencv_dnn -lpthread  #-lopencv_shape
+
+win32:INCLUDEPATH += $$PWD/../thirdpartylib/opencv/include
+win32: LIBS += -L$$PWD/../thirdpartylib/opencv/lib -lopencv_imgproc451.dll -lopencv_highgui451.dll  -lopencv_imgcodecs451.dll -lopencv_video451.dll -lopencv_videoio451.dll   -lopencv_core451.dll
+win32: LIBS += -L$$PWD/../thirdpartylib/opencv/lib  -lopencv_core451.dll # -lzlib   #-llibwebp -llibpng  -llibjpeg-turbo -llibopenjp2 -llibtiff  -lIlmImf
+

+ 70 - 0
src/detection/trafficlight_software/utils.h

@@ -0,0 +1,70 @@
+#pragma once
+
+#include <dirent.h>
+#include <fstream>
+#include <unordered_map>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <cstring>
+
+static inline int read_files_in_dir(const char* p_dir_name, std::vector<std::string>& file_names) {
+    DIR *p_dir = opendir(p_dir_name);
+    if (p_dir == nullptr) {
+        return -1;
+    }
+
+    struct dirent* p_file = nullptr;
+    while ((p_file = readdir(p_dir)) != nullptr) {
+        if (strcmp(p_file->d_name, ".") != 0 &&
+            strcmp(p_file->d_name, "..") != 0) {
+            //std::string cur_file_name(p_dir_name);
+            //cur_file_name += "/";
+            //cur_file_name += p_file->d_name;
+            std::string cur_file_name(p_file->d_name);
+            file_names.push_back(cur_file_name);
+        }
+    }
+
+    closedir(p_dir);
+    return 0;
+}
+
+// Function to trim leading and trailing whitespace from a string
+static inline std::string trim_leading_whitespace(const std::string& str) {
+    size_t first = str.find_first_not_of(' ');
+    if (std::string::npos == first) {
+        return str;
+    }
+    size_t last = str.find_last_not_of(' ');
+    return str.substr(first, (last - first + 1));
+}
+
+// Src: https://stackoverflow.com/questions/16605967
+static inline std::string to_string_with_precision(const float a_value, const int n = 2) {
+    std::ostringstream out;
+    out.precision(n);
+    out << std::fixed << a_value;
+    return out.str();
+}
+
+static inline int read_labels(const std::string labels_filename, std::unordered_map<int, std::string>& labels_map) {
+
+    std::ifstream file(labels_filename);
+    // Read each line of the file
+    std::string line;
+    int index = 0;
+    while (std::getline(file, line)) {
+        // Strip the line of any leading or trailing whitespace
+        line = trim_leading_whitespace(line);
+
+        // Add the stripped line to the labels_map, using the loop index as the key
+        labels_map[index] = line;
+        index++;
+    }
+    // Close the file
+    file.close();
+
+    return 0;
+}
+