Commit 546b4279 authored by limm's avatar limm
Browse files

add csrc and mmdeploy module

parent 502f4fb9
Pipeline #2810 canceled with stages
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/pose_tracker.h"
#include "mmdeploy/archive/json_archive.h"
#include "mmdeploy/archive/value_archive.h"
#include "mmdeploy/codebase/mmpose/pose_tracker/common.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/mpl/structure.h"
#include "mmdeploy/pipeline.h"
namespace mmdeploy {
using namespace framework;
} // namespace mmdeploy
using namespace mmdeploy;
namespace {
Value config_template() {
static const auto json = R"(
{
"type": "Pipeline",
"input": ["img", "force_det", "state"],
"output": "targets",
"tasks": [
{
"type": "Task",
"name": "prepare",
"module": "pose_tracker::Prepare",
"input": ["img", "force_det", "state"],
"output": "use_det"
},
{
"type": "Task",
"module": "Transform",
"name": "preload",
"input": "img",
"output": "data",
"transforms": [ { "type": "LoadImageFromFile" } ]
},
{
"type": "Cond",
"name": "cond",
"input": ["use_det", "data"],
"output": "dets",
"body": {
"name": "detection",
"type": "Inference",
"params": { "model": "detection" }
}
},
{
"type": "Task",
"name": "process_bboxes",
"module": "pose_tracker::ProcessBboxes",
"input": ["dets", "data", "state"],
"output": ["rois", "track_ids"]
},
{
"input": "*rois",
"output": "*keypoints",
"name": "pose",
"type": "Inference",
"params": { "model": "pose" }
},
{
"type": "Task",
"name": "track_step",
"module": "pose_tracker::TrackStep",
"scheduler": "pool",
"input": ["keypoints", "track_ids", "state"],
"output": "targets"
}
]
}
)"_json;
static const auto config = from_json<Value>(json);
return config;
}
} // namespace
int mmdeploy_pose_tracker_default_params(mmdeploy_pose_tracker_param_t* params) {
mmpose::_pose_tracker::SetDefaultParams(*params);
return 0;
}
int mmdeploy_pose_tracker_create(mmdeploy_model_t det_model, mmdeploy_model_t pose_model,
mmdeploy_context_t context, mmdeploy_pose_tracker_t* pipeline) {
mmdeploy_context_add(context, MMDEPLOY_TYPE_MODEL, "detection", det_model);
mmdeploy_context_add(context, MMDEPLOY_TYPE_MODEL, "pose", pose_model);
auto config = config_template();
return mmdeploy_pipeline_create_v3(Cast(&config), context, (mmdeploy_pipeline_t*)pipeline);
}
void mmdeploy_pose_tracker_destroy(mmdeploy_pose_tracker_t pipeline) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)pipeline);
}
int mmdeploy_pose_tracker_create_state(mmdeploy_pose_tracker_t pipeline,
const mmdeploy_pose_tracker_param_t* params,
mmdeploy_pose_tracker_state_t* state) {
try {
auto create_fn = gRegistry<Module>().Create("pose_tracker::Create", Value()).value();
*state = reinterpret_cast<mmdeploy_pose_tracker_state_t>(new Value(
create_fn->Process({const_cast<mmdeploy_pose_tracker_param_t*>(params)}).value()[0]));
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
void mmdeploy_pose_tracker_destroy_state(mmdeploy_pose_tracker_state_t state) {
delete reinterpret_cast<Value*>(state);
}
int mmdeploy_pose_tracker_create_input(mmdeploy_pose_tracker_state_t* states,
const mmdeploy_mat_t* frames, const int32_t* use_detect,
int batch_size, mmdeploy_value_t* value) {
try {
Value::Array images;
Value::Array use_dets;
Value::Array trackers;
for (int i = 0; i < batch_size; ++i) {
images.push_back({{"ori_img", Cast(frames[i])}});
use_dets.emplace_back(use_detect ? use_detect[i] : -1);
trackers.push_back(*reinterpret_cast<Value*>(states[i]));
}
*value = Take(Value{std::move(images), std::move(use_dets), std::move(trackers)});
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
using ResultType = mmdeploy::Structure<mmdeploy_pose_tracker_target_t, std::vector<int32_t>,
std::vector<mmpose::_pose_tracker::TrackerResult>>;
int mmdeploy_pose_tracker_get_result(mmdeploy_value_t output,
mmdeploy_pose_tracker_target_t** results,
int32_t** result_count) {
if (!output || !results) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
// convert result from Values
std::vector<mmpose::_pose_tracker::TrackerResult> res;
from_value(Cast(output)->front(), res);
size_t total = 0;
for (const auto& r : res) {
total += r.bboxes.size();
}
// preserve space for the output structure
ResultType result_type({total, 1, 1});
auto [result_data, result_cnt, result_holder] = result_type.pointers();
auto result_ptr = result_data;
result_holder->swap(res);
// build output structure
for (auto& r : *result_holder) {
for (int j = 0; j < r.bboxes.size(); ++j) {
auto& p = *result_ptr++;
p.keypoint_count = static_cast<int32_t>(r.keypoints[j].size());
p.keypoints = r.keypoints[j].data();
p.scores = r.scores[j].data();
p.bbox = r.bboxes[j];
p.target_id = r.track_ids[j];
}
result_cnt->push_back(r.bboxes.size());
// debug info
// p.reserved0 = new std::vector(r.pose_input_bboxes);
// p.reserved1 = new std::vector(r.pose_output_bboxes);
}
*results = result_data;
*result_count = result_cnt->data();
result_type.release();
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
int mmdeploy_pose_tracker_apply(mmdeploy_pose_tracker_t pipeline,
mmdeploy_pose_tracker_state_t* states, const mmdeploy_mat_t* frames,
const int32_t* use_detect, int32_t count,
mmdeploy_pose_tracker_target_t** results, int32_t** result_count) {
wrapped<mmdeploy_value_t> input;
if (auto ec =
mmdeploy_pose_tracker_create_input(states, frames, use_detect, count, input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_pipeline_apply((mmdeploy_pipeline_t)pipeline, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_pose_tracker_get_result(output, results, result_count)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
void mmdeploy_pose_tracker_release_result(mmdeploy_pose_tracker_target_t* results,
const int32_t* result_count, int count) {
auto total = std::accumulate(result_count, result_count + count, 0);
ResultType deleter({static_cast<size_t>(total), 1, 1}, results);
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file pose_tracker.h
* @brief Pose tracker C API
*/
#ifndef MMDEPLOY_POSE_TRACKER_H
#define MMDEPLOY_POSE_TRACKER_H
#include "mmdeploy/common.h"
#include "mmdeploy/detector.h"
#include "mmdeploy/model.h"
#include "mmdeploy/pose_detector.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_pose_tracker* mmdeploy_pose_tracker_t;
typedef struct mmdeploy_pose_tracker_state* mmdeploy_pose_tracker_state_t;
typedef struct mmdeploy_pose_tracker_param_t {
// detection interval, default = 1
int32_t det_interval;
// detection label use for pose estimation, default = 0
int32_t det_label;
// detection score threshold, default = 0.5
float det_thr;
// detection minimum bbox size (compute as sqrt(area)), default = -1
float det_min_bbox_size;
// nms iou threshold for merging detected bboxes and bboxes from tracked targets, default = 0.7
float det_nms_thr;
// max number of bboxes used for pose estimation per frame, default = -1
int32_t pose_max_num_bboxes;
// threshold for visible key-points, default = 0.5
float pose_kpt_thr;
// min number of key-points for valid poses (-1 indicates ceil(n_kpts/2)), default = -1
int32_t pose_min_keypoints;
// scale for expanding key-points to bbox, default = 1.25
float pose_bbox_scale;
// min pose bbox size, tracks with bbox size smaller than the threshold will be dropped,
// default = -1
float pose_min_bbox_size;
// nms oks/iou threshold for suppressing overlapped poses, useful when multiple pose estimations
// collapse to the same target, default = 0.5
float pose_nms_thr;
// keypoint sigmas for computing OKS, will use IOU if not set, default = nullptr
float* keypoint_sigmas;
// size of keypoint sigma array, must be consistent with the number of key-points, default = 0
int32_t keypoint_sigmas_size;
// iou threshold for associating missing tracks, default = 0.4
float track_iou_thr;
// max number of missing frames before a missing tracks is removed, default = 10
int32_t track_max_missing;
// track history size, default = 1
int32_t track_history_size;
// weight of position for setting covariance matrices of kalman filters, default = 0.05
float std_weight_position;
// weight of velocity for setting covariance matrices of kalman filters, default = 0.00625
float std_weight_velocity;
// params for the one-euro filter for smoothing the outputs - (beta, fc_min, fc_derivative)
// default = (0.007, 1, 1)
float smooth_params[3];
} mmdeploy_pose_tracker_param_t;
typedef struct mmdeploy_pose_tracker_target_t {
mmdeploy_point_t* keypoints; // key-points of the target
int32_t keypoint_count; // size of `keypoints` array
float* scores; // scores of each key-point
mmdeploy_rect_t bbox; // estimated bbox from key-points
uint32_t target_id; // target id from internal tracker
} mmdeploy_pose_tracker_target_t;
/**
* @brief Fill params with default parameters
* @param[in,out] params
* @return status of the operation
*/
MMDEPLOY_API int mmdeploy_pose_tracker_default_params(mmdeploy_pose_tracker_param_t* params);
/**
* @brief Create pose tracker pipeline
* @param[in] det_model detection model object, created by \ref mmdeploy_model_create
* @param[in] pose_model pose model object
* @param[in] context context object describing execution environment (device, profiler, etc...),
* created by \ref mmdeploy_context_create
* @param[out] pipeline handle of the created pipeline
* @return status of the operation
*/
MMDEPLOY_API int mmdeploy_pose_tracker_create(mmdeploy_model_t det_model,
mmdeploy_model_t pose_model,
mmdeploy_context_t context,
mmdeploy_pose_tracker_t* pipeline);
/**
* @brief Destroy pose tracker pipeline
* @param[in] pipeline
*/
MMDEPLOY_API void mmdeploy_pose_tracker_destroy(mmdeploy_pose_tracker_t pipeline);
/**
* @brief Create a tracker state handle corresponds to a video stream
* @param[in] pipeline handle of a pose tracker pipeline
* @param[in] params params for creating the tracker state
* @param[out] state handle of the created tracker state
* @return status of the operation
*/
MMDEPLOY_API int mmdeploy_pose_tracker_create_state(mmdeploy_pose_tracker_t pipeline,
const mmdeploy_pose_tracker_param_t* params,
mmdeploy_pose_tracker_state_t* state);
/**
* @brief Destroy tracker state
* @param[in] state handle of the tracker state
*/
MMDEPLOY_API void mmdeploy_pose_tracker_destroy_state(mmdeploy_pose_tracker_state_t state);
/**
* @brief Apply pose tracker pipeline, notice that this function supports batch operation by feeding
* arrays of size \p count to \p states, \p frames and \p use_detect
* @param[in] pipeline handle of a pose tracker pipeline
* @param[in] states tracker states handles, array of size \p count
* @param[in] frames input frames of size \p count
* @param[in] use_detect control the use of detector, array of size \p count
* -1: use params.det_interval, 0: don't use detector, 1: force use detector
* @param[in] count batch size
* @param[out] results a linear buffer contains the tracked targets of input frames. Should be
* released by \ref mmdeploy_pose_tracker_release_result
* @param[out] result_count a linear buffer of size \p count contains the number of tracked
* targets of the frames. Should be released by \ref mmdeploy_pose_tracker_release_result
* @return status of the operation
*/
MMDEPLOY_API int mmdeploy_pose_tracker_apply(mmdeploy_pose_tracker_t pipeline,
mmdeploy_pose_tracker_state_t* states,
const mmdeploy_mat_t* frames,
const int32_t* use_detect, int32_t count,
mmdeploy_pose_tracker_target_t** results,
int32_t** result_count);
/**
* @brief Release result objects
* @param[in] results
* @param[in] result_count
* @param[in] count
*/
MMDEPLOY_API void mmdeploy_pose_tracker_release_result(mmdeploy_pose_tracker_target_t* results,
const int32_t* result_count, int count);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_POSE_TRACKER_H
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/restorer.h"
#include "mmdeploy/codebase/mmedit/mmedit.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/device.h"
#include "mmdeploy/core/graph.h"
#include "mmdeploy/core/mpl/structure.h"
#include "mmdeploy/core/utils/formatter.h"
#include "mmdeploy/executor_internal.h"
#include "mmdeploy/handle.h"
#include "mmdeploy/pipeline.h"
using namespace mmdeploy;
using ResultType = mmdeploy::Structure<mmdeploy_mat_t, mmdeploy::framework::Buffer>;
int mmdeploy_restorer_create(mmdeploy_model_t model, const char* device_name, int device_id,
mmdeploy_restorer_t* restorer) {
mmdeploy_context_t context{};
auto ec = mmdeploy_context_create_by_device(device_name, device_id, &context);
if (ec != MMDEPLOY_SUCCESS) {
return ec;
}
ec = mmdeploy_restorer_create_v2(model, context, restorer);
mmdeploy_context_destroy(context);
return ec;
}
int mmdeploy_restorer_create_by_path(const char* model_path, const char* device_name, int device_id,
mmdeploy_restorer_t* restorer) {
mmdeploy_model_t model{};
if (auto ec = mmdeploy_model_create_by_path(model_path, &model)) {
return ec;
}
auto ec = mmdeploy_restorer_create(model, device_name, device_id, restorer);
mmdeploy_model_destroy(model);
return ec;
}
int mmdeploy_restorer_apply(mmdeploy_restorer_t restorer, const mmdeploy_mat_t* images, int count,
mmdeploy_mat_t** results) {
wrapped<mmdeploy_value_t> input;
if (auto ec = mmdeploy_restorer_create_input(images, count, input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_restorer_apply_v2(restorer, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_restorer_get_result(output, results)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
void mmdeploy_restorer_release_result(mmdeploy_mat_t* results, int count) {
ResultType deleter{static_cast<size_t>(count), results};
}
void mmdeploy_restorer_destroy(mmdeploy_restorer_t restorer) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)restorer);
}
int mmdeploy_restorer_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_restorer_t* restorer) {
return mmdeploy_pipeline_create_from_model(model, context, (mmdeploy_pipeline_t*)restorer);
}
int mmdeploy_restorer_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* value) {
return mmdeploy_common_create_input(mats, mat_count, value);
}
int mmdeploy_restorer_apply_v2(mmdeploy_restorer_t restorer, mmdeploy_value_t input,
mmdeploy_value_t* output) {
return mmdeploy_pipeline_apply((mmdeploy_pipeline_t)restorer, input, output);
}
int mmdeploy_restorer_apply_async(mmdeploy_restorer_t restorer, mmdeploy_sender_t input,
mmdeploy_sender_t* output) {
return mmdeploy_pipeline_apply_async((mmdeploy_pipeline_t)restorer, input, output);
}
int mmdeploy_restorer_get_result(mmdeploy_value_t output, mmdeploy_mat_t** results) {
if (!output || !results) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
const Value& value = Cast(output)->front();
auto restorer_output = from_value<std::vector<mmedit::RestorerOutput>>(value);
auto count = restorer_output.size();
ResultType r(count);
auto [_results, buffers] = r.pointers();
for (int i = 0; i < count; ++i) {
auto upscale = restorer_output[i];
auto& res = _results[i];
res.data = upscale.data<uint8_t>();
buffers[i] = upscale.buffer();
res.format = (mmdeploy_pixel_format_t)upscale.pixel_format();
res.height = upscale.height();
res.width = upscale.width();
res.channel = upscale.channel();
res.type = (mmdeploy_data_type_t)upscale.type();
}
*results = _results;
r.release();
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file restorer.h
* @brief Interface to MMEditing image restoration task
*/
#ifndef MMDEPLOY_SRC_APIS_C_RESTORER_H_
#define MMDEPLOY_SRC_APIS_C_RESTORER_H_
#include "mmdeploy/common.h"
#include "mmdeploy/executor.h"
#include "mmdeploy/model.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_restorer* mmdeploy_restorer_t;
/**
* @brief Create a restorer instance
* @param[in] model an instance of image restoration model created by
* \ref mmdeploy_model_create_by_path or \ref mmdeploy_model_create in \ref model.h
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] restorer handle of the created restorer, which must be destroyed
* by \ref mmdeploy_restorer_destroy
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_restorer_create(mmdeploy_model_t model, const char* device_name,
int device_id, mmdeploy_restorer_t* restorer);
/**
* @brief Create a restorer instance
* @param[in] model_path path to image restoration model
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] restorer handle of the created restorer, which must be destroyed
* by \ref mmdeploy_restorer_destroy
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_restorer_create_by_path(const char* model_path, const char* device_name,
int device_id, mmdeploy_restorer_t* restorer);
/**
* @brief Apply restorer to a batch of images
* @param[in] restorer restorer's handle created by \ref mmdeploy_restorer_create_by_path
* @param[in] images a batch of images
* @param[in] count number of images in the batch
* @param[out] results a linear buffer contains the restored images, must be release
* by \ref mmdeploy_restorer_release_result
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_restorer_apply(mmdeploy_restorer_t restorer, const mmdeploy_mat_t* images,
int count, mmdeploy_mat_t** results);
/** @brief Release result buffer returned by \ref mmdeploy_restorer_apply
* @param[in] results result buffer by restorer
* @param[in] count length of \p result
*/
MMDEPLOY_API void mmdeploy_restorer_release_result(mmdeploy_mat_t* results, int count);
/**
* @brief destroy restorer
* @param[in] restorer handle of restorer created by \ref mmdeploy_restorer_create_by_path
*/
MMDEPLOY_API void mmdeploy_restorer_destroy(mmdeploy_restorer_t restorer);
/******************************************************************************
* Experimental asynchronous APIs */
MMDEPLOY_API int mmdeploy_restorer_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_restorer_t* restorer);
MMDEPLOY_API int mmdeploy_restorer_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* value);
MMDEPLOY_API int mmdeploy_restorer_apply_v2(mmdeploy_restorer_t restorer, mmdeploy_value_t input,
mmdeploy_value_t* output);
MMDEPLOY_API int mmdeploy_restorer_apply_async(mmdeploy_restorer_t restorer,
mmdeploy_sender_t input, mmdeploy_sender_t* output);
MMDEPLOY_API int mmdeploy_restorer_get_result(mmdeploy_value_t output, mmdeploy_mat_t** results);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_SRC_APIS_C_RESTORER_H_
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/rotated_detector.h"
#include <numeric>
#include "mmdeploy/codebase/mmrotate/mmrotate.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/graph.h"
#include "mmdeploy/core/mat.h"
#include "mmdeploy/core/utils/formatter.h"
#include "mmdeploy/handle.h"
#include "mmdeploy/pipeline.h"
using namespace std;
using namespace mmdeploy;
int mmdeploy_rotated_detector_create(mmdeploy_model_t model, const char* device_name, int device_id,
mmdeploy_rotated_detector_t* detector) {
mmdeploy_context_t context{};
auto ec = mmdeploy_context_create_by_device(device_name, device_id, &context);
if (ec != MMDEPLOY_SUCCESS) {
return ec;
}
ec = mmdeploy_rotated_detector_create_v2(model, context, detector);
mmdeploy_context_destroy(context);
return ec;
}
int mmdeploy_rotated_detector_create_by_path(const char* model_path, const char* device_name,
int device_id, mmdeploy_rotated_detector_t* detector) {
mmdeploy_model_t model{};
if (auto ec = mmdeploy_model_create_by_path(model_path, &model)) {
return ec;
}
auto ec = mmdeploy_rotated_detector_create(model, device_name, device_id, detector);
mmdeploy_model_destroy(model);
return ec;
}
int mmdeploy_rotated_detector_apply(mmdeploy_rotated_detector_t detector,
const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_rotated_detection_t** results, int** result_count) {
wrapped<mmdeploy_value_t> input;
if (auto ec = mmdeploy_rotated_detector_create_input(mats, mat_count, input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_rotated_detector_apply_v2(detector, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_rotated_detector_get_result(output, results, result_count)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
void mmdeploy_rotated_detector_release_result(mmdeploy_rotated_detection_t* results,
const int* result_count) {
delete[] results;
delete[] result_count;
}
void mmdeploy_rotated_detector_destroy(mmdeploy_rotated_detector_t detector) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)detector);
}
int mmdeploy_rotated_detector_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_rotated_detector_t* detector) {
return mmdeploy_pipeline_create_from_model(model, context, (mmdeploy_pipeline_t*)detector);
}
int mmdeploy_rotated_detector_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* input) {
return mmdeploy_common_create_input(mats, mat_count, input);
}
int mmdeploy_rotated_detector_apply_v2(mmdeploy_rotated_detector_t detector, mmdeploy_value_t input,
mmdeploy_value_t* output) {
return mmdeploy_pipeline_apply((mmdeploy_pipeline_t)detector, input, output);
}
int mmdeploy_rotated_detector_apply_async(mmdeploy_rotated_detector_t detector,
mmdeploy_sender_t input, mmdeploy_sender_t* output) {
return mmdeploy_pipeline_apply_async((mmdeploy_pipeline_t)detector, input, output);
}
int mmdeploy_rotated_detector_get_result(mmdeploy_value_t output,
mmdeploy_rotated_detection_t** results,
int** result_count) {
if (!output || !results || !result_count) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
Value& value = Cast(output)->front();
auto detector_outputs = from_value<vector<mmrotate::RotatedDetectorOutput>>(value);
vector<int> _result_count;
_result_count.reserve(detector_outputs.size());
for (const auto& det_output : detector_outputs) {
_result_count.push_back((int)det_output.detections.size());
}
auto total = std::accumulate(_result_count.begin(), _result_count.end(), 0);
std::unique_ptr<int[]> result_count_data(new int[_result_count.size()]{});
std::copy(_result_count.begin(), _result_count.end(), result_count_data.get());
std::unique_ptr<mmdeploy_rotated_detection_t[]> result_data(
new mmdeploy_rotated_detection_t[total]{});
auto result_ptr = result_data.get();
for (const auto& det_output : detector_outputs) {
for (const auto& detection : det_output.detections) {
result_ptr->label_id = detection.label_id;
result_ptr->score = detection.score;
const auto& rbbox = detection.rbbox;
for (int i = 0; i < 5; i++) {
result_ptr->rbbox[i] = rbbox[i];
}
++result_ptr;
}
}
*result_count = result_count_data.release();
*results = result_data.release();
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file rotated_detector.h
* @brief Interface to MMRotate task
*/
#ifndef MMDEPLOY_SRC_APIS_C_ROTATED_DETECTOR_H_
#define MMDEPLOY_SRC_APIS_C_ROTATED_DETECTOR_H_
#include "mmdeploy/common.h"
#include "mmdeploy/executor.h"
#include "mmdeploy/model.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_rotated_detection_t {
int label_id;
float score;
float rbbox[5]; // cx, cy, w, h, angle
} mmdeploy_rotated_detection_t;
typedef struct mmdeploy_rotated_detector* mmdeploy_rotated_detector_t;
/**
* @brief Create rotated detector's handle
* @param[in] model an instance of mmrotate sdk model created by
* \ref mmdeploy_model_create_by_path or \ref mmdeploy_model_create in \ref model.h
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] detector instance of a rotated detector
* @return status of creating rotated detector's handle
*/
MMDEPLOY_API int mmdeploy_rotated_detector_create(mmdeploy_model_t model, const char* device_name,
int device_id,
mmdeploy_rotated_detector_t* detector);
/**
* @brief Create rotated detector's handle
* @param[in] model_path path of mmrotate sdk model exported by mmdeploy model converter
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] detector instance of a rotated detector
* @return status of creating rotated detector's handle
*/
MMDEPLOY_API int mmdeploy_rotated_detector_create_by_path(const char* model_path,
const char* device_name, int device_id,
mmdeploy_rotated_detector_t* detector);
/**
* @brief Apply rotated detector to batch images and get their inference results
* @param[in] detector rotated detector's handle created by \ref
* mmdeploy_rotated_detector_create_by_path
* @param[in] mats a batch of images
* @param[in] mat_count number of images in the batch
* @param[out] results a linear buffer to save detection results of each image. It must be released
* by \ref mmdeploy_rotated_detector_release_result
* @param[out] result_count a linear buffer with length being \p mat_count to save the number of
* detection results of each image. And it must be released by \ref
* mmdeploy_rotated_detector_release_result
* @return status of inference
*/
MMDEPLOY_API int mmdeploy_rotated_detector_apply(mmdeploy_rotated_detector_t detector,
const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_rotated_detection_t** results,
int** result_count);
/** @brief Release the inference result buffer created by \ref mmdeploy_rotated_detector_apply
* @param[in] results rotated detection results buffer
* @param[in] result_count \p results size buffer
*/
MMDEPLOY_API void mmdeploy_rotated_detector_release_result(mmdeploy_rotated_detection_t* results,
const int* result_count);
/**
* @brief Destroy rotated detector's handle
* @param[in] detector rotated detector's handle created by \ref
* mmdeploy_rotated_detector_create_by_path or by \ref mmdeploy_rotated_detector_create
*/
MMDEPLOY_API void mmdeploy_rotated_detector_destroy(mmdeploy_rotated_detector_t detector);
/******************************************************************************
* Experimental asynchronous APIs */
/**
* @brief Same as \ref mmdeploy_detector_create, but allows to control execution context of tasks
* via context
*/
MMDEPLOY_API int mmdeploy_rotated_detector_create_v2(mmdeploy_model_t model,
mmdeploy_context_t context,
mmdeploy_rotated_detector_t* detector);
/**
* @brief Pack rotated detector inputs into mmdeploy_value_t
* @param[in] mats a batch of images
* @param[in] mat_count number of images in the batch
* @return the created value
*/
MMDEPLOY_API int mmdeploy_rotated_detector_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* input);
/**
* @brief Same as \ref mmdeploy_rotated_detector_apply, but input and output are packed in \ref
* mmdeploy_value_t.
*/
MMDEPLOY_API int mmdeploy_rotated_detector_apply_v2(mmdeploy_rotated_detector_t detector,
mmdeploy_value_t input,
mmdeploy_value_t* output);
/**
* @brief Apply rotated detector asynchronously
* @param[in] detector handle to the detector
* @param[in] input input sender
* @return output sender
*/
MMDEPLOY_API int mmdeploy_rotated_detector_apply_async(mmdeploy_rotated_detector_t detector,
mmdeploy_sender_t input,
mmdeploy_sender_t* output);
/**
* @brief Unpack rotated detector output from a mmdeploy_value_t
* @param[in] output output obtained by applying a detector
* @param[out] results a linear buffer to save detection results of each image. It must be released
* by \ref mmdeploy_detector_release_result
* @param[out] result_count a linear buffer with length number of input images to save the number of
* detection results of each image. Must be released by \ref
* mmdeploy_detector_release_result
* @return status of the operation
*/
MMDEPLOY_API int mmdeploy_rotated_detector_get_result(mmdeploy_value_t output,
mmdeploy_rotated_detection_t** results,
int** result_count);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_SRC_APIS_C_ROTATED_DETECTOR_H_
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/segmentor.h"
#include "mmdeploy/codebase/mmseg/mmseg.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/device.h"
#include "mmdeploy/core/graph.h"
#include "mmdeploy/core/mat.h"
#include "mmdeploy/core/mpl/structure.h"
#include "mmdeploy/core/tensor.h"
#include "mmdeploy/core/utils/formatter.h"
#include "mmdeploy/handle.h"
#include "mmdeploy/pipeline.h"
using namespace std;
using namespace mmdeploy;
using ResultType = mmdeploy::Structure<mmdeploy_segmentation_t, mmdeploy::framework::Buffer>;
int mmdeploy_segmentor_create(mmdeploy_model_t model, const char* device_name, int device_id,
mmdeploy_segmentor_t* segmentor) {
mmdeploy_context_t context{};
auto ec = mmdeploy_context_create_by_device(device_name, device_id, &context);
if (ec != MMDEPLOY_SUCCESS) {
return ec;
}
ec = mmdeploy_segmentor_create_v2(model, context, segmentor);
mmdeploy_context_destroy(context);
return ec;
}
int mmdeploy_segmentor_create_by_path(const char* model_path, const char* device_name,
int device_id, mmdeploy_segmentor_t* segmentor) {
mmdeploy_model_t model{};
if (auto ec = mmdeploy_model_create_by_path(model_path, &model)) {
return ec;
}
auto ec = mmdeploy_segmentor_create(model, device_name, device_id, segmentor);
mmdeploy_model_destroy(model);
return ec;
}
int mmdeploy_segmentor_apply(mmdeploy_segmentor_t segmentor, const mmdeploy_mat_t* mats,
int mat_count, mmdeploy_segmentation_t** results) {
wrapped<mmdeploy_value_t> input;
if (auto ec = mmdeploy_segmentor_create_input(mats, mat_count, input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_segmentor_apply_v2(segmentor, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_segmentor_get_result(output, results)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
void mmdeploy_segmentor_release_result(mmdeploy_segmentation_t* results, int count) {
ResultType deleter(static_cast<size_t>(count), results);
}
void mmdeploy_segmentor_destroy(mmdeploy_segmentor_t segmentor) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)segmentor);
}
int mmdeploy_segmentor_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_segmentor_t* segmentor) {
return mmdeploy_pipeline_create_from_model(model, context, (mmdeploy_pipeline_t*)segmentor);
}
int mmdeploy_segmentor_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* value) {
return mmdeploy_common_create_input(mats, mat_count, value);
}
int mmdeploy_segmentor_apply_v2(mmdeploy_segmentor_t segmentor, mmdeploy_value_t input,
mmdeploy_value_t* output) {
return mmdeploy_pipeline_apply((mmdeploy_pipeline_t)segmentor, input, output);
}
int mmdeploy_segmentor_apply_async(mmdeploy_segmentor_t segmentor, mmdeploy_sender_t input,
mmdeploy_sender_t* output) {
return mmdeploy_pipeline_apply_async((mmdeploy_pipeline_t)segmentor, input, output);
}
int mmdeploy_segmentor_get_result(mmdeploy_value_t output, mmdeploy_segmentation_t** results) {
try {
const auto& value = Cast(output)->front();
size_t image_count = value.size();
ResultType r(image_count);
auto [results_data, buffers] = r.pointers();
auto results_ptr = results_data;
for (auto i = 0; i < image_count; ++i, ++results_ptr) {
auto& output_item = value[i];
MMDEPLOY_DEBUG("the {}-th item in output: {}", i, output_item);
auto segmentor_output = from_value<mmseg::SegmentorOutput>(output_item);
results_ptr->height = segmentor_output.height;
results_ptr->width = segmentor_output.width;
results_ptr->classes = segmentor_output.classes;
auto& mask = segmentor_output.mask;
auto& score = segmentor_output.score;
results_ptr->mask = nullptr;
results_ptr->score = nullptr;
if (mask.shape().size()) {
results_ptr->mask = mask.data<int>();
buffers[i] = mask.buffer();
} else {
results_ptr->score = score.data<float>();
buffers[i] = score.buffer();
}
}
*results = results_data;
r.release();
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("exception caught: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file segmentor.h
* @brief Interface to MMSegmentation task
*/
#ifndef MMDEPLOY_SEGMENTOR_H
#define MMDEPLOY_SEGMENTOR_H
#include "mmdeploy/common.h"
#include "mmdeploy/executor.h"
#include "mmdeploy/model.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_segmentation_t {
int height; ///< height of \p mask that equals to the input image's height
int width; ///< width of \p mask that equals to the input image's width
int classes; ///< the number of labels in \p mask
int* mask; ///< segmentation mask of the input image, in which mask[i * width + j] indicates
///< the label id of pixel at (i, j), this field might be null
float* score; ///< segmentation score map of the input image in CHW format, in which
///< score[height * width * k + i * width + j] indicates the score
///< of class k at pixel (i, j), this field might be null
} mmdeploy_segmentation_t;
typedef struct mmdeploy_segmentor* mmdeploy_segmentor_t;
/**
* @brief Create segmentor's handle
* @param[in] model an instance of mmsegmentation sdk model created by
* \ref mmdeploy_model_create_by_path or \ref mmdeploy_model_create in \ref model.h
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] segmentor instance of a segmentor, which must be destroyed
* by \ref mmdeploy_segmentor_destroy
* @return status of creating segmentor's handle
*/
MMDEPLOY_API int mmdeploy_segmentor_create(mmdeploy_model_t model, const char* device_name,
int device_id, mmdeploy_segmentor_t* segmentor);
/**
* @brief Create segmentor's handle
* @param[in] model_path path of mmsegmentation sdk model exported by mmdeploy model converter
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] segmentor instance of a segmentor, which must be destroyed
* by \ref mmdeploy_segmentor_destroy
* @return status of creating segmentor's handle
*/
MMDEPLOY_API int mmdeploy_segmentor_create_by_path(const char* model_path, const char* device_name,
int device_id, mmdeploy_segmentor_t* segmentor);
/**
* @brief Apply segmentor to batch images and get their inference results
* @param[in] segmentor segmentor's handle created by \ref mmdeploy_segmentor_create_by_path or \ref
* mmdeploy_segmentor_create
* @param[in] mats a batch of images
* @param[in] mat_count number of images in the batch
* @param[out] results a linear buffer of length \p mat_count to save segmentation result of each
* image. It must be released by \ref mmdeploy_segmentor_release_result
* @return status of inference
*/
MMDEPLOY_API int mmdeploy_segmentor_apply(mmdeploy_segmentor_t segmentor,
const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_segmentation_t** results);
/**
* @brief Release result buffer returned by \ref mmdeploy_segmentor_apply
* @param[in] results result buffer
* @param[in] count length of \p results
*/
MMDEPLOY_API void mmdeploy_segmentor_release_result(mmdeploy_segmentation_t* results, int count);
/**
* @brief Destroy segmentor's handle
* @param[in] segmentor segmentor's handle created by \ref mmdeploy_segmentor_create_by_path
*/
MMDEPLOY_API void mmdeploy_segmentor_destroy(mmdeploy_segmentor_t segmentor);
/******************************************************************************
* Experimental asynchronous APIs */
MMDEPLOY_API int mmdeploy_segmentor_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_segmentor_t* segmentor);
MMDEPLOY_API int mmdeploy_segmentor_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* value);
MMDEPLOY_API int mmdeploy_segmentor_apply_v2(mmdeploy_segmentor_t segmentor, mmdeploy_value_t input,
mmdeploy_value_t* output);
MMDEPLOY_API int mmdeploy_segmentor_apply_async(mmdeploy_segmentor_t segmentor,
mmdeploy_sender_t input, mmdeploy_sender_t* output);
MMDEPLOY_API int mmdeploy_segmentor_get_result(mmdeploy_value_t output,
mmdeploy_segmentation_t** results);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_SEGMENTOR_H
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/text_detector.h"
#include <numeric>
#include "mmdeploy/codebase/mmocr/mmocr.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/model.h"
#include "mmdeploy/core/status_code.h"
#include "mmdeploy/core/utils/formatter.h"
#include "mmdeploy/executor_internal.h"
#include "mmdeploy/model.h"
#include "mmdeploy/pipeline.h"
using namespace std;
using namespace mmdeploy;
int mmdeploy_text_detector_create(mmdeploy_model_t model, const char* device_name, int device_id,
mmdeploy_text_detector_t* detector) {
mmdeploy_context_t context{};
auto ec = mmdeploy_context_create_by_device(device_name, device_id, &context);
if (ec != MMDEPLOY_SUCCESS) {
return ec;
}
ec = mmdeploy_text_detector_create_v2(model, context, detector);
mmdeploy_context_destroy(context);
return ec;
}
int mmdeploy_text_detector_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_text_detector_t* detector) {
return mmdeploy_pipeline_create_from_model(model, context, (mmdeploy_pipeline_t*)detector);
}
int mmdeploy_text_detector_create_by_path(const char* model_path, const char* device_name,
int device_id, mmdeploy_text_detector_t* detector) {
mmdeploy_model_t model{};
if (auto ec = mmdeploy_model_create_by_path(model_path, &model)) {
return ec;
}
auto ec = mmdeploy_text_detector_create(model, device_name, device_id, detector);
mmdeploy_model_destroy(model);
return ec;
}
int mmdeploy_text_detector_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* input) {
return mmdeploy_common_create_input(mats, mat_count, input);
}
int mmdeploy_text_detector_apply(mmdeploy_text_detector_t detector, const mmdeploy_mat_t* mats,
int mat_count, mmdeploy_text_detection_t** results,
int** result_count) {
wrapped<mmdeploy_value_t> input;
if (auto ec = mmdeploy_text_detector_create_input(mats, mat_count, input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_text_detector_apply_v2(detector, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_text_detector_get_result(output, results, result_count)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
int mmdeploy_text_detector_apply_v2(mmdeploy_text_detector_t detector, mmdeploy_value_t input,
mmdeploy_value_t* output) {
return mmdeploy_pipeline_apply((mmdeploy_pipeline_t)detector, input, output);
}
int mmdeploy_text_detector_apply_async(mmdeploy_text_detector_t detector, mmdeploy_sender_t input,
mmdeploy_sender_t* output) {
return mmdeploy_pipeline_apply_async((mmdeploy_pipeline_t)detector, input, output);
}
int mmdeploy_text_detector_get_result(mmdeploy_value_t output, mmdeploy_text_detection_t** results,
int** result_count) {
if (!output || !results || !result_count) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
Value& value = reinterpret_cast<Value*>(output)->front();
auto detector_outputs = from_value<std::vector<mmocr::TextDetections>>(value);
vector<int> _result_count;
_result_count.reserve(detector_outputs.size());
for (const auto& det_output : detector_outputs) {
_result_count.push_back((int)det_output.size());
}
auto total = std::accumulate(_result_count.begin(), _result_count.end(), 0);
std::unique_ptr<int[]> result_count_data(new int[_result_count.size()]{});
std::copy(_result_count.begin(), _result_count.end(), result_count_data.get());
std::unique_ptr<mmdeploy_text_detection_t[]> result_data(
new mmdeploy_text_detection_t[total]{});
auto result_ptr = result_data.get();
for (const auto& det_output : detector_outputs) {
for (auto i = 0; i < det_output.size(); ++i, ++result_ptr) {
result_ptr->score = det_output[i].score;
auto& bbox = det_output[i].bbox;
for (auto j = 0; j < bbox.size(); j += 2) {
result_ptr->bbox[j / 2].x = bbox[j];
result_ptr->bbox[j / 2].y = bbox[j + 1];
}
}
}
*result_count = result_count_data.release();
*results = result_data.release();
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return 0;
}
void mmdeploy_text_detector_release_result(mmdeploy_text_detection_t* results,
const int* result_count, int count) {
delete[] results;
delete[] result_count;
}
void mmdeploy_text_detector_destroy(mmdeploy_text_detector_t detector) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)detector);
}
int mmdeploy_text_detector_apply_async_v2(mmdeploy_text_detector_t detector,
const mmdeploy_mat_t* imgs, int img_count,
mmdeploy_text_detector_continue_t cont, void* context,
mmdeploy_sender_t* output) {
mmdeploy_sender_t result_sender{};
if (auto ec = mmdeploy_text_detector_apply_async_v3(detector, imgs, img_count, &result_sender)) {
return ec;
}
if (auto ec = mmdeploy_text_detector_continue_async(result_sender, cont, context, output)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
int mmdeploy_text_detector_apply_async_v3(mmdeploy_text_detector_t detector,
const mmdeploy_mat_t* imgs, int img_count,
mmdeploy_sender_t* output) {
wrapped<mmdeploy_value_t> input_val;
if (auto ec = mmdeploy_text_detector_create_input(imgs, img_count, input_val.ptr())) {
return ec;
}
mmdeploy_sender_t input_sndr = mmdeploy_executor_just(input_val);
if (auto ec = mmdeploy_text_detector_apply_async(detector, input_sndr, output)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
int mmdeploy_text_detector_continue_async(mmdeploy_sender_t input,
mmdeploy_text_detector_continue_t cont, void* context,
mmdeploy_sender_t* output) {
auto sender = Guard([&] {
return Take(
LetValue(Take(input), [fn = cont, context](Value& value) -> TypeErasedSender<Value> {
mmdeploy_text_detection_t* results{};
int* result_count{};
if (auto ec = mmdeploy_text_detector_get_result(Cast(&value), &results, &result_count)) {
return Just(Value());
}
value = nullptr;
mmdeploy_sender_t output{};
if (auto ec = fn(results, result_count, context, &output); ec || !output) {
return Just(Value());
}
return Take(output);
}));
});
if (sender) {
*output = sender;
return MMDEPLOY_SUCCESS;
}
return MMDEPLOY_E_FAIL;
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file text_detector.h
* @brief Interface to MMOCR text detection task
*/
#ifndef MMDEPLOY_TEXT_DETECTOR_H
#define MMDEPLOY_TEXT_DETECTOR_H
#include "mmdeploy/common.h"
#include "mmdeploy/executor.h"
#include "mmdeploy/model.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_text_detection_t {
mmdeploy_point_t bbox[4]; ///< a text bounding box of which the vertex are in clock-wise
float score;
} mmdeploy_text_detection_t;
typedef struct mmdeploy_text_detector* mmdeploy_text_detector_t;
/**
* @brief Create text-detector's handle
* @param[in] model an instance of mmocr text detection model created by
* \ref mmdeploy_model_create_by_path or \ref mmdeploy_model_create in \ref model.h
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] detector instance of a text-detector, which must be destroyed
* by \ref mmdeploy_text_detector_destroy
* @return status of creating text-detector's handle
*/
MMDEPLOY_API int mmdeploy_text_detector_create(mmdeploy_model_t model, const char* device_name,
int device_id, mmdeploy_text_detector_t* detector);
/**
* @brief Create text-detector's handle
* @param[in] model_path path to text detection model
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device
* @param[out] detector instance of a text-detector, which must be destroyed
* by \ref mmdeploy_text_detector_destroy
* @return status of creating text-detector's handle
*/
MMDEPLOY_API int mmdeploy_text_detector_create_by_path(const char* model_path,
const char* device_name, int device_id,
mmdeploy_text_detector_t* detector);
/**
* @brief Apply text-detector to batch images and get their inference results
* @param[in] detector text-detector's handle created by \ref mmdeploy_text_detector_create_by_path
* @param[in] mats a batch of images
* @param[in] mat_count number of images in the batch
* @param[out] results a linear buffer to save text detection results of each
* image. It must be released by calling \ref mmdeploy_text_detector_release_result
* @param[out] result_count a linear buffer of length \p mat_count to save the number of detection
* results of each image. It must be released by \ref mmdeploy_detector_release_result
* @return status of inference
*/
MMDEPLOY_API int mmdeploy_text_detector_apply(mmdeploy_text_detector_t detector,
const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_text_detection_t** results,
int** result_count);
/** @brief Release the inference result buffer returned by \ref mmdeploy_text_detector_apply
* @param[in] results text detection result buffer
* @param[in] result_count \p results size buffer
* @param[in] count the length of buffer \p result_count
*/
MMDEPLOY_API void mmdeploy_text_detector_release_result(mmdeploy_text_detection_t* results,
const int* result_count, int count);
/**
* @brief Destroy text-detector's handle
* @param[in] detector text-detector's handle created by \ref mmdeploy_text_detector_create_by_path
* or \ref mmdeploy_text_detector_create
*/
MMDEPLOY_API void mmdeploy_text_detector_destroy(mmdeploy_text_detector_t detector);
/******************************************************************************
* Experimental asynchronous APIs */
/**
* @brief Same as \ref mmdeploy_text_detector_create, but allows to control execution context of
* tasks via context
*/
MMDEPLOY_API int mmdeploy_text_detector_create_v2(mmdeploy_model_t model,
mmdeploy_context_t context,
mmdeploy_text_detector_t* detector);
/**
* @brief Pack text-detector inputs into mmdeploy_value_t
* @param[in] mats a batch of images
* @param[in] mat_count number of images in the batch
* @return the created value
*/
MMDEPLOY_API int mmdeploy_text_detector_create_input(const mmdeploy_mat_t* mats, int mat_count,
mmdeploy_value_t* input);
/**
* @brief Same as \ref mmdeploy_text_detector_apply, but input and output are packed in \ref
* mmdeploy_value_t.
*/
MMDEPLOY_API int mmdeploy_text_detector_apply_v2(mmdeploy_text_detector_t detector,
mmdeploy_value_t input, mmdeploy_value_t* output);
/**
* @brief Apply text-detector asynchronously
* @param[in] detector handle to the detector
* @param[in] input input sender that will be consumed by the operation
* @return output sender
*/
MMDEPLOY_API int mmdeploy_text_detector_apply_async(mmdeploy_text_detector_t detector,
mmdeploy_sender_t input,
mmdeploy_sender_t* output);
/**
* @brief Unpack detector output from a mmdeploy_value_t
* @param[in] output output sender returned by applying a detector
* @param[out] results a linear buffer to save detection results of each image. It must be
* released by \ref mmdeploy_text_detector_release_result
* @param[out] result_count a linear buffer with length number of input images to save the
* number of detection results of each image. Must be released by \ref
* mmdeploy_text_detector_release_result
* @return status of the operation
*/
MMDEPLOY_API
int mmdeploy_text_detector_get_result(mmdeploy_value_t output, mmdeploy_text_detection_t** results,
int** result_count);
typedef int (*mmdeploy_text_detector_continue_t)(mmdeploy_text_detection_t* results,
int* result_count, void* context,
mmdeploy_sender_t* output);
// MMDEPLOY_API int mmdeploy_text_detector_apply_async_v2(mm_handle_t handle, const mm_mat_t* imgs,
// int img_count,
// mmdeploy_text_detector_continuation_t
// cont, void* context, mmdeploy_sender_t*
// output);
MMDEPLOY_API int mmdeploy_text_detector_apply_async_v3(mmdeploy_text_detector_t detector,
const mmdeploy_mat_t* imgs, int img_count,
mmdeploy_sender_t* output);
MMDEPLOY_API int mmdeploy_text_detector_continue_async(mmdeploy_sender_t input,
mmdeploy_text_detector_continue_t cont,
void* context, mmdeploy_sender_t* output);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_TEXT_DETECTOR_H
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/text_recognizer.h"
#include <numeric>
#include "mmdeploy/archive/value_archive.h"
#include "mmdeploy/codebase/mmocr/mmocr.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/device.h"
#include "mmdeploy/core/mat.h"
#include "mmdeploy/core/model.h"
#include "mmdeploy/core/status_code.h"
#include "mmdeploy/core/utils/formatter.h"
#include "mmdeploy/core/value.h"
#include "mmdeploy/executor_internal.h"
#include "mmdeploy/model.h"
#include "mmdeploy/pipeline.h"
using namespace mmdeploy;
namespace {
Value config_template(const Model& model) {
// clang-format off
return {
{"type", "Pipeline"},
{"input", {"imgs", "bboxes"}},
{
"tasks", {
{
{"type", "Task"},
{"module", "WarpBbox"},
{"input", {"imgs", "bboxes"}},
{"output", "patches"},
},
{
{"type", "Inference"},
{"input", "patches"},
{"output", "texts"},
{"params", {{"model", model}}},
}
}
},
{"output", "texts"},
};
// clang-format on
}
} // namespace
int mmdeploy_text_recognizer_create(mmdeploy_model_t model, const char* device_name, int device_id,
mmdeploy_text_recognizer_t* recognizer) {
mmdeploy_context_t context{};
auto ec = mmdeploy_context_create_by_device(device_name, device_id, &context);
if (ec != MMDEPLOY_SUCCESS) {
return ec;
}
ec = mmdeploy_text_recognizer_create_v2(model, context, recognizer);
mmdeploy_context_destroy(context);
return ec;
}
int mmdeploy_text_recognizer_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_text_recognizer_t* recognizer) {
auto config = config_template(*Cast(model));
return mmdeploy_pipeline_create_v3(Cast(&config), context, (mmdeploy_pipeline_t*)recognizer);
}
int mmdeploy_text_recognizer_create_by_path(const char* model_path, const char* device_name,
int device_id, mmdeploy_text_recognizer_t* recognizer) {
mmdeploy_model_t model{};
if (auto ec = mmdeploy_model_create_by_path(model_path, &model)) {
return ec;
}
auto ec = mmdeploy_text_recognizer_create(model, device_name, device_id, recognizer);
mmdeploy_model_destroy(model);
return ec;
}
int mmdeploy_text_recognizer_apply(mmdeploy_text_recognizer_t recognizer,
const mmdeploy_mat_t* images, int count,
mmdeploy_text_recognition_t** results) {
return mmdeploy_text_recognizer_apply_bbox(recognizer, images, count, nullptr, nullptr, results);
}
int mmdeploy_text_recognizer_create_input(const mmdeploy_mat_t* images, int image_count,
const mmdeploy_text_detection_t* bboxes,
const int* bbox_count, mmdeploy_value_t* output) {
if (image_count && images == nullptr) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
Value::Array input_images;
Value::Array input_bboxes;
auto add_bbox = [&](Mat img, const mmdeploy_text_detection_t* det) {
if (det) {
const auto& b = det->bbox;
Value::Array bbox{b[0].x, b[0].y, b[1].x, b[1].y, b[2].x, b[2].y, b[3].x, b[3].y};
input_bboxes.push_back({{"bbox", std::move(bbox)}});
} else {
input_bboxes.push_back(nullptr);
}
input_images.push_back({{"ori_img", img}});
};
for (int i = 0; i < image_count; ++i) {
auto _mat = Cast(images[i]);
if (bboxes && bbox_count) {
for (int j = 0; j < bbox_count[i]; ++j) {
add_bbox(_mat, bboxes++);
}
} else { // inference with whole image
add_bbox(_mat, nullptr);
}
}
*output = Take(Value{std::move(input_images), std::move(input_bboxes)});
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("exception caught: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
int mmdeploy_text_recognizer_apply_bbox(mmdeploy_text_recognizer_t recognizer,
const mmdeploy_mat_t* images, int image_count,
const mmdeploy_text_detection_t* bboxes,
const int* bbox_count,
mmdeploy_text_recognition_t** results) {
wrapped<mmdeploy_value_t> input;
if (auto ec = mmdeploy_text_recognizer_create_input(images, image_count, bboxes, bbox_count,
input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_text_recognizer_apply_v2(recognizer, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_text_recognizer_get_result(output, results)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
int mmdeploy_text_recognizer_apply_v2(mmdeploy_text_recognizer_t recognizer, mmdeploy_value_t input,
mmdeploy_value_t* output) {
return mmdeploy_pipeline_apply((mmdeploy_pipeline_t)recognizer, input, output);
}
int mmdeploy_text_recognizer_apply_async(mmdeploy_text_recognizer_t recognizer,
mmdeploy_sender_t input, mmdeploy_sender_t* output) {
return mmdeploy_pipeline_apply_async((mmdeploy_pipeline_t)recognizer, input, output);
}
MMDEPLOY_API int mmdeploy_text_recognizer_get_result(mmdeploy_value_t output,
mmdeploy_text_recognition_t** results) {
if (!output || !results) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
std::vector<mmocr::TextRecognition> recognitions;
from_value(Cast(output)->front(), recognitions);
size_t count = recognitions.size();
auto deleter = [&](mmdeploy_text_recognition_t* p) {
mmdeploy_text_recognizer_release_result(p, static_cast<int>(count));
};
std::unique_ptr<mmdeploy_text_recognition_t[], decltype(deleter)> _results(
new mmdeploy_text_recognition_t[count]{}, deleter);
size_t result_idx = 0;
for (const auto& bbox_result : recognitions) {
auto& res = _results[result_idx++];
auto& score = bbox_result.score;
res.length = static_cast<int>(score.size());
res.score = new float[score.size()];
std::copy_n(score.data(), score.size(), res.score);
auto text = bbox_result.text;
res.text = new char[text.length() + 1];
std::copy_n(text.data(), text.length() + 1, res.text);
}
*results = _results.release();
} catch (const std::exception& e) {
MMDEPLOY_ERROR("exception caught: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_SUCCESS;
}
void mmdeploy_text_recognizer_release_result(mmdeploy_text_recognition_t* results, int count) {
for (int i = 0; i < count; ++i) {
delete[] results[i].score;
delete[] results[i].text;
}
delete[] results;
}
void mmdeploy_text_recognizer_destroy(mmdeploy_text_recognizer_t recognizer) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)recognizer);
}
int mmdeploy_text_recognizer_apply_async_v3(mmdeploy_text_recognizer_t recognizer,
const mmdeploy_mat_t* imgs, int img_count,
const mmdeploy_text_detection_t* bboxes,
const int* bbox_count, mmdeploy_sender_t* output) {
wrapped<mmdeploy_value_t> input_val;
if (auto ec = mmdeploy_text_recognizer_create_input(imgs, img_count, bboxes, bbox_count,
input_val.ptr())) {
return ec;
}
mmdeploy_sender_t input_sndr = mmdeploy_executor_just(input_val);
if (auto ec = mmdeploy_text_recognizer_apply_async(recognizer, input_sndr, output)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
int mmdeploy_text_recognizer_continue_async(mmdeploy_sender_t input,
mmdeploy_text_recognizer_continue_t cont, void* context,
mmdeploy_sender_t* output) {
auto sender = Guard([&] {
return Take(
LetValue(Take(input), [fn = cont, context](Value& value) -> TypeErasedSender<Value> {
mmdeploy_text_recognition_t* results{};
if (auto ec = mmdeploy_text_recognizer_get_result(Cast(&value), &results)) {
return Just(Value());
}
value = nullptr;
mmdeploy_sender_t output{};
if (auto ec = fn(results, context, &output); ec || !output) {
return Just(Value());
}
return Take(output);
}));
});
if (sender) {
*output = sender;
return MMDEPLOY_SUCCESS;
}
return MMDEPLOY_E_FAIL;
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file text_recognizer.h
* @brief Interface to MMOCR text recognition task
*/
#ifndef MMDEPLOY_SRC_APIS_C_TEXT_RECOGNIZER_H_
#define MMDEPLOY_SRC_APIS_C_TEXT_RECOGNIZER_H_
#include "mmdeploy/common.h"
#include "mmdeploy/executor.h"
#include "mmdeploy/text_detector.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_text_recognition_t {
char* text;
float* score;
int length;
} mmdeploy_text_recognition_t;
typedef struct mmdeploy_text_recognizer* mmdeploy_text_recognizer_t;
/**
* @brief Create a text recognizer instance
* @param[in] model an instance of mmocr text recognition model created by
* \ref mmdeploy_model_create_by_path or \ref mmdeploy_model_create in \ref model.h
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] recognizer handle of the created text recognizer, which must be destroyed
* by \ref mmdeploy_text_recognizer_destroy
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_text_recognizer_create(mmdeploy_model_t model, const char* device_name,
int device_id,
mmdeploy_text_recognizer_t* recognizer);
/**
* @brief Create a text recognizer instance
* @param[in] model_path path to text recognition model
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] recognizer handle of the created text recognizer, which must be destroyed
* by \ref mmdeploy_text_recognizer_destroy
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_text_recognizer_create_by_path(const char* model_path,
const char* device_name, int device_id,
mmdeploy_text_recognizer_t* recognizer);
/**
* @brief Apply text recognizer to a batch of text images
* @param[in] recognizer text recognizer's handle created by \ref
* mmdeploy_text_recognizer_create_by_path
* @param[in] images a batch of text images
* @param[in] count number of images in the batch
* @param[out] results a linear buffer contains the recognized text, must be release
* by \ref mmdeploy_text_recognizer_release_result
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_text_recognizer_apply(mmdeploy_text_recognizer_t recognizer,
const mmdeploy_mat_t* images, int count,
mmdeploy_text_recognition_t** results);
/**
* @brief Apply text recognizer to a batch of images supplied with text bboxes
* @param[in] recognizer text recognizer's handle created by \ref
* mmdeploy_text_recognizer_create_by_path
* @param[in] images a batch of text images
* @param[in] image_count number of images in the batch
* @param[in] bboxes bounding boxes detected by text detector
* @param[in] bbox_count number of bboxes of each \p images, must be same length as \p images
* @param[out] results a linear buffer contains the recognized text, which has the same length as \p
* bboxes, must be release by \ref mmdeploy_text_recognizer_release_result
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_text_recognizer_apply_bbox(mmdeploy_text_recognizer_t recognizer,
const mmdeploy_mat_t* images, int image_count,
const mmdeploy_text_detection_t* bboxes,
const int* bbox_count,
mmdeploy_text_recognition_t** results);
/** @brief Release result buffer returned by \ref mmdeploy_text_recognizer_apply or \ref
* mmdeploy_text_recognizer_apply_bbox
* @param[in] results result buffer by text recognizer
* @param[in] count length of \p result
*/
MMDEPLOY_API void mmdeploy_text_recognizer_release_result(mmdeploy_text_recognition_t* results,
int count);
/**
* @brief destroy text recognizer
* @param[in] recognizer handle of text recognizer created by \ref
* mmdeploy_text_recognizer_create_by_path or \ref mmdeploy_text_recognizer_create
*/
MMDEPLOY_API void mmdeploy_text_recognizer_destroy(mmdeploy_text_recognizer_t recognizer);
/******************************************************************************
* Experimental asynchronous APIs */
/**
* @brief Same as \ref mmdeploy_text_recognizer_create, but allows to control execution context of
* tasks via context
*/
MMDEPLOY_API int mmdeploy_text_recognizer_create_v2(mmdeploy_model_t model,
mmdeploy_context_t context,
mmdeploy_text_recognizer_t* recognizer);
/**
* @brief Pack text-recognizer inputs into mmdeploy_value_t
* @param[in] images a batch of images
* @param[in] image_count number of images in the batch
* @param[in] bboxes bounding boxes detected by text detector
* @param[in] bbox_count number of bboxes of each \p images, must be same length as \p images
* @return value created
*/
MMDEPLOY_API int mmdeploy_text_recognizer_create_input(const mmdeploy_mat_t* images,
int image_count,
const mmdeploy_text_detection_t* bboxes,
const int* bbox_count,
mmdeploy_value_t* output);
MMDEPLOY_API int mmdeploy_text_recognizer_apply_v2(mmdeploy_text_recognizer_t recognizer,
mmdeploy_value_t input,
mmdeploy_value_t* output);
/**
* @brief Same as \ref mmdeploy_text_recognizer_apply_bbox, but input and output are packed in \ref
* mmdeploy_value_t.
*/
MMDEPLOY_API int mmdeploy_text_recognizer_apply_async(mmdeploy_text_recognizer_t recognizer,
mmdeploy_sender_t input,
mmdeploy_sender_t* output);
typedef int (*mmdeploy_text_recognizer_continue_t)(mmdeploy_text_recognition_t* results,
void* context, mmdeploy_sender_t* output);
MMDEPLOY_API int mmdeploy_text_recognizer_apply_async_v3(mmdeploy_text_recognizer_t recognizer,
const mmdeploy_mat_t* imgs, int img_count,
const mmdeploy_text_detection_t* bboxes,
const int* bbox_count,
mmdeploy_sender_t* output);
MMDEPLOY_API int mmdeploy_text_recognizer_continue_async(mmdeploy_sender_t input,
mmdeploy_text_recognizer_continue_t cont,
void* context, mmdeploy_sender_t* output);
/**
* @brief Unpack text-recognizer output from a mmdeploy_value_t
* @param[in] output
* @param[out] results
* @return status of the operation
*/
MMDEPLOY_API int mmdeploy_text_recognizer_get_result(mmdeploy_value_t output,
mmdeploy_text_recognition_t** results);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_SRC_APIS_C_TEXT_RECOGNIZER_H_
// Copyright (c) OpenMMLab. All rights reserved.
#include "mmdeploy/video_recognizer.h"
#include <numeric>
#include <vector>
#include "mmdeploy/archive/value_archive.h"
#include "mmdeploy/codebase/mmaction/mmaction.h"
#include "mmdeploy/common_internal.h"
#include "mmdeploy/core/device.h"
#include "mmdeploy/core/mat.h"
#include "mmdeploy/core/model.h"
#include "mmdeploy/core/status_code.h"
#include "mmdeploy/core/utils/formatter.h"
#include "mmdeploy/core/value.h"
#include "mmdeploy/executor_internal.h"
#include "mmdeploy/model.h"
#include "mmdeploy/pipeline.h"
using namespace mmdeploy;
int mmdeploy_video_recognizer_create(mmdeploy_model_t model, const char* device_name, int device_id,
mmdeploy_video_recognizer_t* recognizer) {
mmdeploy_context_t context{};
auto ec = mmdeploy_context_create_by_device(device_name, device_id, &context);
if (ec != MMDEPLOY_SUCCESS) {
return ec;
}
ec = mmdeploy_video_recognizer_create_v2(model, context, recognizer);
mmdeploy_context_destroy(context);
return ec;
}
int mmdeploy_video_recognizer_create_by_path(const char* model_path, const char* device_name,
int device_id,
mmdeploy_video_recognizer_t* recognizer) {
mmdeploy_model_t model{};
if (auto ec = mmdeploy_model_create_by_path(model_path, &model)) {
return ec;
}
auto ec = mmdeploy_video_recognizer_create(model, device_name, device_id, recognizer);
mmdeploy_model_destroy(model);
return ec;
}
int mmdeploy_video_recognizer_apply(mmdeploy_video_recognizer_t recognizer,
const mmdeploy_mat_t* images,
const mmdeploy_video_sample_info_t* video_info, int video_count,
mmdeploy_video_recognition_t** results, int** result_count) {
wrapped<mmdeploy_value_t> input;
if (auto ec =
mmdeploy_video_recognizer_create_input(images, video_info, video_count, input.ptr())) {
return ec;
}
wrapped<mmdeploy_value_t> output;
if (auto ec = mmdeploy_video_recognizer_apply_v2(recognizer, input, output.ptr())) {
return ec;
}
if (auto ec = mmdeploy_video_recognizer_get_result(output, results, result_count)) {
return ec;
}
return MMDEPLOY_SUCCESS;
}
void mmdeploy_video_recognizer_release_result(mmdeploy_video_recognition_t* results,
int* result_count, int video_count) {
delete[] results;
delete[] result_count;
}
void mmdeploy_video_recognizer_destroy(mmdeploy_video_recognizer_t recognizer) {
mmdeploy_pipeline_destroy((mmdeploy_pipeline_t)recognizer);
}
int mmdeploy_video_recognizer_create_v2(mmdeploy_model_t model, mmdeploy_context_t context,
mmdeploy_video_recognizer_t* recognizer) {
return mmdeploy_pipeline_create_from_model(model, context, (mmdeploy_pipeline_t*)recognizer);
}
int mmdeploy_video_recognizer_create_input(const mmdeploy_mat_t* images,
const mmdeploy_video_sample_info_t* video_info,
int video_count, mmdeploy_value_t* value) {
if (video_count && (images == nullptr || video_info == nullptr)) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
auto input = std::make_unique<Value>(Value{Value::kArray});
auto sample = std::make_unique<Value>(Value::kArray);
for (int i = 0; i < video_count; ++i) {
int clip_len = video_info[i].clip_len;
int num_clips = video_info[i].num_clips;
int n_mat = clip_len * num_clips;
for (int j = 0; j < n_mat; j++) {
mmdeploy::Mat _mat{images[j].height,
images[j].width,
PixelFormat(images[j].format),
DataType(images[j].type),
images[j].data,
images[j].device ? *(const Device*)(images[j].device) : Device{0}};
sample->push_back({{"ori_img", _mat}, {"clip_len", clip_len}, {"num_clips", num_clips}});
}
input->front().push_back(std::move(*sample.release()));
}
*value = Cast(input.release());
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_SUCCESS;
}
int mmdeploy_video_recognizer_apply_v2(mmdeploy_video_recognizer_t recognizer,
mmdeploy_value_t input, mmdeploy_value_t* output) {
return mmdeploy_pipeline_apply((mmdeploy_pipeline_t)recognizer, input, output);
}
int mmdeploy_video_recognizer_get_result(mmdeploy_value_t output,
mmdeploy_video_recognition_t** results,
int** result_count) {
if (!output || !results || !result_count) {
return MMDEPLOY_E_INVALID_ARG;
}
try {
Value& value = Cast(output)->front();
auto classify_outputs = from_value<std::vector<mmaction::Labels>>(value);
std::vector<int> _result_count;
_result_count.reserve(classify_outputs.size());
for (const auto& cls_output : classify_outputs) {
_result_count.push_back((int)cls_output.size());
}
auto total = std::accumulate(begin(_result_count), end(_result_count), 0);
std::unique_ptr<int[]> result_count_data(new int[_result_count.size()]{});
std::copy(_result_count.begin(), _result_count.end(), result_count_data.get());
std::unique_ptr<mmdeploy_video_recognition_t[]> result_data(
new mmdeploy_video_recognition_t[total]{});
auto result_ptr = result_data.get();
for (const auto& cls_output : classify_outputs) {
for (const auto& label : cls_output) {
result_ptr->label_id = label.label_id;
result_ptr->score = label.score;
++result_ptr;
}
}
*result_count = result_count_data.release();
*results = result_data.release();
return MMDEPLOY_SUCCESS;
} catch (const std::exception& e) {
MMDEPLOY_ERROR("unhandled exception: {}", e.what());
} catch (...) {
MMDEPLOY_ERROR("unknown exception caught");
}
return MMDEPLOY_E_FAIL;
}
// Copyright (c) OpenMMLab. All rights reserved.
/**
* @file video_recognizer.h
* @brief Interface to MMACTION video recognition task
*/
#ifndef MMDEPLOY_VIDEO_RECOGNIZER_H
#define MMDEPLOY_VIDEO_RECOGNIZER_H
#include "mmdeploy/common.h"
#include "mmdeploy/executor.h"
#include "mmdeploy/model.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmdeploy_video_recognition_t {
int label_id;
float score;
} mmdeploy_video_recognition_t;
typedef struct mmdeploy_video_sample_info_t {
int clip_len;
int num_clips;
} mmdeploy_video_sample_info_t;
typedef struct mmdeploy_video_recognizer* mmdeploy_video_recognizer_t;
/**
* @brief Create video recognizer's handle
* @param[in] model an instance of mmaction sdk model created by
* \ref mmdeploy_model_create_by_path or \ref mmdeploy_model_create in \ref model.h
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] recognizer handle of the created video recognizer, which must be destroyed
* by \ref mmdeploy_video_recognizer_destroy
* @return status of creating video recognizer's handle
*/
MMDEPLOY_API int mmdeploy_video_recognizer_create(mmdeploy_model_t model, const char* device_name,
int device_id,
mmdeploy_video_recognizer_t* recognizer);
/**
* @brief Create a video recognizer instance
* @param[in] model_path path to video recognition model
* @param[in] device_name name of device, such as "cpu", "cuda", etc.
* @param[in] device_id id of device.
* @param[out] recognizer handle of the created video recognizer, which must be destroyed
* by \ref mmdeploy_video_recognizer_destroy
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_video_recognizer_create_by_path(const char* model_path,
const char* device_name, int device_id,
mmdeploy_video_recognizer_t* recognizer);
/**
* @brief Apply video recognizer to a batch of videos
* @param[in] recognizer video recognizer's handle created by \ref
* mmdeploy_video_recognizer_create_by_path
* @param[in] images a batch of videos
* @param[in] video_info video information of each video
* @param[in] video_count number of videos
* @param[out] results a linear buffer contains the recognized video, must be release
* by \ref mmdeploy_video_recognizer_release_result
* @param[out] result_count a linear buffer with length being \p video_count to save the number of
* recognition results of each video. It must be released by \ref
* mmdeploy_video_recognizer_release_result
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_video_recognizer_apply(mmdeploy_video_recognizer_t recognizer,
const mmdeploy_mat_t* images,
const mmdeploy_video_sample_info_t* video_info,
int video_count,
mmdeploy_video_recognition_t** results,
int** result_count);
/** @brief Release result buffer returned by \ref mmdeploy_video_recognizer_apply
* @param[in] results result buffer by video recognizer
* @param[in] result_count \p results size buffer
* @param[in] video_count length of \p result_count
*/
MMDEPLOY_API void mmdeploy_video_recognizer_release_result(mmdeploy_video_recognition_t* results,
int* result_count, int video_count);
/**
* @brief destroy video recognizer
* @param[in] recognizer handle of video recognizer created by \ref
* mmdeploy_video_recognizer_create_by_path or \ref mmdeploy_video_recognizer_create
*/
MMDEPLOY_API void mmdeploy_video_recognizer_destroy(mmdeploy_video_recognizer_t recognizer);
/**
* @brief Same as \ref mmdeploy_video_recognizer_create, but allows to control execution context of
* tasks via context
*/
MMDEPLOY_API int mmdeploy_video_recognizer_create_v2(mmdeploy_model_t model,
mmdeploy_context_t context,
mmdeploy_video_recognizer_t* recognizer);
/**
* @brief Pack video recognizer inputs into mmdeploy_value_t
* @param[in] images a batch of videos
* @param[in] video_info video information of each video
* @param[in] video_count number of videos in the batch
* @param[out] value created value
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_video_recognizer_create_input(
const mmdeploy_mat_t* images, const mmdeploy_video_sample_info_t* video_info, int video_count,
mmdeploy_value_t* value);
/**
* @brief Apply video recognizer to a batch of videos
* @param[in] input packed input
* @param[out] output inference output
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_video_recognizer_apply_v2(mmdeploy_video_recognizer_t recognizer,
mmdeploy_value_t input,
mmdeploy_value_t* output);
/**
* @brief Apply video recognizer to a batch of videos
* @param[in] output inference output
* @param[out] results structured output
* @param[out] result_count number of each videos
* @return status code of the operation
*/
MMDEPLOY_API int mmdeploy_video_recognizer_get_result(mmdeploy_value_t output,
mmdeploy_video_recognition_t** results,
int** result_count);
#ifdef __cplusplus
}
#endif
#endif // MMDEPLOY_VIDEO_RECOGNIZER_H

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31729.503
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MMDeploy", "MMDeploy\MMDeployCSharp.csproj", "{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Debug|x64.ActiveCfg = Debug|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Debug|x64.Build.0 = Debug|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Debug|x86.ActiveCfg = Debug|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Debug|x86.Build.0 = Debug|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Release|Any CPU.Build.0 = Release|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Release|x64.ActiveCfg = Release|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Release|x64.Build.0 = Release|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Release|x86.ActiveCfg = Release|Any CPU
{3DC914EB-A8FB-4A89-A7CF-7DF9CC5284A6}.Release|x86.Build.0 = Release|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Debug|x64.ActiveCfg = Debug|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Debug|x64.Build.0 = Debug|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Debug|x86.ActiveCfg = Debug|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Debug|x86.Build.0 = Debug|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Release|Any CPU.Build.0 = Release|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Release|x64.ActiveCfg = Release|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Release|x64.Build.0 = Release|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Release|x86.ActiveCfg = Release|Any CPU
{661A4295-68CF-41C6-85B8-B11748113A6F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5E63FEFB-A55D-4BEB-83B8-7D0E5A59EBF7}
EndGlobalSection
EndGlobal
[*.cs]
csharp_style_var_for_built_in_types=true:silent
csharp_style_var_when_type_is_apparent=true:silent
csharp_style_var_elsewhere=true:silent
##
## StyleCop.Analyzers
##
# Using directive should appear within a namespace declaration
dotnet_diagnostic.SA1200.severity = None
# XML comment analysis is disabled due to project configuration
dotnet_diagnostic.SA0001.severity = None
# The file header is missing or not located at the Top of the file
dotnet_diagnostic.SA1633.severity = None
# Use string.Empty for empty strings
dotnet_diagnostic.SA1122.severity = None
# Variable '_' should begin with lower-case letter
dotnet_diagnostic.SA1312.severity = None
# Parameter '_' should begin with lower-case letter
dotnet_diagnostic.SA1313.severity = None
# Elements should be documented
dotnet_diagnostic.SA1600.severity = None
# Prefix local calls with this
dotnet_diagnostic.SA1101.severity = None
# 'public' members should come before 'private' members
dotnet_diagnostic.SA1202.severity = None
# Comments should contain text
dotnet_diagnostic.SA1120.severity = None
# Constant fields should appear before non-constant fields
dotnet_diagnostic.SA1203.severity = None
# Field '_blah' should not begin with an underscore
dotnet_diagnostic.SA1309.severity = None
# Use trailing comma in multi-line initializers
dotnet_diagnostic.SA1413.severity = None
# A method should not follow a class
dotnet_diagnostic.SA1201.severity = None
# Elements should be separated by blank line
dotnet_diagnostic.SA1516.severity = None
# The parameter spans multiple lines
dotnet_diagnostic.SA1118.severity = None
# Static members should appear before non-static members
dotnet_diagnostic.SA1204.severity = None
# Put constructor initializers on their own line
dotnet_diagnostic.SA1128.severity = None
# Opening braces should not be preceded by blank line
dotnet_diagnostic.SA1509.severity = None
# The parameter should begin on the line after the previous parameter
dotnet_diagnostic.SA1115.severity = None
# File name should match first type name
dotnet_diagnostic.SA1649.severity = None
# File may only contain a single type
dotnet_diagnostic.SA1402.severity = None
# Enumeration items should be documented
dotnet_diagnostic.SA1602.severity = None
# Element should not be on a single line
dotnet_diagnostic.SA1502.severity = None
# Closing parenthesis should not be preceded by a space
dotnet_diagnostic.SA1009.severity = None
# Closing parenthesis should be on line of last parameter
dotnet_diagnostic.SA1111.severity = None
# Braces should not be ommitted
dotnet_diagnostic.SA1503.severity = None
# The name of a C# element does not begin with an upper-case letter
# dotnet_diagnostic.SA1300.severity = None
# The name of a public or internal field in C# does not begin with an upper-case letter
# dotnet_diagnostic.SA1307.severity = None
# The code uses one of the basic C# types, but does not use the built-in alias for the type
# dotnet_diagnostic.SA1121.severity = None
# Two or more attributes appeared within the same set of square brackets.
dotnet_diagnostic.SA1133.severity = None
# The C# code contains a region.
dotnet_diagnostic.SA1124.severity = None
# The parameters to a C# method or indexer call or declaration span across multiple lines, but the first parameter does not start on the line after the opening bracket.
dotnet_diagnostic.SA1116.severity = None
# The parameters to a C# method or indexer call or declaration are not all on the same line or each on a separate line.
dotnet_diagnostic.SA1117.severity = None
using System.Collections.Generic;
namespace MMDeploy
{
/// <summary>
/// Single classification result of a picture.
/// A picture may contains multiple reuslts.
/// </summary>
public struct Label
{
/// <summary>
/// Id.
/// </summary>
public int Id;
/// <summary>
/// Score.
/// </summary>
public float Score;
/// <summary>
/// Initializes a new instance of the <see cref="Label"/> struct.
/// </summary>
/// <param name="id">id.</param>
/// <param name="score">score.</param>
public Label(int id, float score)
{
Id = id;
Score = score;
}
}
/// <summary>
/// Output of Classifier.
/// </summary>
public struct ClassifierOutput
{
/// <summary>
/// Classification results for single image.
/// </summary>
public List<Label> Results;
/// <summary>
/// Add result to single image.
/// </summary>
/// <param name="id">id.</param>
/// <param name="score">score.</param>
public void Add(int id, float score)
{
if (Results == null)
{
Results = new List<Label>();
}
Results.Add(new Label(id, score));
}
/// <summary>
/// Gets number of output.
/// </summary>
public int Count
{
get { return (Results == null) ? 0 : Results.Count; }
}
}
/// <summary>
/// classifier.
/// </summary>
public class Classifier : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="Classifier"/> class.
/// </summary>
/// <param name="modelPath">model path.</param>
/// <param name="deviceName">device name.</param>
/// <param name="deviceId">deviceId.</param>
public Classifier(string modelPath, string deviceName, int deviceId)
{
ThrowException(NativeMethods.mmdeploy_classifier_create_by_path(modelPath, deviceName, deviceId, out _handle));
}
/// <summary>
/// Get label information of each image in a batch.
/// </summary>
/// <param name="mats">input mats.</param>
/// <returns>Results of each input mat.</returns>
public List<ClassifierOutput> Apply(Mat[] mats)
{
List<ClassifierOutput> output = new List<ClassifierOutput>();
unsafe
{
Label* results = null;
int* resultCount = null;
fixed (Mat* _mats = mats)
{
ThrowException(NativeMethods.mmdeploy_classifier_apply(_handle, _mats, mats.Length, &results, &resultCount));
}
FormatResult(mats.Length, resultCount, results, ref output, out var total);
ReleaseResult(results, resultCount, total);
}
return output;
}
private unsafe void FormatResult(int matCount, int* resultCount, Label* results, ref List<ClassifierOutput> output, out int total)
{
total = matCount;
for (int i = 0; i < matCount; i++)
{
ClassifierOutput outi = default;
for (int j = 0; j < resultCount[i]; j++)
{
outi.Add(results->Id, results->Score);
results++;
}
output.Add(outi);
}
}
private unsafe void ReleaseResult(Label* results, int* resultCount, int count)
{
NativeMethods.mmdeploy_classifier_release_result(results, resultCount, count);
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_classifier_destroy(_handle);
}
}
}
namespace MMDeploy
{
/// <summary>
/// Context.
/// </summary>
public class Context : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="Context"/> class.
/// </summary>
public Context()
{
ThrowException(NativeMethods.mmdeploy_context_create(out _handle));
}
/// <summary>
/// Initializes a new instance of the <see cref="Context"/> class with device.
/// </summary>
/// <param name="device">device.</param>
public Context(Device device) : this()
{
Add(device);
}
/// <summary>
/// Add model to the context.
/// </summary>
/// <param name="name">name.</param>
/// <param name="model">model.</param>
public void Add(string name, Model model)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.MODEL, name, model));
}
/// <summary>
/// Add scheduler to the context.
/// </summary>
/// <param name="name">name.</param>
/// <param name="scheduler">scheduler.</param>
public void Add(string name, Scheduler scheduler)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.SCHEDULER, name, scheduler));
}
/// <summary>
/// Add device to the context.
/// </summary>
/// <param name="device">device.</param>
public void Add(Device device)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.DEVICE, "", device));
}
/// <summary>
/// Add profiler to the context.
/// </summary>
/// <param name="profiler">profiler.</param>
public void Add(Profiler profiler)
{
ThrowException(NativeMethods.mmdeploy_context_add(this, (int)ContextType.PROFILER, "", profiler));
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_model_destroy(_handle);
}
}
}
using System;
using System.Collections.Generic;
namespace MMDeploy
{
#pragma warning disable 0649
/// <summary>
/// mm_instance_mask_t of c code.
/// </summary>
internal unsafe struct CInstanceMask
{
public char* Data;
public int Height;
public int Width;
}
/// <summary>
/// mm_detect_t of c code.
/// </summary>
internal unsafe struct CDetect
{
public int LabelId;
public float Score;
public Rect BBox;
public CInstanceMask* Mask;
}
#pragma warning restore 0649
/// <summary>
/// Instance mask.
/// </summary>
public struct InstanceMask
{
/// <summary>
/// Height.
/// </summary>
public int Height;
/// <summary>
/// Width.
/// </summary>
public int Width;
/// <summary>
/// Raw data.
/// </summary>
public byte[] Data;
internal unsafe InstanceMask(CInstanceMask* mask)
{
Height = mask->Height;
Width = mask->Width;
Data = new byte[Height * Width];
fixed (byte* data = this.Data)
{
Buffer.MemoryCopy(mask->Data, data, Height * Width, Height * Width);
}
}
}
/// <summary>
/// Single detection result of a picture.
/// A picture may contains multiple reuslts.
/// </summary>
public struct Detect
{
/// <summary>
/// Label id.
/// </summary>
public int LabelId;
/// <summary>
/// Score.
/// </summary>
public float Score;
/// <summary>
/// Bounding box.
/// </summary>
public Rect BBox;
/// <summary>
/// Whether has mask.
/// </summary>
public bool HasMask;
/// <summary>
/// Mask.
/// </summary>
public InstanceMask Mask;
/// <summary>
/// Initializes a new instance of the <see cref="Detect"/> struct.
/// </summary>
/// <param name="labelId">label id.</param>
/// <param name="score"> score.</param>
/// <param name="bbox">bounding box.</param>
public Detect(int labelId, float score, Rect bbox)
{
LabelId = labelId;
Score = score;
BBox = bbox;
HasMask = false;
Mask = default;
}
internal unsafe Detect(CDetect* result) : this(result->LabelId, result->Score, result->BBox)
{
if (result->Mask != null)
{
HasMask = true;
CInstanceMask* mask = result->Mask;
Mask = new InstanceMask(mask);
}
}
}
/// <summary>
/// Output of Detector.
/// </summary>
public struct DetectorOutput
{
/// <summary>
/// Detection results for single image.
/// </summary>
public List<Detect> Results;
/// <summary>
/// Init Reuslts.
/// </summary>
public void Init()
{
if (Results == null)
{
Results = new List<Detect>();
}
}
/// <summary>
/// Add result to single image.
/// </summary>
/// <param name="labelId">label id.</param>
/// <param name="score">score.</param>
/// <param name="bbox">bounding box.</param>
public void Add(int labelId, float score, Rect bbox)
{
Init();
Results.Add(new Detect(labelId, score, bbox));
}
internal unsafe void Add(CDetect* result)
{
Init();
Results.Add(new Detect(result));
}
/// <summary>
/// Gets number of output.
/// </summary>
public int Count
{
get { return (Results == null) ? 0 : Results.Count; }
}
}
/// <summary>
/// Detector.
/// </summary>
public class Detector : DisposableObject
{
/// <summary>
/// Initializes a new instance of the <see cref="Detector"/> class.
/// </summary>
/// <param name="modelPath">model path.</param>
/// <param name="deviceName">device name.</param>
/// <param name="deviceId">device id.</param>
public Detector(string modelPath, string deviceName, int deviceId)
{
ThrowException(NativeMethods.mmdeploy_detector_create_by_path(modelPath, deviceName, deviceId, out _handle));
}
/// <summary>
/// Get information of each image in a batch.
/// </summary>
/// <param name="mats">input mats.</param>
/// <returns>Results of each input mat.</returns>
public List<DetectorOutput> Apply(Mat[] mats)
{
List<DetectorOutput> output = new List<DetectorOutput>();
unsafe
{
CDetect* results = null;
int* resultCount = null;
fixed (Mat* _mats = mats)
{
ThrowException(NativeMethods.mmdeploy_detector_apply(_handle, _mats, mats.Length, &results, &resultCount));
}
FormatResult(mats.Length, resultCount, results, ref output, out var total);
ReleaseResult(results, resultCount, total);
}
return output;
}
private unsafe void FormatResult(int matCount, int* resultCount, CDetect* results, ref List<DetectorOutput> output, out int total)
{
total = matCount;
for (int i = 0; i < matCount; i++)
{
DetectorOutput outi = default;
for (int j = 0; j < resultCount[i]; j++)
{
outi.Add(results);
results++;
}
output.Add(outi);
}
}
private unsafe void ReleaseResult(CDetect* results, int* resultCount, int count)
{
NativeMethods.mmdeploy_detector_release_result(results, resultCount, count);
}
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_detector_destroy(_handle);
}
}
}
namespace MMDeploy
{
/// <summary>
/// Device.
/// </summary>
public class Device : DisposableObject
{
private readonly string _name;
private readonly int _index;
/// <summary>
/// Initializes a new instance of the <see cref="Device"/> class.
/// </summary>
/// <param name="name">device name.</param>
/// <param name="index">device index.</param>
public Device(string name, int index = 0)
{
this._name = name;
this._index = index;
ThrowException(NativeMethods.mmdeploy_device_create(name, index, out _handle));
}
/// <summary>
/// Gets device name.
/// </summary>
public string Name { get => _name; }
/// <summary>
/// Gets device index.
/// </summary>
public int Index { get => _index; }
/// <inheritdoc/>
protected override void ReleaseHandle()
{
NativeMethods.mmdeploy_device_destroy(_handle);
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment