Jetson Xavier NX パドル推論

注 ---------------------- このブログでは主にコードについて話します ---------------

1. 基本的な準備

1. 既存の環境:

サードパーティのライブラリ

------ YAML-CPP

------ パドル推論

ジェットソン 

----ジェットパック 4.6

自己訓練されたモデル

モデル、パラメータ、yml ファイル

2. CMake_Lists (理解できない場合は、私の他のブログを参照してください)

入り口

cmakeは使い方が簡単です

cmake_minimum_required(VERSION 3.10.2) #camke版本
 
project(paddle_test)  #设置项目名字
 
find_package(OpenCV)   #CMake自带了FindOpenCV.cmake文件,通过调用find_package命令来搜索OpenCV库

include_directories(OpenCV_INCLUDE_DIRS)#将OpenCV库的头文件路径添加到编译选项中
 
include_directories(/home/hty/C++_PACK/paddle_inference)#将paddle的头文件路径添加到编译选项中

include_directories(/home/hty/C++_PACK/yaml-cpp/include)

set(PADDLE_LIBRARIES /home/hty/C++_PACK/paddle_inference/paddle/lib/libpaddle_inference.so)
 
set(YAML_LIBRARIES /home/hty/C++_PACK/yaml-cpp/build/libyaml-cpp.so)

message(${OpenCV_INCLUDE_DIRS}) #输出OpenCV库的头文件路径 可删
 
message(${OpenCV_LIBRARIES}) #输出OpenCV库的链接路径和库名称  可删
 
add_definitions("-Wall -std=c++11")  #添加C++编译选项
 
add_executable(paddle_test paddle_test.cpp)  #可执行文件名字 编译文件
 
 
target_link_libraries(paddle_test ${OpenCV_LIBRARIES}) #将OpenCV库链接到可执行文件中
 
target_link_libraries(paddle_test ${PADDLE_LIBRARIES}) #将paddle库链接到可执行文件中

target_link_libraries(paddle_test ${YAML_LIBRARIES})

2. コード部分(後日掲載)

1.ymlデータの読み込み(ラベルタグの読み込み)

YAML::Node yaml_reader = YAML::LoadFile("../SSD.yml");
    float threshold = 0.5f;   //阈值
    //读取yaml中的标签
    std::vector<std::string> label_list = yaml_reader["label_list"].as<std::vector<std::string>>();
    //获取标准化参数
    std::vector<float> means = {0.485,0.456,0.406};
    std::vector<float> stds  = {0.229,0.224,0.225};
    std::cout << "label_list is ------";
    for (const auto& label : label_list) {  //const auto& 只读label的值  遍历label
        std::cout << label << " ";
    }

2. モデルファイルの構成と予測 Config の初期化

    //配置模型参数
    std::string model_file = "../SSD_model";  //模型文件
    std::string params_file = "../SSD_pa";    //参数文件
    paddle_infer::Config config;
    config.SetModel(model_file, params_file); // 加载模型文件
    config.EnableUseGpu(1000, 0);  //使用gpu
    config.SwitchIrOptim(true);    //IR加速
    config.EnableMemoryOptim();   //内存优化  显存内存复用
    config.SetOptimCacheDir("../trt_cache");    // 设置缓存路径
    config.EnableTensorRtEngine(1 << 30, 1, 3, paddle_infer::PrecisionType::kHalf, true, false);  //TensorRT调用  采用float16 
    std::shared_ptr<paddle_infer::Predictor> predictor = paddle_infer::CreatePredictor(config);  //创建Predictor

3. 入出力データの設定

    //输入设置 300*300
    int im_size = 300;
    cv::Mat im_shape = cv::Mat(1, 2, CV_32FC1);
    im_shape.at<float>(0, 0) = im_size;
    im_shape.at<float>(0, 1) = im_size;
    std::vector<int> input_shape = {1, 3, im_size, im_size};  //1*3*300*300


    struct DATA{  //定义数据
        float id;
        float score;
        float x_min;
        float y_min;
        float x_max;
        float y_max;
    }data;

4. 画像の前処理 

入力 Mat をベクトルに変換すると、形状が hwc から chw、BGR から RGB に変わります。

/*  图片预处理
img:   图片
img_size:图片大小 
mean: 输入均值
std:  输入标准差
return chw储存方式的vector
*/
std::vector<float> preprocess(cv::Mat img, cv::Size img_size,std::vector<float> mean,std::vector<float> std){
    cv::Mat result;

    //放缩到目标大小
    cv::resize(img, result, img_size);
    cv::cvtColor(result, result, cv::COLOR_BGR2RGB); //BGR to RGB
    result.convertTo(result, CV_32FC3, 1.0 / 255.0);  //转为float32类型 并且归一化

    //标准化
    for (int c = 0; c < 3; ++c) {  //遍历所有像素 三个通道 进行标准化
        result.forEach<cv::Vec3f>(    //使用opencv中forEach对像素进行函数操作   cv::Vec3f定义为float32
            [&](cv::Vec3f &pixel, const int *position) -> void { //[&]lambal表达式引用捕获,直接访问外部mean,std变量  
                pixel[c] -= mean[c];  
                pixel[c] /= std[c];
            }
        );
    }

    //将图像转为vector类型,并且从hwc转为chw
	std::vector<cv::Mat> mv;
	cv::split(result, mv);  //分离三通道
	std::vector<float> R = mv[0].reshape(1, 1);
	std::vector<float> G = mv[1].reshape(1, 1);
	std::vector<float> B = mv[2].reshape(1, 1);
	//RGB数据合并
	std::vector<float> input_data;
	input_data.insert(input_data.end(), R.begin(), R.end());
	input_data.insert(input_data.end(), G.begin(), G.end());
	input_data.insert(input_data.end(), B.begin(), B.end());

    return input_data;
}

5. 予報

/*  预测
input_data:输入预处理后的vector数据
input_shape:输入的图片大小 格式为NCHW
predictor  :初始化好的predictor
return : 预测的输出
*/
std::vector<float> predict(std::vector<float> input_data,std::vector<int> input_shape,std::shared_ptr<paddle_infer::Predictor> predictor){
        // 准备输入 Tensor
        auto input_names = predictor->GetInputNames();
        auto input_tensor = predictor->GetInputHandle(input_names[0]);
        input_tensor->Reshape(input_shape);
        input_tensor->CopyFromCpu(input_data.data());  //复制一份图片,拷贝数据输入

        //运行  
        predictor->Run();  

        //输出
        auto output_names = predictor->GetOutputNames();//获取输出名字
        auto output_tensor = predictor->GetOutputHandle(output_names[0]);//获取输出句柄
        std::vector<int> output_shape = output_tensor->shape();
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 
                              1, std::multiplies<int>());
        std::vector<float> out_datas; 
        out_datas.resize(out_num);
        output_tensor->CopyToCpu(out_datas.data()); //将输出拷贝到out_data

        return out_datas;
}

完全なコード

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <chrono>
#include <numeric>
#include <cmath>
#include "paddle/include/paddle_inference_api.h"
#include <opencv2/opencv.hpp>
#include <yaml-cpp/yaml.h>

/*  图片预处理
img:   图片
img_size:图片大小 
mean: 输入均值
std:  输入标准差
return chw储存方式的vector
*/
std::vector<float> preprocess(cv::Mat img, cv::Size img_size,std::vector<float> mean,std::vector<float> std){
    cv::Mat result;

    //放缩到目标大小
    cv::resize(img, result, img_size);
    cv::cvtColor(result, result, cv::COLOR_BGR2RGB); //BGR to RGB
    result.convertTo(result, CV_32FC3, 1.0 / 255.0);  //转为float32类型 并且归一化

    //标准化
    for (int c = 0; c < 3; ++c) {  //遍历所有像素 三个通道 进行标准化
        result.forEach<cv::Vec3f>(    //使用opencv中forEach对像素进行函数操作   cv::Vec3f定义为float32
            [&](cv::Vec3f &pixel, const int *position) -> void { //[&]lambal表达式引用捕获,直接访问外部mean,std变量  
                pixel[c] -= mean[c];  
                pixel[c] /= std[c];
            }
        );
    }

    //将图像转为vector类型,并且从hwc转为chw
	std::vector<cv::Mat> mv;
	cv::split(result, mv);  //分离三通道
	std::vector<float> R = mv[0].reshape(1, 1);
	std::vector<float> G = mv[1].reshape(1, 1);
	std::vector<float> B = mv[2].reshape(1, 1);
	//RGB数据合并
	std::vector<float> input_data;
	input_data.insert(input_data.end(), R.begin(), R.end());
	input_data.insert(input_data.end(), G.begin(), G.end());
	input_data.insert(input_data.end(), B.begin(), B.end());

    return input_data;
}

/*  预测
input_data:输入预处理后的vector数据
input_shape:输入的图片大小 格式为NCHW
predictor  :初始化好的predictor
return : 预测的输出
*/
std::vector<float> predict(std::vector<float> input_data,std::vector<int> input_shape,std::shared_ptr<paddle_infer::Predictor> predictor){
        // 准备输入 Tensor
        auto input_names = predictor->GetInputNames();
        auto input_tensor = predictor->GetInputHandle(input_names[0]);
        input_tensor->Reshape(input_shape);
        input_tensor->CopyFromCpu(input_data.data());  //复制一份图片,拷贝数据输入

        //运行  
        predictor->Run();  

        //输出
        auto output_names = predictor->GetOutputNames();//获取输出名字
        auto output_tensor = predictor->GetOutputHandle(output_names[0]);//获取输出句柄
        std::vector<int> output_shape = output_tensor->shape();
        int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 
                              1, std::multiplies<int>());
        std::vector<float> out_datas; 
        out_datas.resize(out_num);
        output_tensor->CopyToCpu(out_datas.data()); //将输出拷贝到out_data

        return out_datas;
}

int main(void)
{
    YAML::Node yaml_reader = YAML::LoadFile("../SSD.yml");
    float threshold = 0.5f;   //阈值
    //读取yaml中的标签
    std::vector<std::string> label_list = yaml_reader["label_list"].as<std::vector<std::string>>();
    //获取标准化参数
    std::vector<float> means = {0.485,0.456,0.406};
    std::vector<float> stds  = {0.229,0.224,0.225};
    std::cout << "label_list is ------";
    for (const auto& label : label_list) {  //const auto& 只读label的值  遍历label
        std::cout << label << " ";
    }
    
    //配置模型参数
    std::string model_file = "../SSD_model";  //模型文件
    std::string params_file = "../SSD_pa";    //参数文件
    paddle_infer::Config config;
    config.SetModel(model_file, params_file); // 加载模型文件
    config.EnableUseGpu(1000, 0);  //使用gpu
    config.SwitchIrOptim(true);    //IR加速
    config.EnableMemoryOptim();   //内存优化  显存内存复用
    config.SetOptimCacheDir("../trt_cache");    // 设置缓存路径
    config.EnableTensorRtEngine(1 << 30, 1, 3, paddle_infer::PrecisionType::kHalf, true, false);  //TensorRT调用  采用float16 
    std::shared_ptr<paddle_infer::Predictor> predictor = paddle_infer::CreatePredictor(config);  //创建Predictor

    //输入设置 300*300
    int im_size = 300;
    cv::Mat im_shape = cv::Mat(1, 2, CV_32FC1);
    im_shape.at<float>(0, 0) = im_size;
    im_shape.at<float>(0, 1) = im_size;
    std::vector<int> input_shape = {1, 3, im_size, im_size};  //1*3*300*300


    struct DATA{  //定义数据
        float id;
        float score;
        float x_min;
        float y_min;
        float x_max;
        float y_max;
    }data;

    //配置摄像头
    cv::VideoCapture cap(0);
    if (!cap.isOpened()){
        std::cout << "error to open capture" << std::endl;
        return -1;
    }

    while (true){
        auto start_time = std::chrono::high_resolution_clock::now();
        cv::Mat frame;
        bool ret = cap.read(frame);
        if (!ret)
        {
            break;
        }

        //图像预处理
        std::vector<float> input_data = preprocess(frame,cv::Size(im_size,im_size),means,stds); 

        //预测
        std::vector<float> out_datas = predict(input_data,input_shape,predictor);

        // 后处理
        int out_data_len = out_datas.size()/6;
        std::cout<<"----------------data_start---------------------------"<<std::endl;
        for(int i =0;i<out_data_len;i++){    //遍历所有数据
                
                float temp_score = out_datas[6*i+1];
                if(temp_score>threshold){    //准确度大于threshold
                    //获取位置等数据
                    data.id    = out_datas[6*i];          
                    data.score = out_datas[6*i+1];      
                    data.x_min = out_datas[6*i+2]*frame.rows;
                    data.y_min = out_datas[6*i+3]*frame.cols;
                    data.x_max = out_datas[6*i+4]*frame.rows;
                    data.y_max = out_datas[6*i+5]*frame.cols;
                    std::string label_id = label_list[(int)data.id-1];

                    std::stringstream string_ss;
                    string_ss << data.score;
                    std::string string_score = string_ss.str();
                    std::cout<<"label is  "<<label_id<<"  score is  "<<string_score<<std::endl;
                    //画图
                    cv::rectangle(frame, cv::Point((int)data.x_min, (int)data.y_min),
                                            cv::Point((int)data.x_max, (int)data.y_max), cv::Scalar(255, 0, 255), 2);
                    cv::putText(frame, label_id, cv::Point((int)data.x_min, (int)data.y_min - 2), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 0, 0), 2);
                    cv::putText(frame, string_score, cv::Point((int)data.x_min - 35, (int)data.y_min - 2), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2);
                }
        }

        //图片显示
        //cv::imshow("img",frame);
        cv::waitKey(1);

        // 计算帧率
        auto end_time = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
        double frame_time = duration.count() / 1000000.0; // 将微秒转换为秒
        double fps = 1.0f/frame_time;
        std::cout<<"FPS is -----  "<<fps<<std::endl;
        std::cout<<"----------------data_end---------------------------"<<std::endl;
    }

    
    return 0;
}

おすすめ

転載: blog.csdn.net/A15768533126/article/details/130447726