前言

记得最开始尝试部署的时候直接进行了ai,拿着ai的代码就去跑,结果失败了,又去网上找了很久,都没有成功,直到看见了一篇gitee代码,拿上我就用,最后也是成功了。最离谱的是我换了一个模型(只是再训练了一次),不知道是不是中间哪里不一样,代码再次跑不通,痛定思痛决定还是搞懂为什么,最后再次跑通,发现跟之前b站学的理论对应上了,以此记录。

加载模型

这部分ai的还是对的,所以就不解释了。

cv::Mat CameraHandler::letterbox(const cv::Mat& source)
{
    int col = source.cols;
    int row = source.rows;
    int _max = MAX(col, row);
    cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC4);
    source.copyTo(result(cv::Rect(0, 0, col, row)));
    return result;
}
 ov::Core core;
    std::string modelPath=//路径
    // Step 3: 编译模型到特定的设备,例如 "CPU"
    ov::CompiledModel compiled_model = core.compile_model(modelPath, "CPU");
    // Step 4: 创建推理请求
    ov::InferRequest infer_request = compiled_model.create_infer_request();
    cv::Mat letterbox_img = letterbox(frame);
    float scale = letterbox_img.size[0] / 640.0;
    cv::Mat blob = cv::dnn::blobFromImage(letterbox_img, 1.0 / 255.0, cv::Size(640, 640), cv::Scalar(), true);
    // -------- Step 5. Feed the blob into the input node of the Model -------
    // Get input port for model with one input
    auto input_port = compiled_model.input();
    // Create tensor from external memory
    ov::Tensor input_tensor(input_port.get_element_type(), input_port.get_shape(), blob.ptr(0));
    // Set input tensor for model with one input
    infer_request.set_input_tensor(input_tensor);
    // -------- Step 6. Start inference --------
    infer_request.infer();
    // Step 10: 获取推理结果
    ov::Tensor output_tensor = infer_request.get_output_tensor(0);

最后拿到output_tensor就是模型得到的东西,这部分代码只要跑通不报错,基本就没什么问题。

std::vector<Trash> detections;
    //拿到内容
    float* output_data=output_tensor.data<float>();
    //形状
    ov::Shape output_shape=output_tensor.get_shape();//(1,9,8400)

    cv::Mat output_buffer(output_shape[1], output_shape[2], CV_32F, output_data);
    transpose(output_buffer, output_buffer); //[8400,9]
    //9是四个位置信息,五个类别
    std::vector<int> class_ids;
    std::vector<float> class_scores;
    std::vector<cv::Rect> boxes;
    // Figure out the bbox, class_id and class_score
    for (int i = 0; i < output_buffer.rows; i++) {
        cv::Mat classes_scores = output_buffer.row(i).colRange(4, 9);//取后5个数
        cv::Point class_id;
        double maxClassScore;
        minMaxLoc(classes_scores, 0, &maxClassScore, 0, &class_id);
        // std::cout<<maxClassScore<<std::endl;
        if (maxClassScore > confidence_threshold) {
            class_scores.push_back(maxClassScore);
            class_ids.push_back(class_id.x);
            float cx = output_buffer.at<float>(i, 0);
            float cy = output_buffer.at<float>(i, 1);
            float w = output_buffer.at<float>(i, 2);
            float h = output_buffer.at<float>(i, 3);

            int left = int((cx - 0.5 * w) * scale);
            int top = int((cy - 0.5 * h) * scale);
            int width = int(w * scale);
            int height = int(h * scale);

            boxes.push_back(cv::Rect(left, top, width, height));
        }
    }
    //非极大值抑制
    std::vector<int> indices;
    float nms_threshold = 0.8;
    cv::dnn::NMSBoxes(boxes, class_scores, confidence_threshold, nms_threshold, indices);

    // -------- Visualize the detection results -----------
    for (size_t i = 0; i < indices.size(); i++) {
        Trash detection;
        int index = indices[i];
        int class_id = class_ids[index];
        float confidence=class_scores[index];
        detection.class_id = static_cast<int>(class_id);
        detection.confidence = confidence;
        detection.x_min = boxes[index].x;
        detection.y_min = boxes[index].y;
        detection.x_max = boxes[index].x+boxes[index].width;
        detection.y_max = boxes[index].y+boxes[index].height;
        detections.push_back(detection);
    }

解析部分如上,最后将得到的detections就是我们需要的东西,由于我的代码是放在类的一个函数里面的,直接跑肯定是跑不通的。

解析

		std::vector<Trash> detections;
    //拿到内容
    float* output_data=output_tensor.data<float>();
    //形状
    ov::Shape output_shape=output_tensor.get_shape();//(1,9,8400)

    cv::Mat output_buffer(output_shape[1], output_shape[2], CV_32F, output_data);
    transpose(output_buffer, output_buffer); //[8400,9]

output_data是将模型输出的东西转变成float类型,output_shape是我模型的形状,得到的是(1,9,8400),1是batch数,我推理一张图片,所以肯定是1。9是推理的结果,前四个是位置信息,我的任务是5分类,所以后面5个数是对应每个类别的可能性。8400是识别的个数,这个是模型自己规定的,具体原因可以自行查找,网上有很多讲解。

将output_data放进output_buffer,并且将9和8400逆置。

//9是四个位置信息,五个类别
    std::vector<int> class_ids;
    std::vector<float> class_scores;
    std::vector<cv::Rect> boxes;
    // Figure out the bbox, class_id and class_score
    for (int i = 0; i < output_buffer.rows; i++) {
        cv::Mat classes_scores = output_buffer.row(i).colRange(4, 9);//取后5个数
        cv::Point class_id;
        double maxClassScore;
        minMaxLoc(classes_scores, 0, &maxClassScore, 0, &class_id);
        // std::cout<<maxClassScore<<std::endl;
        if (maxClassScore > confidence_threshold) {
            class_scores.push_back(maxClassScore);
            class_ids.push_back(class_id.x);
            float cx = output_buffer.at<float>(i, 0);
            float cy = output_buffer.at<float>(i, 1);
            float w = output_buffer.at<float>(i, 2);
            float h = output_buffer.at<float>(i, 3);

            int left = int((cx - 0.5 * w) * scale);
            int top = int((cy - 0.5 * h) * scale);
            int width = int(w * scale);
            int height = int(h * scale);

            boxes.push_back(cv::Rect(left, top, width, height));
        }
    }

for循环8400每个结果,classes_scores将每个类别对应的分数取出,minMaxLoc是对比每个类别的可能性得到可能性最大的,并且将对应的位置存进class_id里面。

判断最大可能性的值是否大于置信度(自己规定的),大于就是我们需要的结果,将置信度和类别以及位置分别存入数组。

 //非极大值抑制
    std::vector<int> indices;
    float nms_threshold = 0.8;
    cv::dnn::NMSBoxes(boxes, class_scores, confidence_threshold, nms_threshold, indices);

再采用非极大值抑制,如果两个框交叉的UOI大于你规定的nms_threshold,那么就会抑制掉置信度小的。

// -------- Visualize the detection results -----------
    for (size_t i = 0; i < indices.size(); i++) {
        Trash detection;
        int index = indices[i];
        int class_id = class_ids[index];
        float confidence=class_scores[index];
        detection.class_id = static_cast<int>(class_id);
        detection.confidence = confidence;
        detection.x_min = boxes[index].x;
        detection.y_min = boxes[index].y;
        detection.x_max = boxes[index].x+boxes[index].width;
        detection.y_max = boxes[index].y+boxes[index].height;
        detections.push_back(detection);
    }

将最后的结果存入detections里面。

总结

部署代码倒是挺多,就是c++版本的比较少,能力有限,有误麻烦指出,谢谢。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐