Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add C++ API for SDK #831

Merged
merged 9 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ if (MMDEPLOY_BUILD_SDK)
endif ()

if (MMDEPLOY_BUILD_EXAMPLES)
include(${CMAKE_SOURCE_DIR}/cmake/opencv.cmake)
add_subdirectory(demo/csrc)
endif ()

Expand Down
1 change: 1 addition & 0 deletions cmake/MMDeployConfig.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(MMDEPLOY_TARGET_DEVICES @MMDEPLOY_TARGET_DEVICES@)
set(MMDEPLOY_TARGET_BACKENDS @MMDEPLOY_TARGET_BACKENDS@)
set(MMDEPLOY_BUILD_TYPE @CMAKE_BUILD_TYPE@)
set(MMDEPLOY_BUILD_SHARED @MMDEPLOY_SHARED_LIBS@)
set(MMDEPLOY_BUILD_SDK_CXX_API @MMDEPLOY_BUILD_SDK_CXX_API@)
set(MMDEPLOY_BUILD_SDK_MONOLITHIC @MMDEPLOY_BUILD_SDK_MONOLITHIC@)
set(MMDEPLOY_VERSION_MAJOR @MMDEPLOY_VERSION_MAJOR@)
set(MMDEPLOY_VERSION_MINOR @MMDEPLOY_VERSION_MINOR@)
Expand Down
1 change: 1 addition & 0 deletions csrc/mmdeploy/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ if (MMDEPLOY_BUILD_SDK)
add_subdirectory(net)
add_subdirectory(codebase)
add_subdirectory(apis/c/mmdeploy)
add_subdirectory(apis/cxx)
endif ()
24 changes: 24 additions & 0 deletions csrc/mmdeploy/apis/cxx/CMakeLists.txt
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 ()
67 changes: 67 additions & 0 deletions csrc/mmdeploy/apis/cxx/mmdeploy/classifier.hpp
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_
145 changes: 145 additions & 0 deletions csrc/mmdeploy/apis/cxx/mmdeploy/common.hpp
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_ {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

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_
67 changes: 67 additions & 0 deletions csrc/mmdeploy/apis/cxx/mmdeploy/detector.hpp
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_
Loading