Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iteration2 #23

Merged
merged 4 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The latest (Phase 2) developed UML class and activity diagrams can be found in t

A short video providing a brief overview of the project and the details explaining the AIP process used is embedded below. A direct link to the same can also be found [here](https://www.youtube.com/watch?v=Eoj4YyOxvfU).

[![Video](https://i3.ytimg.com/vi/Eoj4YyOxvfU/maxresdefault.jpg)](https://www.youtube.com/watch?v=Eoj4YyOxvfU)
[![Video](https://i3.ytimg.com/vi/6D_xVzv4fGo/maxresdefault.jpg)](https://www.youtube.com/watch?v=6D_xVzv4fGo)

### Dependencies, Models, and Libraries
This project makes use of the OpenCV library (their official website can be found [here]()) for using computer vision functionalities and tools. HDAL also uses a YOLO v5 model (initially developed by Joseph Redmon, more information about which is linked [here](https://pjreddie.com/darknet/yolo/)). This deep-learning based object detection model helps HDAL detect humans from a continuous video feed from where further tracking is done. The YOLO v5 model is used by accessing its weights through a ONNX model that was generated from a PyTorch YOLO v5s model. This was done using [this](https://github.com/ultralytics/yolov5/releases) tutorial.
Expand Down Expand Up @@ -70,11 +70,20 @@ To generate and view the Doxygen documentation of the project, run the following
open docs/html/index.html
```

### Running the Program Executables
### Running the Program Executables (Project Demo Run)

To try a demo of HDAL on your system's webcam, execute the following commands. You should first know the input device `/dev/video0` in our case and measure the height of the camera. We will need this as command line arguments.
To run the demo code of the project (Running HDAL on any camera), the following command is to be executed.
``` bash
# Execute the 'app/main.cpp' file to see a demo run of HDAL on your system's webcam:
# Run a demo of HDAL on your computer system:
./build/app/HDAL_demo [camera_device] [camera_height]
```
In this command the two arguments provided are explained below.
- `camera_device` refers to to the name of the camera on your system. For most computer systems, `/dev/video0` refers to the system's built-in webcam. If you want to run HDAL from an external camera, you would need to check the name of the camera as assigned by your computer system and provide that as a single quotation marked string for this argument.
- `camera_height` refers to the height of the camera (in meters) from the ground. Since HDAL assumes the camera to be placed at a constant and fixed height from the ground throughout its running, it is important for this value to be accurate for HDAL to give precise and correct relative coordinates of each human obstacle in its field of view (FOV).

An example of a command to get HDAL running on your system using the built-in webcam (assuming a random camera height) would look like the one shown below.
``` bash
# An example demo run command to run HDAL on your system's webcam:
./build/app/HDAL_demo '/dev/video0' 0.762
```

Expand Down Expand Up @@ -113,7 +122,7 @@ This generates an `index.html` page in the `build/app_coverage` sub-directory th


### Google Coding Style Verification
To check how the written code conforms to the Google C++ style guide, look at the `results/cpplint_output.txt` file to see the output on using the *Cpplint* tool on this project. You should not be able to see any issues or problems, with all the files processed successfully.
To check how the written code conforms to the Google C++ style guide, look at the `results/cpplint_output.txt` and `results/cpplint_output.png` files to see the output on using the *Cpplint* tool on this project. You should not be able to see any issues or problems, with all the files processed successfully.

This can be self-verified as well by running the following command in the highest-level directory of the project.
```sh
Expand All @@ -127,14 +136,14 @@ On running the above command, you should see the same output in the `results/cpp


### Static Code Analysis
To check the static code analysis of this project, check the `results/cppcheck_output.txt` file to see the output on using the *Cppcheck* tool. You should not be able to see any issues or problems, with all the files checked successfully.
To check the static code analysis of this project, check the `results/cppcheck_output.txt` and `results/cppcheck_output.png` files to see the output on using the *Cppcheck* tool. You should not be able to see any issues or problems, with all the files checked successfully.

This can be self-verified as well by running the following command in the highest-level directory of the project.
```sh
# Install Cppcheck (ignore if already installed):
sudo apt install cppcheck
# Self-check the static code analysis using Cppcheck:
cppcheck --enable=all --std=c++11 --suppress=missingInclude $( find . -name *.cpp | grep -vE -e "^./build/" )
cppcheck --enable=all --std=c++11 --suppress=missingInclude --suppress=unusedFunction $( find . -name *.cpp | grep -vE -e "^./build/" )
```

On running the above command, you should see the same output in the `results/cppcheck_output.txt` file.
Expand All @@ -158,3 +167,8 @@ The quad chart for this project, `proposal/Phase 0 Quad Chart.pdf` describes the
Further, a short video providing a brief overview of the project and the details explained in the report and quad chart is embedded below. To access the video directly from a link, please click [here](https://www.youtube.com/watch?v=uGA3f2nemRw).

[![Video](https://i3.ytimg.com/vi/uGA3f2nemRw/maxresdefault.jpg)](https://www.youtube.com/watch?v=uGA3f2nemRw)

### References
- [YOLO v5 ONNX model source/tutorial](https://github.com/ultralytics/yolov5/releases)
- [YOLO v5 class names list](https://github.com/pjreddie/darknet/blob/master/data/coco.names)
- [Object Detector test image](https://docs.opencv.org/4.x/dc/dff/tutorial_py_pyramids.html)
141 changes: 73 additions & 68 deletions app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,96 @@
* @file main.cpp
* @author Vikram Setty (vikrams@umd.edu)
* @author Vinay Lanka (vlanka@umd.edu)
* @brief A demo run of HDAL running on a webcam. This file shows how the detector and tracker come together for running HDAL. This demo has been tested on a Lenovo FHD300 webcam attached externally to a computer system.
* @brief A demo run of HDAL running on a webcam. This file shows how the
* detector and tracker come together for running HDAL. This demo has been
* tested on a Lenovo FHD300 webcam attached externally to a computer system.
* @version 0.1
* @date 2023-10-29
*
*
* @copyright Copyright (c) 2023
*
*
*/
#include <iostream>
#include <fstream>
#include <iostream>
#include <string>

#include "detector_header.hpp"
#include "tracker_header.hpp"

// Parameters to initialise detector object
const char CLASSLIST_PATH[] = "./data/coco.names";
const char MODEL_PATH[] = "./model/yolov5s.onnx";
const float YOLO_IMG_WIDTH = 640.0;
const float YOLO_IMG_HEIGHT = 640.0;
const float CONFIDENCE_THRESHOLD = 0.45;
const float NMS_THRESHOLD = 0.45;
const float SCORE_THRESHOLD = 0.5;
const int YOLO_GRID_CELLS = 25200;

//Parameters to initialise detector object
const std::string CLASSLIST_PATH = "./data/coco.names" ;
const std::string MODEL_PATH = "./model/yolov5s.onnx" ;
const float YOLO_IMG_WIDTH = 640.0 ;
const float YOLO_IMG_HEIGHT = 640.0 ;
const float CONFIDENCE_THRESHOLD = 0.45 ;
const float NMS_THRESHOLD = 0.45 ;
const float SCORE_THRESHOLD = 0.5 ;
const int YOLO_GRID_CELLS = 25200 ;

//Parameters to initialise tracker object
// Parameters to initialise tracker object
float HEIGHT = 0.762;
const float FOCAL_LENGTH = 1.898;
const float HFOV = 100.11;
const float VFOV = 56.34;
const float PIXEL_SIZE = 0.0028;
const std::vector<int> RESOLUTION = {1280,720};

std::vector<int> RESOLUTION = {1280, 720};

/**
* @brief Creating 'Detector' and 'Tracker' objects and calling their functions and share information to run the demo.
*
* @return * int
* @brief Creating 'Detector' and 'Tracker' objects and calling their functions
* and share information to run the demo.
*
* @return * int
*/
int main(int argc, char* argv[]) {
//Use command line arguments to initialise camera and height
std::string capture_device = argv[1];
HEIGHT = std::stof(argv[2]);
//Initialise Detector
std::vector<std::string> yolo_classes;
std::ifstream read_input(CLASSLIST_PATH);
std::string text;
while (read_input >> text) {
getline(read_input, text);
yolo_classes.push_back(text) ;
}
cv::dnn::Net yolo_model = cv::dnn::readNet(MODEL_PATH) ;
Detector detector(yolo_model,YOLO_IMG_WIDTH,YOLO_IMG_HEIGHT,CONFIDENCE_THRESHOLD,NMS_THRESHOLD,SCORE_THRESHOLD,YOLO_GRID_CELLS,yolo_classes) ;
//Initialise Camera
cv::VideoCapture cap(capture_device);
cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
cap.set(cv::CAP_PROP_FRAME_HEIGHT,720);
if(!cap.isOpened()){
std::cout << "Error opening video stream or file" << std::endl;
return -1;
}
//Create tracker object
Tracker *human_tracker = new Tracker(HEIGHT, FOCAL_LENGTH, HFOV, VFOV, RESOLUTION, PIXEL_SIZE);
while(1){
cv::Mat frame;
cap >> frame;
// If the frame is empty, break immediately
if (frame.empty())
break;
int main(int argc, char* argv[]) {
// Use command line arguments to initialise camera and height
std::string capture_device = argv[1];
HEIGHT = std::stof(argv[2]);
// Initialise Detector
std::vector<std::string> yolo_classes;
std::ifstream read_input(CLASSLIST_PATH);
std::string text;
while (read_input >> text) {
getline(read_input, text);
yolo_classes.push_back(text);
}
cv::dnn::Net yolo_model = cv::dnn::readNet(MODEL_PATH);
Detector detector(yolo_model, YOLO_IMG_WIDTH, YOLO_IMG_HEIGHT,
CONFIDENCE_THRESHOLD, NMS_THRESHOLD, SCORE_THRESHOLD,
YOLO_GRID_CELLS, yolo_classes);
// Initialise Camera
cv::VideoCapture cap(capture_device);
cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
if (!cap.isOpened()) {
std::cout << "Error opening video stream or file" << std::endl;
return -1;
}
// Create tracker object
Tracker* human_tracker =
new Tracker(HEIGHT, FOCAL_LENGTH, HFOV, VFOV, RESOLUTION, PIXEL_SIZE);
while (1) {
cv::Mat frame;
cap >> frame;
// If the frame is empty, break immediately
if (frame.empty()) break;

DetectorOutput output = detector.detect_humans(frame) ;
//Detector method comes here to populate prediction pixels
std::vector<cv::Point> prediction_pixels = output.pixels;
//Calling tracker method for coordinates in camera frame
std::vector<std::vector<float>> coordinates = human_tracker->pixel_to_camera_frame(prediction_pixels);
//Plot coordinates on frame
cv::Mat final_frame = human_tracker->plot_coordinates(prediction_pixels, coordinates, output.boxed_img);
//Display the frame
cv::imshow("Frame", final_frame);
char c=(char)cv::waitKey(25);
if(c==27)
break;
}
// Close capture object
cap.release();
// Closes all the frames
cv::destroyAllWindows();
return 0;
DetectorOutput output = detector.detect_humans(frame);
// Detector method comes here to populate prediction pixels
std::vector<cv::Point> prediction_pixels = output.pixels;
// Calling tracker method for coordinates in camera frame
std::vector<std::vector<float>> coordinates =
human_tracker->pixel_to_camera_frame(prediction_pixels);
// Plot coordinates on frame
cv::Mat final_frame = human_tracker->plot_coordinates(
prediction_pixels, coordinates, output.boxed_img);
// Display the frame
cv::imshow("Frame", final_frame);
char c = static_cast<char>(cv::waitKey(25));
if (c == 27) break;
}
// Close capture object
cap.release();
// Closes all the frames
cv::destroyAllWindows();
return 0;
}
42 changes: 24 additions & 18 deletions libs/ObjectDetector/detector_header.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/**
* @file detector_header.hpp
* @author Vikram Setty (vikrams@umd.edu)
* @brief The header file for the human obstacle detector with all the instance member variables and functions.
* @brief The header file for the human obstacle detector with all the instance
* member variables and functions.
* @version 0.1
* @date 2023-10-29
*
*
* @copyright Copyright (c) 2023
*
*
*/
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
Expand All @@ -15,19 +16,20 @@
#pragma once

/**
* @brief A data structure for the Detector to return the exact information required by the Tracker.
*
* @brief A data structure for the Detector to return the exact information
* required by the Tracker.
*
*/
struct DetectorOutput{

std::vector<cv::Point> pixels ;
cv::Mat boxed_img ;

} ;
struct DetectorOutput {
std::vector<cv::Point> pixels;
cv::Mat boxed_img;
};

/**
* @brief The Detector class that takes a video frame and returns the image with bounding box drawn over it along with pixel information for the Tracker to use.
*
* @brief The Detector class that takes a video frame and returns the image with
* bounding box drawn over it along with pixel information for the Tracker to
* use.
*
*/
class Detector {
private:
Expand All @@ -38,16 +40,20 @@ class Detector {
const float nms_threshold;
const float score_threshold;
const int yolo_grid_cells;
cv::Mat img ;
cv::Mat boxed_img ;
std::vector<std::string> yolo_classes ;
cv::Mat img;
cv::Mat boxed_img;
const std::vector<std::string> yolo_classes;
cv::Mat preprocess_img();
void get_bounding_boxes(std::vector<cv::Rect> boxes, std::vector<float> confidence_values, std::vector<cv::Point> &box_pixels) ;
void get_bounding_boxes(std::vector<cv::Rect> boxes,
std::vector<float> confidence_values,
std::vector<cv::Point>& box_pixels);
DetectorOutput postprocess_img(std::vector<cv::Mat> yolo_outputs);

public:
Detector(cv::dnn::Net yolo_model, int yolo_img_width, int yolo_img_height,
float confidence_threshold, float nms_threshold, float score_threshold, int yolo_grid_cells,std::vector<std::string> yolo_classes);
float confidence_threshold, float nms_threshold,
float score_threshold, int yolo_grid_cells,
std::vector<std::string>& yolo_classes);
DetectorOutput detect_humans(cv::Mat video_frame);
~Detector();
};
Loading