mirror of
https://github.com/PaddlePaddle/FastDeploy.git
synced 2025-10-05 16:48:03 +08:00
Refine cpp/python api of visualize with lots of deprecated apis (#303)
* fix patchelf * refine visualize api * Update CMakeLists.txt * refine visualize api * add libs directory * Create __init__.py
This commit is contained in:
@@ -66,6 +66,7 @@ option(WITH_OPENCV_STATIC "Use OpenCV static lib for Android." OFF)
|
|||||||
option(WITH_LITE_STATIC "Use Paddle-Lite static lib for Android." OFF)
|
option(WITH_LITE_STATIC "Use Paddle-Lite static lib for Android." OFF)
|
||||||
|
|
||||||
# Please don't open this flag now, some bugs exists.
|
# Please don't open this flag now, some bugs exists.
|
||||||
|
# Only support Linux Now
|
||||||
# option(ENABLE_OPENCV_CUDA "Whether to enable opencv with cuda, this will allow process image with GPU." OFF)
|
# option(ENABLE_OPENCV_CUDA "Whether to enable opencv with cuda, this will allow process image with GPU." OFF)
|
||||||
|
|
||||||
# Whether to build fastdeploy with vision/text/... examples, only for testings.
|
# Whether to build fastdeploy with vision/text/... examples, only for testings.
|
||||||
@@ -298,10 +299,13 @@ endif()
|
|||||||
if(ENABLE_VISION)
|
if(ENABLE_VISION)
|
||||||
add_definitions(-DENABLE_VISION)
|
add_definitions(-DENABLE_VISION)
|
||||||
if(ENABLE_OPENCV_CUDA)
|
if(ENABLE_OPENCV_CUDA)
|
||||||
add_definitions(-DENABLE_OPENCV_CUDA)
|
if(NOT WITH_GPU)
|
||||||
if(APPLE OR ANDROID OR IOS)
|
message(FATAL_ERROR "ENABLE_OPENCV_CUDA is available on Linux and WITH_GPU=ON, but now WITH_GPU=OFF.")
|
||||||
message(FATAL_ERROR "Cannot enable opencv with cuda in mac/ios/android os, please set -DENABLE_OPENCV_CUDA=OFF.")
|
|
||||||
endif()
|
endif()
|
||||||
|
if(APPLE OR ANDROID OR IOS OR WIN32)
|
||||||
|
message(FATAL_ERROR "Cannot enable opencv with cuda in mac/ios/android/windows os, please set -DENABLE_OPENCV_CUDA=OFF.")
|
||||||
|
endif()
|
||||||
|
add_definitions(-DENABLE_OPENCV_CUDA)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/yaml-cpp)
|
add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/yaml-cpp)
|
||||||
list(APPEND DEPEND_LIBS yaml-cpp)
|
list(APPEND DEPEND_LIBS yaml-cpp)
|
||||||
|
0
fastdeploy/libs/__init__.py
Normal file
0
fastdeploy/libs/__init__.py
Normal file
@@ -14,12 +14,96 @@
|
|||||||
|
|
||||||
#ifdef ENABLE_VISION_VISUALIZE
|
#ifdef ENABLE_VISION_VISUALIZE
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "fastdeploy/vision/visualize/visualize.h"
|
#include "fastdeploy/vision/visualize/visualize.h"
|
||||||
#include "opencv2/imgproc/imgproc.hpp"
|
#include "opencv2/imgproc/imgproc.hpp"
|
||||||
|
|
||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat VisDetection(const cv::Mat& im, const DetectionResult& result,
|
||||||
|
float score_threshold, int line_size, float font_size) {
|
||||||
|
if (result.contain_masks) {
|
||||||
|
FDASSERT(result.boxes.size() == result.masks.size(),
|
||||||
|
"The size of masks must be equal to the size of boxes, but now "
|
||||||
|
"%zu != %zu.",
|
||||||
|
result.boxes.size(), result.masks.size());
|
||||||
|
}
|
||||||
|
int max_label_id =
|
||||||
|
*std::max_element(result.label_ids.begin(), result.label_ids.end());
|
||||||
|
std::vector<int> color_map = GenerateColorMap(max_label_id);
|
||||||
|
|
||||||
|
int h = im.rows;
|
||||||
|
int w = im.cols;
|
||||||
|
auto vis_im = im.clone();
|
||||||
|
for (size_t i = 0; i < result.boxes.size(); ++i) {
|
||||||
|
if (result.scores[i] < score_threshold) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int x1 = static_cast<int>(result.boxes[i][0]);
|
||||||
|
int y1 = static_cast<int>(result.boxes[i][1]);
|
||||||
|
int x2 = static_cast<int>(result.boxes[i][2]);
|
||||||
|
int y2 = static_cast<int>(result.boxes[i][3]);
|
||||||
|
int box_h = y2 - y1;
|
||||||
|
int box_w = x2 - x1;
|
||||||
|
int c0 = color_map[3 * result.label_ids[i] + 0];
|
||||||
|
int c1 = color_map[3 * result.label_ids[i] + 1];
|
||||||
|
int c2 = color_map[3 * result.label_ids[i] + 2];
|
||||||
|
cv::Scalar rect_color = cv::Scalar(c0, c1, c2);
|
||||||
|
std::string id = std::to_string(result.label_ids[i]);
|
||||||
|
std::string score = std::to_string(result.scores[i]);
|
||||||
|
if (score.size() > 4) {
|
||||||
|
score = score.substr(0, 4);
|
||||||
|
}
|
||||||
|
std::string text = id + "," + score;
|
||||||
|
int font = cv::FONT_HERSHEY_SIMPLEX;
|
||||||
|
cv::Size text_size = cv::getTextSize(text, font, font_size, 1, nullptr);
|
||||||
|
cv::Point origin;
|
||||||
|
origin.x = x1;
|
||||||
|
origin.y = y1;
|
||||||
|
cv::Rect rect(x1, y1, box_w, box_h);
|
||||||
|
cv::rectangle(vis_im, rect, rect_color, line_size);
|
||||||
|
cv::putText(vis_im, text, origin, font, font_size,
|
||||||
|
cv::Scalar(255, 255, 255), 1);
|
||||||
|
if (result.contain_masks) {
|
||||||
|
int mask_h = static_cast<int>(result.masks[i].shape[0]);
|
||||||
|
int mask_w = static_cast<int>(result.masks[i].shape[1]);
|
||||||
|
// non-const pointer for cv:Mat constructor
|
||||||
|
int32_t* mask_raw_data = const_cast<int32_t*>(
|
||||||
|
static_cast<const int32_t*>(result.masks[i].Data()));
|
||||||
|
// only reference to mask data (zero copy)
|
||||||
|
cv::Mat mask(mask_h, mask_w, CV_32SC1, mask_raw_data);
|
||||||
|
if ((mask_h != box_h) || (mask_w != box_w)) {
|
||||||
|
cv::resize(mask, mask, cv::Size(box_w, box_h));
|
||||||
|
}
|
||||||
|
// use a bright color for instance mask
|
||||||
|
int mc0 = 255 - c0 >= 127 ? 255 - c0 : 127;
|
||||||
|
int mc1 = 255 - c1 >= 127 ? 255 - c1 : 127;
|
||||||
|
int mc2 = 255 - c2 >= 127 ? 255 - c2 : 127;
|
||||||
|
int32_t* mask_data = reinterpret_cast<int32_t*>(mask.data);
|
||||||
|
// inplace blending (zero copy)
|
||||||
|
uchar* vis_im_data = static_cast<uchar*>(vis_im.data);
|
||||||
|
for (size_t i = y1; i < y2; ++i) {
|
||||||
|
for (size_t j = x1; j < x2; ++j) {
|
||||||
|
if (mask_data[(i - y1) * mask_w + (j - x1)] != 0) {
|
||||||
|
vis_im_data[i * w * 3 + j * 3 + 0] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(mc0) * 0.5f +
|
||||||
|
static_cast<float>(vis_im_data[i * w * 3 + j * 3 + 0]) * 0.5f);
|
||||||
|
vis_im_data[i * w * 3 + j * 3 + 1] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(mc1) * 0.5f +
|
||||||
|
static_cast<float>(vis_im_data[i * w * 3 + j * 3 + 1]) * 0.5f);
|
||||||
|
vis_im_data[i * w * 3 + j * 3 + 2] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(mc2) * 0.5f +
|
||||||
|
static_cast<float>(vis_im_data[i * w * 3 + j * 3 + 2]) * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vis_im;
|
||||||
|
}
|
||||||
|
|
||||||
// Default only support visualize num_classes <= 1000
|
// Default only support visualize num_classes <= 1000
|
||||||
// If need to visualize num_classes > 1000
|
// If need to visualize num_classes > 1000
|
||||||
// Please call Visualize::GetColorMap(num_classes) first
|
// Please call Visualize::GetColorMap(num_classes) first
|
||||||
@@ -27,6 +111,10 @@ cv::Mat Visualize::VisDetection(const cv::Mat& im,
|
|||||||
const DetectionResult& result,
|
const DetectionResult& result,
|
||||||
float score_threshold, int line_size,
|
float score_threshold, int line_size,
|
||||||
float font_size) {
|
float font_size) {
|
||||||
|
FDWARNING << "DEPRECATED: fastdeploy::vision::Visualize::VisDetection is "
|
||||||
|
"deprecated, please use fastdeploy::vision:VisDetection "
|
||||||
|
"function instead."
|
||||||
|
<< std::endl;
|
||||||
if (result.contain_masks) {
|
if (result.contain_masks) {
|
||||||
FDASSERT(result.boxes.size() == result.masks.size(),
|
FDASSERT(result.boxes.size() == result.masks.size(),
|
||||||
"The size of masks must be equal the size of boxes!");
|
"The size of masks must be equal the size of boxes!");
|
||||||
|
@@ -21,12 +21,69 @@ namespace fastdeploy {
|
|||||||
|
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat VisFaceDetection(const cv::Mat& im, const FaceDetectionResult& result,
|
||||||
|
int line_size, float font_size) {
|
||||||
|
auto color_map = GenerateColorMap();
|
||||||
|
int h = im.rows;
|
||||||
|
int w = im.cols;
|
||||||
|
|
||||||
|
auto vis_im = im.clone();
|
||||||
|
bool vis_landmarks = false;
|
||||||
|
if ((result.landmarks_per_face > 0) &&
|
||||||
|
(result.boxes.size() * result.landmarks_per_face ==
|
||||||
|
result.landmarks.size())) {
|
||||||
|
vis_landmarks = true;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < result.boxes.size(); ++i) {
|
||||||
|
cv::Rect rect(result.boxes[i][0], result.boxes[i][1],
|
||||||
|
result.boxes[i][2] - result.boxes[i][0],
|
||||||
|
result.boxes[i][3] - result.boxes[i][1]);
|
||||||
|
int color_id = i % 333;
|
||||||
|
int c0 = color_map[3 * color_id + 0];
|
||||||
|
int c1 = color_map[3 * color_id + 1];
|
||||||
|
int c2 = color_map[3 * color_id + 2];
|
||||||
|
cv::Scalar rect_color = cv::Scalar(c0, c1, c2);
|
||||||
|
std::string text = std::to_string(result.scores[i]);
|
||||||
|
if (text.size() > 4) {
|
||||||
|
text = text.substr(0, 4);
|
||||||
|
}
|
||||||
|
int font = cv::FONT_HERSHEY_SIMPLEX;
|
||||||
|
cv::Size text_size = cv::getTextSize(text, font, font_size, 1, nullptr);
|
||||||
|
cv::Point origin;
|
||||||
|
origin.x = rect.x;
|
||||||
|
origin.y = rect.y;
|
||||||
|
cv::Rect text_background =
|
||||||
|
cv::Rect(result.boxes[i][0], result.boxes[i][1] - text_size.height,
|
||||||
|
text_size.width, text_size.height);
|
||||||
|
cv::rectangle(vis_im, rect, rect_color, line_size);
|
||||||
|
cv::putText(vis_im, text, origin, font, font_size,
|
||||||
|
cv::Scalar(255, 255, 255), 1);
|
||||||
|
// vis landmarks (if have)
|
||||||
|
if (vis_landmarks) {
|
||||||
|
cv::Scalar landmark_color = rect_color;
|
||||||
|
for (size_t j = 0; j < result.landmarks_per_face; ++j) {
|
||||||
|
cv::Point landmark;
|
||||||
|
landmark.x = static_cast<int>(
|
||||||
|
result.landmarks[i * result.landmarks_per_face + j][0]);
|
||||||
|
landmark.y = static_cast<int>(
|
||||||
|
result.landmarks[i * result.landmarks_per_face + j][1]);
|
||||||
|
cv::circle(vis_im, landmark, line_size, landmark_color, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vis_im;
|
||||||
|
}
|
||||||
|
|
||||||
// Default only support visualize num_classes <= 1000
|
// Default only support visualize num_classes <= 1000
|
||||||
// If need to visualize num_classes > 1000
|
// If need to visualize num_classes > 1000
|
||||||
// Please call Visualize::GetColorMap(num_classes) first
|
// Please call Visualize::GetColorMap(num_classes) first
|
||||||
cv::Mat Visualize::VisFaceDetection(const cv::Mat& im,
|
cv::Mat Visualize::VisFaceDetection(const cv::Mat& im,
|
||||||
const FaceDetectionResult& result,
|
const FaceDetectionResult& result,
|
||||||
int line_size, float font_size) {
|
int line_size, float font_size) {
|
||||||
|
FDWARNING << "DEPRECATED: fastdeploy::vision::Visualize::VisFaceDetection is "
|
||||||
|
"deprecated, please use fastdeploy::vision:VisFaceDetection "
|
||||||
|
"function instead."
|
||||||
|
<< std::endl;
|
||||||
auto color_map = GetColorMap();
|
auto color_map = GetColorMap();
|
||||||
int h = im.rows;
|
int h = im.rows;
|
||||||
int w = im.cols;
|
int w = im.cols;
|
||||||
|
@@ -21,9 +21,59 @@
|
|||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat VisMatting(const cv::Mat& im, const MattingResult& result,
|
||||||
|
bool remove_small_connected_area) {
|
||||||
|
FDASSERT((!im.empty()), "im can't be empty!");
|
||||||
|
FDASSERT((im.channels() == 3), "Only support 3 channels mat!");
|
||||||
|
|
||||||
|
auto vis_img = im.clone();
|
||||||
|
int out_h = static_cast<int>(result.shape[0]);
|
||||||
|
int out_w = static_cast<int>(result.shape[1]);
|
||||||
|
int height = im.rows;
|
||||||
|
int width = im.cols;
|
||||||
|
std::vector<float> alpha_copy;
|
||||||
|
alpha_copy.assign(result.alpha.begin(), result.alpha.end());
|
||||||
|
float* alpha_ptr = static_cast<float*>(alpha_copy.data());
|
||||||
|
cv::Mat alpha(out_h, out_w, CV_32FC1, alpha_ptr);
|
||||||
|
if (remove_small_connected_area) {
|
||||||
|
alpha = RemoveSmallConnectedArea(alpha, 0.05f);
|
||||||
|
}
|
||||||
|
if ((out_h != height) || (out_w != width)) {
|
||||||
|
cv::resize(alpha, alpha, cv::Size(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((vis_img).type() != CV_8UC3) {
|
||||||
|
(vis_img).convertTo((vis_img), CV_8UC3);
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar* vis_data = static_cast<uchar*>(vis_img.data);
|
||||||
|
uchar* im_data = static_cast<uchar*>(im.data);
|
||||||
|
float* alpha_data = reinterpret_cast<float*>(alpha.data);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < height; ++i) {
|
||||||
|
for (size_t j = 0; j < width; ++j) {
|
||||||
|
float alpha_val = alpha_data[i * width + j];
|
||||||
|
vis_data[i * width * 3 + j * 3 + 0] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(im_data[i * width * 3 + j * 3 + 0]) * alpha_val +
|
||||||
|
(1.f - alpha_val) * 153.f);
|
||||||
|
vis_data[i * width * 3 + j * 3 + 1] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(im_data[i * width * 3 + j * 3 + 1]) * alpha_val +
|
||||||
|
(1.f - alpha_val) * 255.f);
|
||||||
|
vis_data[i * width * 3 + j * 3 + 2] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(im_data[i * width * 3 + j * 3 + 2]) * alpha_val +
|
||||||
|
(1.f - alpha_val) * 120.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vis_img;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat Visualize::VisMattingAlpha(const cv::Mat& im,
|
cv::Mat Visualize::VisMattingAlpha(const cv::Mat& im,
|
||||||
const MattingResult& result,
|
const MattingResult& result,
|
||||||
bool remove_small_connected_area) {
|
bool remove_small_connected_area) {
|
||||||
|
FDWARNING << "DEPRECATED: fastdeploy::vision::Visualize::VisMattingAlpha is "
|
||||||
|
"deprecated, please use fastdeploy::vision:VisMatting function "
|
||||||
|
"instead."
|
||||||
|
<< std::endl;
|
||||||
FDASSERT((!im.empty()), "im can't be empty!");
|
FDASSERT((!im.empty()), "im can't be empty!");
|
||||||
FDASSERT((im.channels() == 3), "Only support 3 channels mat!");
|
FDASSERT((im.channels() == 3), "Only support 3 channels mat!");
|
||||||
|
|
@@ -20,7 +20,30 @@
|
|||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat VisOcr(const cv::Mat &im, const OCRResult &ocr_result) {
|
||||||
|
auto vis_im = im.clone();
|
||||||
|
|
||||||
|
for (int n = 0; n < ocr_result.boxes.size(); n++) {
|
||||||
|
cv::Point rook_points[4];
|
||||||
|
|
||||||
|
for (int m = 0; m < 4; m++) {
|
||||||
|
rook_points[m] = cv::Point(int(ocr_result.boxes[n][m * 2]),
|
||||||
|
int(ocr_result.boxes[n][m * 2 + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const cv::Point *ppt[1] = {rook_points};
|
||||||
|
int npt[] = {4};
|
||||||
|
cv::polylines(vis_im, ppt, npt, 1, 1, CV_RGB(0, 255, 0), 2, 8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vis_im;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat Visualize::VisOcr(const cv::Mat &im, const OCRResult &ocr_result) {
|
cv::Mat Visualize::VisOcr(const cv::Mat &im, const OCRResult &ocr_result) {
|
||||||
|
FDWARNING
|
||||||
|
<< "DEPRECATED: fastdeploy::vision::Visualize::VisOcr is deprecated, "
|
||||||
|
"please use fastdeploy::vision:VisOcr function instead."
|
||||||
|
<< std::endl;
|
||||||
auto vis_im = im.clone();
|
auto vis_im = im.clone();
|
||||||
|
|
||||||
for (int n = 0; n < ocr_result.boxes.size(); n++) {
|
for (int n = 0; n < ocr_result.boxes.size(); n++) {
|
||||||
|
@@ -21,6 +21,49 @@
|
|||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat RemoveSmallConnectedArea(const cv::Mat& alpha_pred, float threshold) {
|
||||||
|
cv::Mat gray, binary;
|
||||||
|
alpha_pred.convertTo(gray, CV_8UC1, 255.f);
|
||||||
|
cv::Mat alpha_pred_clone = alpha_pred.clone();
|
||||||
|
// 255 * 0.05 ~ 13
|
||||||
|
unsigned int binary_threshold = static_cast<unsigned int>(255.f * threshold);
|
||||||
|
cv::threshold(gray, binary, binary_threshold, 255, cv::THRESH_BINARY);
|
||||||
|
// morphologyEx with OPEN operation to remove noise first.
|
||||||
|
auto kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3),
|
||||||
|
cv::Point(-1, -1));
|
||||||
|
cv::morphologyEx(binary, binary, cv::MORPH_OPEN, kernel);
|
||||||
|
// Computationally connected domain
|
||||||
|
cv::Mat labels = cv::Mat::zeros(alpha_pred_clone.size(), CV_32S);
|
||||||
|
cv::Mat stats, centroids;
|
||||||
|
int num_labels =
|
||||||
|
cv::connectedComponentsWithStats(binary, labels, stats, centroids, 8, 4);
|
||||||
|
if (num_labels <= 1) {
|
||||||
|
// no noise, skip.
|
||||||
|
return alpha_pred;
|
||||||
|
}
|
||||||
|
// find max connected area, 0 is background
|
||||||
|
int max_connected_id = 1; // 1,2,...
|
||||||
|
int max_connected_area = stats.at<int>(max_connected_id, cv::CC_STAT_AREA);
|
||||||
|
for (int i = 1; i < num_labels; ++i) {
|
||||||
|
int tmp_connected_area = stats.at<int>(i, cv::CC_STAT_AREA);
|
||||||
|
if (tmp_connected_area > max_connected_area) {
|
||||||
|
max_connected_area = tmp_connected_area;
|
||||||
|
max_connected_id = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int h = alpha_pred_clone.rows;
|
||||||
|
const int w = alpha_pred_clone.cols;
|
||||||
|
// remove small connected area.
|
||||||
|
for (int i = 0; i < h; ++i) {
|
||||||
|
int* label_row_ptr = labels.ptr<int>(i);
|
||||||
|
float* alpha_row_ptr = alpha_pred_clone.ptr<float>(i);
|
||||||
|
for (int j = 0; j < w; ++j) {
|
||||||
|
if (label_row_ptr[j] != max_connected_id) alpha_row_ptr[j] = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alpha_pred_clone;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat Visualize::RemoveSmallConnectedArea(const cv::Mat& alpha_pred,
|
cv::Mat Visualize::RemoveSmallConnectedArea(const cv::Mat& alpha_pred,
|
||||||
float threshold) {
|
float threshold) {
|
||||||
cv::Mat gray, binary;
|
cv::Mat gray, binary;
|
||||||
@@ -67,4 +110,4 @@ cv::Mat Visualize::RemoveSmallConnectedArea(const cv::Mat& alpha_pred,
|
|||||||
|
|
||||||
} // namespace vision
|
} // namespace vision
|
||||||
} // namespace fastdeploy
|
} // namespace fastdeploy
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,8 +21,32 @@
|
|||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat VisSegmentation(const cv::Mat& im, const SegmentationResult& result,
|
||||||
|
float weight) {
|
||||||
|
auto color_map = GenerateColorMap(1000);
|
||||||
|
int64_t height = result.shape[0];
|
||||||
|
int64_t width = result.shape[1];
|
||||||
|
auto vis_img = cv::Mat(height, width, CV_8UC3);
|
||||||
|
|
||||||
|
int64_t index = 0;
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
int category_id = result.label_map[index++];
|
||||||
|
vis_img.at<cv::Vec3b>(i, j)[0] = color_map[3 * category_id + 0];
|
||||||
|
vis_img.at<cv::Vec3b>(i, j)[1] = color_map[3 * category_id + 1];
|
||||||
|
vis_img.at<cv::Vec3b>(i, j)[2] = color_map[3 * category_id + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cv::addWeighted(im, 1.0 - weight, vis_img, weight, 0, vis_img);
|
||||||
|
return vis_img;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat Visualize::VisSegmentation(const cv::Mat& im,
|
cv::Mat Visualize::VisSegmentation(const cv::Mat& im,
|
||||||
const SegmentationResult& result) {
|
const SegmentationResult& result) {
|
||||||
|
FDWARNING << "DEPRECATED: fastdeploy::vision::Visualize::VisSegmentation is "
|
||||||
|
"deprecated, please use fastdeploy::vision:VisSegmentation "
|
||||||
|
"function instead."
|
||||||
|
<< std::endl;
|
||||||
auto color_map = GetColorMap();
|
auto color_map = GetColorMap();
|
||||||
int64_t height = result.shape[0];
|
int64_t height = result.shape[0];
|
||||||
int64_t width = result.shape[1];
|
int64_t width = result.shape[1];
|
||||||
|
@@ -21,6 +21,104 @@
|
|||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
cv::Mat SwapBackground(const cv::Mat& im, const cv::Mat& background,
|
||||||
|
const MattingResult& result,
|
||||||
|
bool remove_small_connected_area) {
|
||||||
|
FDASSERT((!im.empty()), "Image can't be empty!");
|
||||||
|
FDASSERT((im.channels() == 3), "Only support 3 channels image mat!");
|
||||||
|
FDASSERT((!background.empty()), "Background image can't be empty!");
|
||||||
|
FDASSERT((background.channels() == 3),
|
||||||
|
"Only support 3 channels background image mat!");
|
||||||
|
auto vis_img = im.clone();
|
||||||
|
auto background_copy = background.clone();
|
||||||
|
int out_h = static_cast<int>(result.shape[0]);
|
||||||
|
int out_w = static_cast<int>(result.shape[1]);
|
||||||
|
int height = im.rows;
|
||||||
|
int width = im.cols;
|
||||||
|
int bg_height = background.rows;
|
||||||
|
int bg_width = background.cols;
|
||||||
|
std::vector<float> alpha_copy;
|
||||||
|
alpha_copy.assign(result.alpha.begin(), result.alpha.end());
|
||||||
|
float* alpha_ptr = static_cast<float*>(alpha_copy.data());
|
||||||
|
cv::Mat alpha(out_h, out_w, CV_32FC1, alpha_ptr);
|
||||||
|
if (remove_small_connected_area) {
|
||||||
|
alpha = Visualize::RemoveSmallConnectedArea(alpha, 0.05f);
|
||||||
|
}
|
||||||
|
if ((vis_img).type() != CV_8UC3) {
|
||||||
|
(vis_img).convertTo((vis_img), CV_8UC3);
|
||||||
|
}
|
||||||
|
if ((background_copy).type() != CV_8UC3) {
|
||||||
|
(background_copy).convertTo((background_copy), CV_8UC3);
|
||||||
|
}
|
||||||
|
if ((bg_height != height) || (bg_width != width)) {
|
||||||
|
cv::resize(background, background_copy, cv::Size(width, height));
|
||||||
|
}
|
||||||
|
if ((out_h != height) || (out_w != width)) {
|
||||||
|
cv::resize(alpha, alpha, cv::Size(width, height));
|
||||||
|
}
|
||||||
|
uchar* vis_data = static_cast<uchar*>(vis_img.data);
|
||||||
|
uchar* background_data = static_cast<uchar*>(background_copy.data);
|
||||||
|
uchar* im_data = static_cast<uchar*>(im.data);
|
||||||
|
float* alpha_data = reinterpret_cast<float*>(alpha.data);
|
||||||
|
for (size_t i = 0; i < height; ++i) {
|
||||||
|
for (size_t j = 0; j < width; ++j) {
|
||||||
|
float alpha_val = alpha_data[i * width + j];
|
||||||
|
for (size_t c = 0; c < 3; ++c) {
|
||||||
|
vis_data[i * width * 3 + j * 3 + c] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(im_data[i * width * 3 + j * 3 + c]) * alpha_val +
|
||||||
|
(1.f - alpha_val) * background_data[i * width * 3 + j * 3 + c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vis_img;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat SwapBackground(const cv::Mat& im, const cv::Mat& background,
|
||||||
|
const SegmentationResult& result, int background_label) {
|
||||||
|
FDASSERT((!im.empty()), "Image can't be empty!");
|
||||||
|
FDASSERT((im.channels() == 3), "Only support 3 channels image mat!");
|
||||||
|
FDASSERT((!background.empty()), "Background image can't be empty!");
|
||||||
|
FDASSERT((background.channels() == 3),
|
||||||
|
"Only support 3 channels background image mat!");
|
||||||
|
auto vis_img = im.clone();
|
||||||
|
auto background_copy = background.clone();
|
||||||
|
int height = im.rows;
|
||||||
|
int width = im.cols;
|
||||||
|
int bg_height = background.rows;
|
||||||
|
int bg_width = background.cols;
|
||||||
|
if ((vis_img).type() != CV_8UC3) {
|
||||||
|
(vis_img).convertTo((vis_img), CV_8UC3);
|
||||||
|
}
|
||||||
|
if ((background_copy).type() != CV_8UC3) {
|
||||||
|
(background_copy).convertTo((background_copy), CV_8UC3);
|
||||||
|
}
|
||||||
|
if ((bg_height != height) || (bg_width != width)) {
|
||||||
|
cv::resize(background, background_copy, cv::Size(width, height));
|
||||||
|
}
|
||||||
|
uchar* vis_data = static_cast<uchar*>(vis_img.data);
|
||||||
|
uchar* background_data = static_cast<uchar*>(background_copy.data);
|
||||||
|
uchar* im_data = static_cast<uchar*>(im.data);
|
||||||
|
float keep_value = 0.f;
|
||||||
|
for (size_t i = 0; i < height; ++i) {
|
||||||
|
for (size_t j = 0; j < width; ++j) {
|
||||||
|
int category_id = result.label_map[i * width + j];
|
||||||
|
if (background_label != category_id) {
|
||||||
|
keep_value = 1.0f;
|
||||||
|
} else {
|
||||||
|
keep_value = 0.f;
|
||||||
|
}
|
||||||
|
for (size_t c = 0; c < 3; ++c) {
|
||||||
|
vis_data[i * width * 3 + j * 3 + c] = cv::saturate_cast<uchar>(
|
||||||
|
static_cast<float>(im_data[i * width * 3 + j * 3 + c]) *
|
||||||
|
keep_value +
|
||||||
|
(1.f - keep_value) * background_data[i * width * 3 + j * 3 + c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vis_img;
|
||||||
|
}
|
||||||
|
|
||||||
cv::Mat Visualize::SwapBackgroundMatting(const cv::Mat& im,
|
cv::Mat Visualize::SwapBackgroundMatting(const cv::Mat& im,
|
||||||
const cv::Mat& background,
|
const cv::Mat& background,
|
||||||
const MattingResult& result,
|
const MattingResult& result,
|
||||||
@@ -123,4 +221,4 @@ cv::Mat Visualize::SwapBackgroundSegmentation(
|
|||||||
|
|
||||||
} // namespace vision
|
} // namespace vision
|
||||||
} // namespace fastdeploy
|
} // namespace fastdeploy
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,6 +21,24 @@ namespace vision {
|
|||||||
int Visualize::num_classes_ = 0;
|
int Visualize::num_classes_ = 0;
|
||||||
std::vector<int> Visualize::color_map_ = std::vector<int>();
|
std::vector<int> Visualize::color_map_ = std::vector<int>();
|
||||||
|
|
||||||
|
static std::vector<int> global_fd_vis_color_map = std::vector<int>();
|
||||||
|
|
||||||
|
std::vector<int> GenerateColorMap(int num_classes) {
|
||||||
|
std::vector<int> color_map(num_classes * 3, 0);
|
||||||
|
for (int i = 0; i < num_classes; ++i) {
|
||||||
|
int j = 0;
|
||||||
|
int lab = i;
|
||||||
|
while (lab) {
|
||||||
|
color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j));
|
||||||
|
color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j));
|
||||||
|
color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j));
|
||||||
|
++j;
|
||||||
|
lab >>= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return color_map;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<int>& Visualize::GetColorMap(int num_classes) {
|
const std::vector<int>& Visualize::GetColorMap(int num_classes) {
|
||||||
if (num_classes < num_classes_) {
|
if (num_classes < num_classes_) {
|
||||||
return color_map_;
|
return color_map_;
|
||||||
@@ -42,6 +60,6 @@ const std::vector<int>& Visualize::GetColorMap(int num_classes) {
|
|||||||
return color_map_;
|
return color_map_;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vision
|
} // namespace vision
|
||||||
} // namespace fastdeploy
|
} // namespace fastdeploy
|
||||||
#endif
|
#endif
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
namespace vision {
|
namespace vision {
|
||||||
|
|
||||||
|
// This class will deprecated, please not use it
|
||||||
class FASTDEPLOY_DECL Visualize {
|
class FASTDEPLOY_DECL Visualize {
|
||||||
public:
|
public:
|
||||||
static int num_classes_;
|
static int num_classes_;
|
||||||
@@ -47,6 +48,31 @@ class FASTDEPLOY_DECL Visualize {
|
|||||||
static cv::Mat VisOcr(const cv::Mat& srcimg, const OCRResult& ocr_result);
|
static cv::Mat VisOcr(const cv::Mat& srcimg, const OCRResult& ocr_result);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<int> GenerateColorMap(int num_classes = 1000);
|
||||||
|
cv::Mat RemoveSmallConnectedArea(const cv::Mat& alpha_pred, float threshold);
|
||||||
|
FASTDEPLOY_DECL cv::Mat VisDetection(const cv::Mat& im,
|
||||||
|
const DetectionResult& result,
|
||||||
|
float score_threshold = 0.0,
|
||||||
|
int line_size = 1, float font_size = 0.5f);
|
||||||
|
FASTDEPLOY_DECL cv::Mat VisFaceDetection(const cv::Mat& im,
|
||||||
|
const FaceDetectionResult& result,
|
||||||
|
int line_size = 1,
|
||||||
|
float font_size = 0.5f);
|
||||||
|
FASTDEPLOY_DECL cv::Mat VisSegmentation(const cv::Mat& im,
|
||||||
|
const SegmentationResult& result,
|
||||||
|
float weight = 0.5);
|
||||||
|
FASTDEPLOY_DECL cv::Mat VisMatting(const cv::Mat& im,
|
||||||
|
const MattingResult& result,
|
||||||
|
bool remove_small_connected_area = false);
|
||||||
|
FASTDEPLOY_DECL cv::Mat VisOcr(const cv::Mat& im, const OCRResult& ocr_result);
|
||||||
|
FASTDEPLOY_DECL cv::Mat SwapBackground(
|
||||||
|
const cv::Mat& im, const cv::Mat& background, const MattingResult& result,
|
||||||
|
bool remove_small_connected_area = false);
|
||||||
|
FASTDEPLOY_DECL cv::Mat SwapBackground(const cv::Mat& im,
|
||||||
|
const cv::Mat& background,
|
||||||
|
const SegmentationResult& result,
|
||||||
|
int background_label);
|
||||||
|
|
||||||
} // namespace vision
|
} // namespace vision
|
||||||
} // namespace fastdeploy
|
} // namespace fastdeploy
|
||||||
#endif
|
#endif
|
||||||
|
@@ -16,6 +16,76 @@
|
|||||||
|
|
||||||
namespace fastdeploy {
|
namespace fastdeploy {
|
||||||
void BindVisualize(pybind11::module& m) {
|
void BindVisualize(pybind11::module& m) {
|
||||||
|
m.def("vis_detection",
|
||||||
|
[](pybind11::array& im_data, vision::DetectionResult& result,
|
||||||
|
float score_threshold, int line_size, float font_size) {
|
||||||
|
auto im = PyArrayToCvMat(im_data);
|
||||||
|
auto vis_im = vision::VisDetection(im, result, score_threshold,
|
||||||
|
line_size, font_size);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
})
|
||||||
|
.def("vis_face_detection",
|
||||||
|
[](pybind11::array& im_data, vision::FaceDetectionResult& result,
|
||||||
|
int line_size, float font_size) {
|
||||||
|
auto im = PyArrayToCvMat(im_data);
|
||||||
|
auto vis_im =
|
||||||
|
vision::VisFaceDetection(im, result, line_size, font_size);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
})
|
||||||
|
.def("vis_segmentation",
|
||||||
|
[](pybind11::array& im_data, vision::SegmentationResult& result,
|
||||||
|
float weight) {
|
||||||
|
cv::Mat im = PyArrayToCvMat(im_data);
|
||||||
|
auto vis_im = vision::VisSegmentation(im, result, weight);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
})
|
||||||
|
.def("swap_background",
|
||||||
|
[](pybind11::array& im_data, pybind11::array& background_data,
|
||||||
|
vision::MattingResult& result, bool remove_small_connected_area) {
|
||||||
|
cv::Mat im = PyArrayToCvMat(im_data);
|
||||||
|
cv::Mat background = PyArrayToCvMat(background_data);
|
||||||
|
auto vis_im = vision::SwapBackground(im, background, result,
|
||||||
|
remove_small_connected_area);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
})
|
||||||
|
.def("swap_background",
|
||||||
|
[](pybind11::array& im_data, pybind11::array& background_data,
|
||||||
|
vision::SegmentationResult& result, int background_label) {
|
||||||
|
cv::Mat im = PyArrayToCvMat(im_data);
|
||||||
|
cv::Mat background = PyArrayToCvMat(background_data);
|
||||||
|
auto vis_im = vision::SwapBackground(im, background, result,
|
||||||
|
background_label);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
})
|
||||||
|
.def("vis_ppocr",
|
||||||
|
[](pybind11::array& im_data, vision::OCRResult& result) {
|
||||||
|
auto im = PyArrayToCvMat(im_data);
|
||||||
|
auto vis_im = vision::VisOcr(im, result);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
})
|
||||||
|
.def("vis_matting",
|
||||||
|
[](pybind11::array& im_data, vision::MattingResult& result,
|
||||||
|
bool remove_small_connected_area) {
|
||||||
|
cv::Mat im = PyArrayToCvMat(im_data);
|
||||||
|
auto vis_im =
|
||||||
|
vision::VisMatting(im, result, remove_small_connected_area);
|
||||||
|
FDTensor out;
|
||||||
|
vision::Mat(vis_im).ShareWithTensor(&out);
|
||||||
|
return TensorToPyArray(out);
|
||||||
|
});
|
||||||
|
|
||||||
pybind11::class_<vision::Visualize>(m, "Visualize")
|
pybind11::class_<vision::Visualize>(m, "Visualize")
|
||||||
.def(pybind11::init<>())
|
.def(pybind11::init<>())
|
||||||
.def_static("vis_detection",
|
.def_static("vis_detection",
|
||||||
|
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
@@ -22,39 +22,51 @@ def vis_detection(im_data,
|
|||||||
score_threshold=0.0,
|
score_threshold=0.0,
|
||||||
line_size=1,
|
line_size=1,
|
||||||
font_size=0.5):
|
font_size=0.5):
|
||||||
return C.vision.Visualize.vis_detection(
|
return C.vision.vis_detection(im_data, det_result, score_threshold,
|
||||||
im_data, det_result, score_threshold, line_size, font_size)
|
line_size, font_size)
|
||||||
|
|
||||||
|
|
||||||
def vis_face_detection(im_data, face_det_result, line_size=1, font_size=0.5):
|
def vis_face_detection(im_data, face_det_result, line_size=1, font_size=0.5):
|
||||||
return C.vision.Visualize.vis_face_detection(im_data, face_det_result,
|
return C.vision.vis_face_detection(im_data, face_det_result, line_size,
|
||||||
line_size, font_size)
|
font_size)
|
||||||
|
|
||||||
|
|
||||||
def vis_segmentation(im_data, seg_result):
|
def vis_segmentation(im_data, seg_result):
|
||||||
return C.vision.Visualize.vis_segmentation(im_data, seg_result)
|
return C.vision.vis_segmentation(im_data, seg_result)
|
||||||
|
|
||||||
|
|
||||||
def vis_matting_alpha(im_data,
|
def vis_matting_alpha(im_data,
|
||||||
matting_result,
|
matting_result,
|
||||||
remove_small_connected_area=False):
|
remove_small_connected_area=False):
|
||||||
return C.vision.Visualize.vis_matting_alpha(im_data, matting_result,
|
logging.warning(
|
||||||
remove_small_connected_area)
|
"DEPRECATED: fastdeploy.vision.vis_matting_alpha is deprecated, please use fastdeploy.vision.vis_matting function instead."
|
||||||
|
)
|
||||||
|
return C.vision.vis_matting(im_data, matting_result,
|
||||||
|
remove_small_connected_area)
|
||||||
|
|
||||||
|
|
||||||
|
def vis_matting(im_data, matting_result, remove_small_connected_area=False):
|
||||||
|
return C.vision.vis_matting(im_data, matting_result,
|
||||||
|
remove_small_connected_area)
|
||||||
|
|
||||||
|
|
||||||
def swap_background_matting(im_data,
|
def swap_background_matting(im_data,
|
||||||
background,
|
background,
|
||||||
result,
|
result,
|
||||||
remove_small_connected_area=False):
|
remove_small_connected_area=False):
|
||||||
|
logging.warning(
|
||||||
|
"DEPRECATED: fastdeploy.vision.swap_background_matting is deprecated, please use fastdeploy.vision.swap_background function instead."
|
||||||
|
)
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
result,
|
result, C.vision.MattingResult), "The result must be MattingResult type"
|
||||||
C.vision.MattingResult), "The result must be MattingResult type"
|
|
||||||
return C.vision.Visualize.swap_background_matting(
|
return C.vision.Visualize.swap_background_matting(
|
||||||
im_data, background, result, remove_small_connected_area)
|
im_data, background, result, remove_small_connected_area)
|
||||||
|
|
||||||
|
|
||||||
def swap_background_segmentation(im_data, background, background_label,
|
def swap_background_segmentation(im_data, background, background_label, result):
|
||||||
result):
|
logging.warning(
|
||||||
|
"DEPRECATED: fastdeploy.vision.swap_background_segmentation is deprecated, please use fastdeploy.vision.swap_background function instead."
|
||||||
|
)
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
result, C.vision.
|
result, C.vision.
|
||||||
SegmentationResult), "The result must be SegmentaitonResult type"
|
SegmentationResult), "The result must be SegmentaitonResult type"
|
||||||
@@ -62,9 +74,22 @@ def swap_background_segmentation(im_data, background, background_label,
|
|||||||
im_data, background, background_label, result)
|
im_data, background, background_label, result)
|
||||||
|
|
||||||
|
|
||||||
def remove_small_connected_area(alpha_pred_data, threshold):
|
def swap_background(im_data,
|
||||||
assert len(alpha_pred_data.shape) == 3, "alpha has a (h, w, 1) shape"
|
background,
|
||||||
return C.vision.Visualize.remove_small_connected_area(alpha_pred_data,
|
result,
|
||||||
threshold)
|
remove_small_connected_area=False,
|
||||||
|
background_label=0):
|
||||||
|
if isinstance(result, C.vision.MattingResult):
|
||||||
|
return C.vision.swap_background(im_data, background, result,
|
||||||
|
remove_small_connected_area)
|
||||||
|
elif isinstance(result, C.vision.SegmentationResult):
|
||||||
|
return C.vision.swap_background(im_data, background, result,
|
||||||
|
background_label)
|
||||||
|
else:
|
||||||
|
raise Exception(
|
||||||
|
"Only support result type of MattingResult or SegmentationResult, but now the data type is {}.".
|
||||||
|
format(type(result)))
|
||||||
|
|
||||||
|
|
||||||
def vis_ppocr(im_data, det_result):
|
def vis_ppocr(im_data, det_result):
|
||||||
return C.vision.Visualize.vis_ppocr(im_data, det_result)
|
return C.vision.vis_ppocr(im_data, det_result)
|
||||||
|
Reference in New Issue
Block a user