-
Notifications
You must be signed in to change notification settings - Fork 629
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature] Add C++ API for SDK (#831)
* add C++ API * unify result type & add examples * minor fix * install cxx API headers * fix Mat, add more examples * fix monolithic build & fix lint * install examples correctly * fix lint
- Loading branch information
Showing
23 changed files
with
1,104 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Copyright (c) OpenMMLab. All rights reserved. | ||
|
||
cmake_minimum_required(VERSION 3.14) | ||
project(mmdeploy_cxx_api) | ||
|
||
if (MMDEPLOY_BUILD_SDK_CXX_API) | ||
add_library(${PROJECT_NAME} INTERFACE) | ||
target_include_directories(${PROJECT_NAME} INTERFACE | ||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> | ||
$<INSTALL_INTERFACE:include>) | ||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17) | ||
target_link_libraries(${PROJECT_NAME} INTERFACE mmdeploy::core) | ||
foreach (task ${MMDEPLOY_TASKS}) | ||
target_link_libraries(mmdeploy_${task} INTERFACE ${PROJECT_NAME}) | ||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mmdeploy/${task}.hpp | ||
DESTINATION include/mmdeploy) | ||
endforeach () | ||
if (TARGET mmdeploy) | ||
target_link_libraries(mmdeploy INTERFACE ${PROJECT_NAME}) | ||
endif () | ||
mmdeploy_export(${PROJECT_NAME}) | ||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mmdeploy/common.hpp | ||
DESTINATION include/mmdeploy) | ||
endif () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright (c) OpenMMLab. All rights reserved. | ||
|
||
#ifndef MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_CLASSIFIER_HPP_ | ||
#define MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_CLASSIFIER_HPP_ | ||
|
||
#include "mmdeploy/classifier.h" | ||
#include "mmdeploy/common.hpp" | ||
|
||
namespace mmdeploy { | ||
|
||
using Classification = mmdeploy_classification_t; | ||
|
||
class Classifier : public NonMovable { | ||
public: | ||
Classifier(const Model& model, const Device& device) { | ||
auto ec = mmdeploy_classifier_create(model, device.name(), device.index(), &classifier_); | ||
if (ec != MMDEPLOY_SUCCESS) { | ||
throw_exception(static_cast<ErrorCode>(ec)); | ||
} | ||
} | ||
|
||
~Classifier() { | ||
if (classifier_) { | ||
mmdeploy_classifier_destroy(classifier_); | ||
classifier_ = {}; | ||
} | ||
} | ||
|
||
using Result = Result_<Classification>; | ||
|
||
std::vector<Result> Apply(Span<const Mat> images) { | ||
if (images.empty()) { | ||
return {}; | ||
} | ||
|
||
Classification* results{}; | ||
int* result_count{}; | ||
auto ec = mmdeploy_classifier_apply(classifier_, reinterpret(images.data()), | ||
static_cast<int>(images.size()), &results, &result_count); | ||
if (ec != MMDEPLOY_SUCCESS) { | ||
throw_exception(static_cast<ErrorCode>(ec)); | ||
} | ||
|
||
std::vector<Result> rets; | ||
rets.reserve(images.size()); | ||
|
||
std::shared_ptr<Classification> data(results, [result_count, count = images.size()](auto p) { | ||
mmdeploy_classifier_release_result(p, result_count, count); | ||
}); | ||
|
||
size_t offset = 0; | ||
for (size_t i = 0; i < images.size(); ++i) { | ||
offset += rets.emplace_back(offset, result_count[i], data).size(); | ||
} | ||
|
||
return rets; | ||
} | ||
|
||
Result Apply(const Mat& img) { return Apply(Span{img})[0]; } | ||
|
||
private: | ||
mmdeploy_classifier_t classifier_{}; | ||
}; | ||
|
||
} // namespace mmdeploy | ||
|
||
#endif // MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_CLASSIFIER_HPP_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright (c) OpenMMLab. All rights reserved. | ||
|
||
#ifndef MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_COMMON_H_ | ||
#define MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_COMMON_H_ | ||
|
||
#include <memory> | ||
#include <type_traits> | ||
#include <utility> | ||
|
||
#include "mmdeploy/common.h" | ||
#include "mmdeploy/core/mpl/span.h" | ||
#include "mmdeploy/core/status_code.h" | ||
#include "mmdeploy/core/types.h" | ||
#include "mmdeploy/model.h" | ||
|
||
#ifndef MMDEPLOY_CXX_USE_OPENCV | ||
#define MMDEPLOY_CXX_USE_OPENCV 1 | ||
#endif | ||
|
||
#if MMDEPLOY_CXX_USE_OPENCV | ||
#include "opencv2/core/core.hpp" | ||
#endif | ||
|
||
namespace mmdeploy { | ||
|
||
using Rect = mmdeploy_rect_t; | ||
|
||
namespace { // for now, avoid conflict with internal classes, for now | ||
|
||
class Model { | ||
public: | ||
explicit Model(const char* path) { | ||
mmdeploy_model_t model{}; | ||
auto ec = mmdeploy_model_create_by_path(path, &model); | ||
if (ec != MMDEPLOY_SUCCESS) { | ||
throw_exception(static_cast<ErrorCode>(ec)); | ||
} | ||
model_.reset(model, [](auto p) { mmdeploy_model_destroy(p); }); | ||
} | ||
|
||
Model(const void* buffer, size_t size) { | ||
mmdeploy_model_t model{}; | ||
auto ec = mmdeploy_model_create(buffer, static_cast<int>(size), &model); | ||
if (ec != MMDEPLOY_SUCCESS) { | ||
throw_exception(static_cast<ErrorCode>(ec)); | ||
} | ||
model_.reset(model, [](auto p) { mmdeploy_model_destroy(p); }); | ||
} | ||
|
||
operator mmdeploy_model_t() const noexcept { return model_.get(); } | ||
|
||
private: | ||
std::shared_ptr<mmdeploy_model> model_{}; | ||
}; | ||
|
||
class Device { | ||
public: | ||
explicit Device(std::string name, int index = 0) : name_(std::move(name)), index_(index) {} | ||
|
||
const char* name() const noexcept { return name_.c_str(); } | ||
int index() const noexcept { return index_; } | ||
|
||
private: | ||
std::string name_; | ||
int index_; | ||
}; | ||
|
||
class Mat { | ||
public: | ||
Mat() : desc_{} {} | ||
|
||
Mat(int height, int width, int channels, mmdeploy_pixel_format_t format, | ||
mmdeploy_data_type_t type, uint8_t* data) | ||
: desc_{data, height, width, channels, format, type} {} | ||
|
||
const mmdeploy_mat_t& desc() const noexcept { return desc_; } | ||
|
||
#if MMDEPLOY_CXX_USE_OPENCV | ||
Mat(const cv::Mat& mat, mmdeploy_pixel_format_t pixel_format) | ||
: desc_{mat.data, mat.rows, mat.cols, mat.channels(), pixel_format, GetCvType(mat.depth())} { | ||
if (pixel_format == MMDEPLOY_PIXEL_FORMAT_COUNT) { | ||
throw_exception(eNotSupported); | ||
} | ||
if (desc_.type == MMDEPLOY_DATA_TYPE_COUNT) { | ||
throw_exception(eNotSupported); | ||
} | ||
} | ||
Mat(const cv::Mat& mat) : Mat(mat, GetCvFormat(mat.channels())) {} | ||
|
||
static mmdeploy_data_type_t GetCvType(int depth) { | ||
switch (depth) { | ||
case CV_8U: | ||
return MMDEPLOY_DATA_TYPE_UINT8; | ||
case CV_32F: | ||
return MMDEPLOY_DATA_TYPE_FLOAT; | ||
default: | ||
return MMDEPLOY_DATA_TYPE_COUNT; | ||
} | ||
} | ||
static mmdeploy_pixel_format_t GetCvFormat(int channels) { | ||
switch (channels) { | ||
case 1: | ||
return MMDEPLOY_PIXEL_FORMAT_GRAYSCALE; | ||
case 3: | ||
return MMDEPLOY_PIXEL_FORMAT_BGR; | ||
case 4: | ||
return MMDEPLOY_PIXEL_FORMAT_BGRA; | ||
default: | ||
return MMDEPLOY_PIXEL_FORMAT_COUNT; | ||
} | ||
} | ||
#endif | ||
private: | ||
mmdeploy_mat_t desc_; | ||
}; | ||
|
||
template <typename T> | ||
class Result_ { | ||
public: | ||
Result_(size_t offset, size_t size, std::shared_ptr<T> data) | ||
: offset_(offset), size_(size), data_(std::move(data)) {} | ||
|
||
T& operator[](size_t index) const noexcept { return *(data_.get() + offset_ + index); } | ||
size_t size() const noexcept { return size_; } | ||
T* begin() const noexcept { return data_.get() + offset_; } | ||
T* end() const noexcept { return begin() + size_; } | ||
|
||
T* operator->() const noexcept { return data_.get(); } | ||
T& operator*() const noexcept { return *data_; } | ||
|
||
private: | ||
size_t offset_; | ||
size_t size_; | ||
std::shared_ptr<T> data_; | ||
}; | ||
|
||
inline const mmdeploy_mat_t* reinterpret(const Mat* p) { | ||
return reinterpret_cast<const mmdeploy_mat_t*>(p); | ||
} | ||
|
||
} // namespace | ||
|
||
} // namespace mmdeploy | ||
|
||
#endif // MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_COMMON_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright (c) OpenMMLab. All rights reserved. | ||
|
||
#ifndef MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_DETECTOR_HPP_ | ||
#define MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_DETECTOR_HPP_ | ||
|
||
#include "mmdeploy/common.hpp" | ||
#include "mmdeploy/detector.h" | ||
|
||
namespace mmdeploy { | ||
|
||
using Detection = mmdeploy_detection_t; | ||
|
||
class Detector : public NonMovable { | ||
public: | ||
Detector(const Model& model, const Device& device) { | ||
auto ec = mmdeploy_detector_create(model, device.name(), device.index(), &detector_); | ||
if (ec != MMDEPLOY_SUCCESS) { | ||
throw_exception(static_cast<ErrorCode>(ec)); | ||
} | ||
} | ||
|
||
~Detector() { | ||
if (detector_) { | ||
mmdeploy_detector_destroy(detector_); | ||
detector_ = {}; | ||
} | ||
} | ||
|
||
using Result = Result_<Detection>; | ||
|
||
std::vector<Result> Apply(Span<const Mat> images) { | ||
if (images.empty()) { | ||
return {}; | ||
} | ||
|
||
Detection* results{}; | ||
int* result_count{}; | ||
auto ec = mmdeploy_detector_apply(detector_, reinterpret(images.data()), | ||
static_cast<int>(images.size()), &results, &result_count); | ||
if (ec != MMDEPLOY_SUCCESS) { | ||
throw_exception(static_cast<ErrorCode>(ec)); | ||
} | ||
|
||
std::shared_ptr<Detection> data(results, [result_count, count = images.size()](auto p) { | ||
mmdeploy_detector_release_result(p, result_count, count); | ||
}); | ||
|
||
std::vector<Result> rets; | ||
rets.reserve(images.size()); | ||
|
||
size_t offset = 0; | ||
for (size_t i = 0; i < images.size(); ++i) { | ||
offset += rets.emplace_back(offset, result_count[i], data).size(); | ||
} | ||
|
||
return rets; | ||
} | ||
|
||
Result Apply(const Mat& image) { return Apply(Span{image})[0]; } | ||
|
||
private: | ||
mmdeploy_detector_t detector_{}; | ||
}; | ||
|
||
} // namespace mmdeploy | ||
|
||
#endif // MMDEPLOY_CSRC_MMDEPLOY_APIS_CXX_DETECTOR_HPP_ |
Oops, something went wrong.