diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index a5c4dce..f95b4a7 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(example) +add_subdirectory(yolov8-cls-inference) \ No newline at end of file diff --git a/app/yolov8-cls-inference/CMakeLists.txt b/app/yolov8-cls-inference/CMakeLists.txt new file mode 100644 index 0000000..22a50bd --- /dev/null +++ b/app/yolov8-cls-inference/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.5) + +project(yolov8-cls-inference) + +find_package(OpenCV REQUIRED) + +set(PROJECT_SOURCE_FILES + main.cpp +) + +add_executable(${CMAKE_PROJECT_NAME} ${PROJECT_SOURCE_FILES}) +target_link_libraries(${CMAKE_PROJECT_NAME} ${OpenCV_LIBS}) +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS}) \ No newline at end of file diff --git a/app/yolov8-cls-inference/README.md b/app/yolov8-cls-inference/README.md new file mode 100644 index 0000000..4a184c6 --- /dev/null +++ b/app/yolov8-cls-inference/README.md @@ -0,0 +1,29 @@ + +## YOLOv8-cls inference + +1. OpenCV installation + + [Get started with OpenCV](https://opencv.org/get-started/) + +2. Ultralytics installation + + Create and activate python venv + ``` + python -m venv + source /bin/activate + ``` + Install ultralytics using pip + ``` + pip install ultralytics + ``` + +3. Export YOLOv8-cls model + ``` + python export.py + ``` + +4. Run the project + ``` + make -C build + build/yolov8-cls-inference + ``` diff --git a/app/yolov8-cls-inference/export.py b/app/yolov8-cls-inference/export.py new file mode 100644 index 0000000..38b3cc3 --- /dev/null +++ b/app/yolov8-cls-inference/export.py @@ -0,0 +1,13 @@ + +from ultralytics import YOLO + +# load the YOLOv8-cls model +model = YOLO("yolov8n-cls.pt") + +# export the classification list +with open('classification_list.txt', 'w') as file: + for name in model.names.values(): + file.write(name + '\n') + +# export the model to ONNX format +model.export(format="onnx", imgsz=224) diff --git a/app/yolov8-cls-inference/main.cpp b/app/yolov8-cls-inference/main.cpp new file mode 100644 index 0000000..852131f --- /dev/null +++ b/app/yolov8-cls-inference/main.cpp @@ -0,0 +1,68 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) { + if (argc < 4) { + std::cerr << "[fatal error] Not all required parameters are specified\n"; + return 1; + } + + // read an input image + cv::Mat raw_image = cv::imread(argv[3]); + if (raw_image.empty()) { + std::cerr << "[fatal error] Failed to read the input image\n"; + return 1; + } + + // read the classification list + std::ifstream file(argv[2]); + + if (!file.is_open()) { + std::cerr << "[fatal error] Failed to open the classification list file\n"; + return 1; + } + + std::string line; + std::vector class_list; + while (std::getline(file, line)) { + class_list.push_back(line); + } + + // read the network model + cv::dnn::Net net = cv::dnn::readNetFromONNX(argv[1]); + if (net.empty()) { + std::cerr << "[fatal error] Failed to read the network model\n"; + return 1; + } + + // prepare the image for inference + cv::Mat input_image; + cv::resize(raw_image, input_image, cv::Size(224, 224), cv::INTER_LINEAR); + cv::Mat blob = cv::dnn::blobFromImage(input_image, 1.0 / 255.0, + cv::Size(224, 224), cv::Scalar()); + + // inference + net.setInput(blob); + cv::Mat output = net.forward("output0"); + + // extract a result from the output + double max_class_score = 0.0; + cv::Point max_loc; + cv::minMaxLoc(output, nullptr, &max_class_score, nullptr, &max_loc); + + // print the results + std::cout << "class ID: " << max_loc.x << '\n'; + std::cout << "class name: " << class_list[max_loc.x] << '\n'; + std::cout << "confidence: " << max_class_score << '\n'; + + return 0; +}