目錄
環(huán)境配置
系統(tǒng)環(huán)境
項目文件路徑?
文件環(huán)境
?config.txt
?CMakeLists.txt
type.names
?讀取config.txt配置文件
修改圖片尺寸格式
讀取缺陷標志文件
生成缺陷隨機顏色標識
模型推理
推理結(jié)果獲取
缺陷信息還原并顯示
總代碼
環(huán)境配置
系統(tǒng)環(huán)境
Ubuntu18.04
onnxruntime-linux-x64 1.12.1:https://github.com/microsoft/onnxruntime/releases
opencv 3.4.3
cmake?3.10.2
項目文件路徑?
1.? bin:存放可執(zhí)行程序和識別結(jié)果
2.? data:存放數(shù)據(jù)集
3.? src:存放源程序
4.? include:存放頭文件
5.? config.txt:配置文件,內(nèi)容分別是模型相對路徑、圖片相對路徑、缺陷標識文件相對路徑、缺陷識別閾值、缺陷重疊閾值
6.? type.names:缺陷標識文件,內(nèi)容和模型識別的缺陷標識順序需要一致
文件環(huán)境
?config.txt
分別表示模型相對路徑、圖片相對路徑、缺陷標識文件相對路徑、缺陷識別閾值、缺陷重疊閾值
../models/best.onnx
../data/2.bmp
../type.names
0.4
0.4
?CMakeLists.txt
需要更改的地方已經(jīng)在里面標注好了
# 項目名稱,隨便寫
PROJECT(image_onnx)
# cmake版本,根據(jù)自己的寫
cmake_minimum_required(VERSION 3.10)
# 編譯好的可執(zhí)行文件放置的位置
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${image_onnx_SOURCE_DIR}/bin)
# find required opencv
find_package(OpenCV REQUIRED)
# directory of opencv headers
include_directories(${OpenCV_INCLUDE_DIRS})
# 根據(jù)自己的onnxruntime存放路徑編寫
set(ONNXRUNTIME_ROOT_PATH /home/ebaina/onnxruntime-linux-x64-1.12.1/)
set(ONNXRUNTIME_INCLUDE_DIRS ${ONNXRUNTIME_ROOT_PATH}/include/)
set(ONNXRUNTIME_LIB ${ONNXRUNTIME_ROOT_PATH}lib/libonnxruntime.so)
# 需要編譯的cpp文件所在路徑,前面是編譯好的可執(zhí)行文件名
add_executable(image_onnx src/main_image.cpp
src/change_image.cpp
src/adjust_result.cpp)
# directory of opencv library
link_directories(${OpenCV_LIBRARY_DIRS})
# opencv libraries
target_link_libraries(image_onnx ${OpenCV_LIBS})
include_directories(${ONNXRUNTIME_INCLUDE_DIRS})
target_link_libraries(image_onnx ${ONNXRUNTIME_LIB})
# include
target_include_directories(image_onnx
PRIVATE
${PROJECT_SOURCE_DIR}/include
)
type.names
缺陷標志文件,內(nèi)容和模型識別的缺陷標識順序需要一致,模型識別網(wǎng)站:Netron
文章來源:http://www.zghlxwxcb.cn/news/detail-796807.html
burr
cbreakage
inbreakage
bpulp
corrode文章來源地址http://www.zghlxwxcb.cn/news/detail-796807.html
?讀取config.txt配置文件
// 自動讀取模型路徑,圖片路徑,缺陷閾值,重疊閾值
std::string model_path_;
std::string imgPath;
std::string namesPath;
float threshold;
float nms_threshold;
// 打開配置文件并讀取配置
std::ifstream configFile("../config.txt");
if (configFile.is_open()) {
configFile >> model_path_ >> imgPath >> namesPath >> threshold >> nms_threshold;
configFile.close();
std::cout << "Model Path: " << model_path_ << std::endl;
std::cout << "Image Path: " << imgPath << std::endl;
std::cout << "Names Path: " << namesPath << std::endl;
std::cout << "Threshold: " << threshold << std::endl;
std::cout << "NMS Threshold: " << nms_threshold << std::endl;
} else
std::cerr << "Failed to open config file." << std::endl;
const char* model_path = model_path_.c_str();
修改圖片尺寸格式
// 圖片變換
cv::Mat inputImage = cv::imread(imgPath);
if (inputImage.empty()) {
std::cerr << "Failed to load image." << std::endl;
return 1;
}
// 獲取圖片尺寸
int y = inputImage.rows;
int x = inputImage.cols;
// 圖片尺寸變換
cv::Mat image0 = resizeImage(inputImage, y, x);
// 圖像歸一化
std::vector<float> input_image_ = nchwImage(image0);
讀取缺陷標志文件
// 讀取缺陷標志文件
std::ifstream inputFile(namesPath);
if (!inputFile.is_open()) {
std::cerr << "Failed to open the file." << std::endl;
return 1;
}
std::vector<std::string> typeNames;
std::string line;
while (std::getline(inputFile, line))
typeNames.push_back(line);
inputFile.close();
生成缺陷隨機顏色標識
// 缺陷顏色標識隨機
int numColors = typeNames.size();
std::vector<std::vector<int>> colors;
for (int i = 0; i < numColors; ++i)
colors.push_back(generateRandomColor());
// // 打印顏色種類
// for (const auto &color : colors)
// std::cout << "R: " << color[0] << ", G: " << color[1] << ", B: " << color[2] << std::endl;
模型推理
// 模型設(shè)置和推理結(jié)果
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "Default");
// CPU
Ort::Session session_{env, model_path, Ort::SessionOptions{nullptr}};
// 模型輸入尺寸
static constexpr const int height_ = 640; //model input height
static constexpr const int width_ = 640; //model input width
Ort::Value input_tensor_{nullptr};
std::array<int64_t, 4> input_shape_{1, 3, height_, width_}; //mode input shape NCHW = 1x3xHxW
// 模型輸出尺寸
Ort::Value output_tensor_{nullptr};
std::array<int64_t, 3> output_shape_{1, 9, 8400}; //model output shape,
std::array<_Float32, 9*8400> results_{};
// 模型輸入輸出張量設(shè)置
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault);
input_tensor_ = Ort::Value::CreateTensor<float>(memory_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size());
output_tensor_ = Ort::Value::CreateTensor<float>(memory_info, results_.data(), results_.size(), output_shape_.data(), output_shape_.size());
// 查看模型輸入輸出的名稱
const char* input_names[] = {"images"};
const char* output_names[] = {"output0"};
// 推理
session_.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor_, 1, output_names, &output_tensor_, 1);
float* out = output_tensor_.GetTensorMutableData<float>();
推理結(jié)果獲取
// 推理結(jié)果獲取
int rows = 9; // 第二維度大小,即行數(shù)
int cols = 8400; // 第三維度大小,即列數(shù)
std::vector<std::vector<float>> matrix(rows, std::vector<float>(cols));
for (int row = 0; row < rows; ++row)
for (int col = 0; col < cols; ++col)
matrix[row][col] = out[row * cols + col];
// 9,8400數(shù)組轉(zhuǎn)置為8400,9
std::vector<std::vector<float>> tran_matrix = transpose(matrix);
// // 顯示缺陷篩選結(jié)果
// std::vector<std::vector<float>> num = tran_matrix;
// for (size_t n = 0; n < num.size(); ++n) {
// bool aboveThreshold = false;
// for (size_t col = 4; col <= 8; ++col)
// if (num[n][col] > threshold) {
// aboveThreshold = true;
// break;
// }
// if (aboveThreshold) {
// std::cout << "Row " << n << ": ";
// for (const auto& val : num[n])
// std::cout << val << " ";
// std::cout << std::endl;
// }
// }
缺陷信息還原并顯示
// 缺陷還原
std::vector<std::vector<double>> select_matrix;
select_matrix = select(tran_matrix, threshold, cols,rows);
// 缺陷位置信息還原
select_matrix = return_(select_matrix, y, x);
// 缺陷位置信息篩選
select_matrix = nms_(select_matrix, nms_threshold);
// // 打印數(shù)組的內(nèi)容
// for (const auto& row : select_matrix){
// for (const auto& value : row) {
// std::cout << value << " ";
// }
// std::cout << std::endl;
// }
// 繪制識別框
cv::Mat outputImage = draw_image(select_matrix, inputImage, typeNames, colors);
// 自定義窗口大小
int windowWidth = 1200;
int windowHeight = 900;
// 調(diào)整窗口大小
cv::namedWindow("Image with Bounding Boxes", cv::WINDOW_NORMAL);
cv::resizeWindow("Image with Bounding Boxes", windowWidth, windowHeight);
cv::imshow("Image with Bounding Boxes", outputImage);
cv::imwrite("marked_image.jpg", outputImage);
cv::waitKey(0);
main代碼(關(guān)注取源碼!)
#include <assert.h>
#include <random>
#include <onnxruntime_cxx_api.h>
#include "cpu_provider_factory.h"
#include <adjust_result.h>
// 隨機生成顏色
std::vector<int> generateRandomColor() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0, 1.0);
std::vector<int> color(3);
for (int i = 0; i < 3; ++i) {
color[i] = static_cast<int>(dis(gen) * 255);
}
return color;
}
int main(int argc, char* argv[]) {
// // 模型路徑,圖片路徑,缺陷閾值,重疊閾值
// const char* model_path = "../models/best.onnx";
// std::string imgPath = "../data/3.bmp";
// std::string namesPath = "../type.names";
// float threshold = 0.4;
// float nms_threshold = 0.4;
// 自動讀取模型路徑,圖片路徑,缺陷閾值,重疊閾值
std::string model_path_;
std::string imgPath;
std::string namesPath;
float threshold;
float nms_threshold;
// 打開配置文件并讀取配置
std::ifstream configFile("../config.txt");
if (configFile.is_open()) {
configFile >> model_path_ >> imgPath >> namesPath >> threshold >> nms_threshold;
configFile.close();
std::cout << "Model Path: " << model_path_ << std::endl;
std::cout << "Image Path: " << imgPath << std::endl;
std::cout << "Names Path: " << namesPath << std::endl;
std::cout << "Threshold: " << threshold << std::endl;
std::cout << "NMS Threshold: " << nms_threshold << std::endl;
} else
std::cerr << "Failed to open config file." << std::endl;
const char* model_path = model_path_.c_str();
// 圖片變換
cv::Mat inputImage = cv::imread(imgPath);
if (inputImage.empty()) {
std::cerr << "Failed to load image." << std::endl;
return 1;
}
// 獲取圖片尺寸
int y = inputImage.rows;
int x = inputImage.cols;
// 圖片尺寸變換
cv::Mat image0 = resizeImage(inputImage, y, x);
// 圖像歸一化
std::vector<float> input_image_ = nchwImage(image0);
// 讀取缺陷標志文件
std::ifstream inputFile(namesPath);
if (!inputFile.is_open()) {
std::cerr << "Failed to open the file." << std::endl;
return 1;
}
std::vector<std::string> typeNames;
std::string line;
while (std::getline(inputFile, line))
typeNames.push_back(line);
inputFile.close();
// // 打印缺陷標志文件內(nèi)容
// std::cout << "Number of elements: " << typeNames.size() << std::endl;
// for (const std::string &typeName : typeNames)
// std::cout << typeName << std::endl;
// 缺陷顏色標識隨機
int numColors = typeNames.size();
std::vector<std::vector<int>> colors;
for (int i = 0; i < numColors; ++i)
colors.push_back(generateRandomColor());
// // 打印顏色種類
// for (const auto &color : colors)
// std::cout << "R: " << color[0] << ", G: " << color[1] << ", B: " << color[2] << std::endl;
// 模型設(shè)置和推理結(jié)果
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "Default");
// CPU
Ort::Session session_{env, model_path, Ort::SessionOptions{nullptr}};
// 模型輸入尺寸
static constexpr const int height_ = 640; //model input height
static constexpr const int width_ = 640; //model input width
Ort::Value input_tensor_{nullptr};
std::array<int64_t, 4> input_shape_{1, 3, height_, width_}; //mode input shape NCHW = 1x3xHxW
// 模型輸出尺寸
Ort::Value output_tensor_{nullptr};
std::array<int64_t, 3> output_shape_{1, 9, 8400}; //model output shape,
std::array<_Float32, 9*8400> results_{};
// 模型輸入輸出張量設(shè)置
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault);
input_tensor_ = Ort::Value::CreateTensor<float>(memory_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size());
output_tensor_ = Ort::Value::CreateTensor<float>(memory_info, results_.data(), results_.size(), output_shape_.data(), output_shape_.size());
// 查看模型輸入輸出的名稱
const char* input_names[] = {"images"};
const char* output_names[] = {"output0"};
// 推理
session_.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor_, 1, output_names, &output_tensor_, 1);
float* out = output_tensor_.GetTensorMutableData<float>();
// 推理結(jié)果獲取
int rows = 9; // 第二維度大小,即行數(shù)
int cols = 8400; // 第三維度大小,即列數(shù)
std::vector<std::vector<float>> matrix(rows, std::vector<float>(cols));
for (int row = 0; row < rows; ++row)
for (int col = 0; col < cols; ++col)
matrix[row][col] = out[row * cols + col];
// 9,8400數(shù)組轉(zhuǎn)置為8400,9
std::vector<std::vector<float>> tran_matrix = transpose(matrix);
// // 顯示缺陷篩選結(jié)果
// std::vector<std::vector<float>> num = tran_matrix;
// for (size_t n = 0; n < num.size(); ++n) {
// bool aboveThreshold = false;
// for (size_t col = 4; col <= 8; ++col)
// if (num[n][col] > threshold) {
// aboveThreshold = true;
// break;
// }
// if (aboveThreshold) {
// std::cout << "Row " << n << ": ";
// for (const auto& val : num[n])
// std::cout << val << " ";
// std::cout << std::endl;
// }
// }
// 缺陷還原
std::vector<std::vector<double>> select_matrix;
select_matrix = select(tran_matrix, threshold, cols,rows);
// 缺陷位置信息還原
select_matrix = return_(select_matrix, y, x);
// 缺陷位置信息篩選
select_matrix = nms_(select_matrix, nms_threshold);
// // 打印數(shù)組的內(nèi)容
// for (const auto& row : select_matrix){
// for (const auto& value : row) {
// std::cout << value << " ";
// }
// std::cout << std::endl;
// }
// 繪制識別框
cv::Mat outputImage = draw_image(select_matrix, inputImage, typeNames, colors);
// 自定義窗口大小
int windowWidth = 1200;
int windowHeight = 900;
// 調(diào)整窗口大小
cv::namedWindow("Image with Bounding Boxes", cv::WINDOW_NORMAL);
cv::resizeWindow("Image with Bounding Boxes", windowWidth, windowHeight);
cv::imshow("Image with Bounding Boxes", outputImage);
cv::imwrite("marked_image.jpg", outputImage);
cv::waitKey(0);
return 0;
}
到了這里,關(guān)于Ubuntu環(huán)境下C++使用onnxruntime和Opencv進行YOLOv8模型部署的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!