mmdeploy的object_detection优化

mmdeploy编译后,bin目录下有c++编译的object_detection程序,用于目标检测和实例分割,该源码位于:

mmdeploy/demo/csrc/c/object_detection.cpp
#include <fstream>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <string>
#include <iostream>
#include <ctime>
#include "mmdeploy/detector.h"

std::string TrimEnd(const std::string& str) {
    size_t endpos = str.find_last_not_of(" \t\r\n");
    return (endpos != std::string::npos) ? str.substr(0, endpos + 1) : str;
}

// 在加载类别时使用TrimEnd()函数
std::vector<std::string> LoadCategories(const std::string& coco_class_file) {
    std::ifstream file(coco_class_file);
    std::vector<std::string> categories;
    if (file.is_open()) {
        std::string line;
        while (getline(file, line)) {
            categories.push_back(TrimEnd(line)); // 显式去除末尾空白和换行符
        }
        file.close();
    } else {
        std::cerr << "Error opening class file: " << coco_class_file << std::endl;
        exit(1);
    }
    return categories;
}

void SaveResultsToJson(const std::vector<std::vector<float>>& bboxes, 
                       const std::vector<int>& labels, 
                       const std::vector<float>& scores, 
                       const std::string& json_save_path) {
    std::ofstream json_file(json_save_path);
    if (json_file.is_open()) {
        json_file << "{\n";
        json_file << "  \"bboxes\": [\n";
        for (size_t i = 0; i < bboxes.size(); ++i) {
            json_file << "    [";
            for (size_t j = 0; j < bboxes[i].size(); ++j) {
                json_file << bboxes[i][j];
                if (j < bboxes[i].size() - 1) json_file << ", ";
            }
            json_file << "]";
            if (i < bboxes.size() - 1) json_file << ",";
            json_file << "\n";
        }
        json_file << "  ],\n";
        json_file << "  \"labels\": [\n    ";
        for (size_t i = 0; i < labels.size(); ++i) {
            json_file << labels[i];
            if (i < labels.size() - 1) json_file << ", ";
        }
        json_file << "\n  ],\n";
        json_file << "  \"scores\": [\n    ";
        for (size_t i = 0; i < scores.size(); ++i) {
            json_file << scores[i];
            if (i < scores.size() - 1) json_file << ", ";
        }
        json_file << "\n  ]\n";
        json_file << "}\n";
        json_file.close();
    } else {
        std::cerr << "Error opening JSON file for writing: " << json_save_path << std::endl;
    }
}
int main(int argc, char* argv[]) {
    if (argc != 8) {
        fprintf(stderr, "usage:\n  object_detection device_name model_path image_path save_path coco_txt_path score\n");
        return 1;
    }

    auto device_name = argv[1];
    auto model_path = argv[2];
    auto image_path = argv[3];
    auto save_path = argv[4];
    auto json_save_path = argv[5];
    auto coco_txt_path = argv[6];
    float score_threshold = std::stof(argv[7]);

    // 读取分类名称
    auto categories = LoadCategories(coco_txt_path);
    cv::Mat img = cv::imread(image_path);
    if (!img.data) {
        fprintf(stderr, "failed to load image: %s\n", image_path);
        return 1;
    }
    cv::Size img_size = img.size();
    mmdeploy_detector_t detector{};
    int status{};
    status = mmdeploy_detector_create_by_path(model_path, device_name, 0, &detector);
    if (status != MMDEPLOY_SUCCESS) {
        fprintf(stderr, "failed to create detector, code: %d\n", (int)status);
        return 1;
    }

    mmdeploy_mat_t mat{
        img.data, img.rows, img.cols, 3, MMDEPLOY_PIXEL_FORMAT_BGR, MMDEPLOY_DATA_TYPE_UINT8
    };

    mmdeploy_detection_t* bboxes{};
    int* res_count{};

    status = mmdeploy_detector_apply(detector, &mat, 1, &bboxes, &res_count);
    if (status != MMDEPLOY_SUCCESS) {
        fprintf(stderr, "failed to apply detector, code: %d\n", (int)status);
        return 1;
    }

    std::vector<std::vector<float>> json_bboxes;
    std::vector<int> json_labels;
    std::vector<float> json_scores;

    for (int i = 0; i < *res_count; ++i) {
        const auto& box = bboxes[i].bbox;
        const auto& mask = bboxes[i].mask;

        // 跳过无效的检测框(框的高度或宽度 < 1)
        if ((box.right - box.left) < 1 || (box.bottom - box.top) < 1) {
            continue;
        }

        // 跳过得分低于指定阈值的检测
        if (bboxes[i].score < score_threshold) {
            continue;
        }

        std::vector<float> bbox = {box.left, box.top, box.right, box.bottom};
        json_bboxes.push_back(bbox);
        json_labels.push_back(bboxes[i].label_id);
        json_scores.push_back(bboxes[i].score);
        
        // 生成遮罩叠加,如果模型导出遮罩
        if (mask != nullptr) {
          //fprintf(stdout, "mask %d, height=%d, width=%d\n", i, mask->height, mask->width);
          // 分离RGB通道,叠加遮罩到指定颜色通道
          cv::Mat ch[3], mask_img;
          int col = 0;  // int col = i % 3;
          split(img, ch);
          cv::Mat imgMask(mask->height, mask->width, CV_8UC1, &mask->data[0]);
          // rtmdet-inst
          if (img_size.height == mask->height && img_size.width == mask->width) {
            mask_img = ch[col];
          }
          else {
            auto x0 = std::max(std::floor(box.left) - 1, 0.f);
            auto y0 = std::max(std::floor(box.top) - 1, 0.f);
            cv::Rect roi((int)x0, (int)y0, mask->width, mask->height);
            mask_img = ch[col](roi);
          }
          cv::bitwise_or(imgMask, mask_img, mask_img);
          merge(ch, 3, img);
        }

        // 在图像上绘制矩形框
        cv::rectangle(img, cv::Point{(int)box.left, (int)box.top},
                      cv::Point{(int)box.right, (int)box.bottom}, cv::Scalar{0, 255, 0});

        // 在矩形框的右上角绘制分类名称
        std::string class_name = categories[bboxes[i].label_id];
        int baseLine;
        cv::Size labelSize = cv::getTextSize(class_name, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        int top = std::max((int)box.top, labelSize.height);
        cv::putText(img, class_name, cv::Point((int)box.left, top), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1);
    }

    cv::imwrite(save_path, img);

    // 将检测结果保存为JSON文件
    SaveResultsToJson(json_bboxes, json_labels, json_scores, json_save_path);

    mmdeploy_detector_release_result(bboxes, res_count, 1);
    mmdeploy_detector_destroy(detector);

    return 0;
}

调用方法:

./bin/object_detection cuda yolox_x ../mmdetection3/demo/demo.jpg demo.jpg 1.json coco.txt 0.5

其中coco.txt为coco数据集标签文件,内容如下:

person
bicycle
car
motorbike
aeroplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
sofa
pottedplant
bed
diningtable
toilet
tvmonitor
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush
motorcycle
potted plant
dining table
tv
couch
airplane

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个示例函数,它接受一个std::vector<full_object_detection>作为输入参数: ``` #include <vector> #include <opencv2/opencv.hpp> void process_detections(std::vector<full_object_detection> detections) { for (const auto& detection : detections) { // 在这里处理每个检测对象 } } ``` 这个函数遍历传入的检测对象vector,并在循环内部处理每个检测对象。 ### 回答2: 当输入参数是std::vector<full_object_detection>的函数可以使用以下C++代码实现: #include <iostream> #include <vector> struct full_object_detection { int x; int y; }; void process_full_object_detections(const std::vector<full_object_detection>& detections) { // 在这里对输入的std::vector<full_object_detection> 进行处理 // 可以使用detections.size()获取vector的大小,即元素数量 // 对于每个元素,可以使用detections[i].x和detections[i].y访问到坐标值 // 以下是一个简单的示例,只是简单打印元素的坐标值 for (int i = 0; i < detections.size(); i++) { std::cout << "Object " << i + 1 << " x: " << detections[i].x << ", y: " << detections[i].y << std::endl; } } int main() { // 创建一个std::vector<full_object_detection>对象作为函数参数 std::vector<full_object_detection> detections; full_object_detection detection1; detection1.x = 10; detection1.y = 20; detections.push_back(detection1); full_object_detection detection2; detection2.x = 30; detection2.y = 40; detections.push_back(detection2); // 调用函数并传递参数 process_full_object_detections(detections); return 0; } 此代码定义了一个结构体full_object_detection,包含了x和y坐标属性。然后定义了一个函数process_full_object_detections,该函数接受一个std::vector<full_object_detection>类型的参数detections,并对其进行处理。在main函数中,创建了一个std::vector<full_object_detection>对象detections,并为每个元素的x和y属性赋值。最后调用process_full_object_detections函数,并将detections传递给它。函数内部的示例代码仅仅是打印元素的坐标值,您可以根据实际需求对vector进行任何处理。 ### 回答3: 当您需要用C语言来编写函数来处理`std::vector<full_object_detection>`类型的输入参数时,需要保证您的代码是C语言兼容的。由于`std::vector`是C++标准库的一部分,而不是C语言标准库的一部分,因此在C语言中无法直接使用`std::vector`类型。但是您可以使用C语言中的数组和结构体来模拟实现类似的功能。 在C语言中,您可以使用结构体来表示`full_object_detection`类型,并使用动态分配的数组来模拟`std::vector`。下面是一个示例代码,以供参考: ```c #include <stdio.h> #include <stdlib.h> typedef struct { int x, y, width, height; } full_object_detection; void process_full_object_detections(full_object_detection* detections, int num_detections) { // 在这个函数中,您可以针对full_object_detection数组执行自己的操作 for (int i = 0; i < num_detections; i++) { full_object_detection detection = detections[i]; // 对每一个full_object_detection执行所需的操作,例如打印坐标 printf("Detection %d: x=%d, y=%d, width=%d, height=%d\n", i, detection.x, detection.y, detection.width, detection.height); } } int main() { // 创建并填充full_object_detection数组 full_object_detection* detections = (full_object_detection*)malloc(3 * sizeof(full_object_detection)); detections[0].x = 0; detections[0].y = 0; detections[0].width = 10; detections[0].height = 20; detections[1].x = 5; detections[1].y = 5; detections[1].width = 15; detections[1].height = 25; detections[2].x = 10; detections[2].y = 10; detections[2].width = 20; detections[2].height = 30; // 调用处理函数 process_full_object_detections(detections, 3); // 释放内存 free(detections); return 0; } ``` 在上述示例代码中,`process_full_object_detections`函数接受一个`full_object_detection`的指针,以及该数组的长度作为输入参数。您可以在该函数中执行您需要的操作,例如遍历数组并处理每个`full_object_detection`对象。 希望这个示例能对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值