Python调用C++接口传入并返回图像和其他参数(有框架代码)

2024-01-09 08:32:14

python调用C++函数并传入传出图像

框架代码获取:VX搜索“晓理紫”公号,关注并回复‘c++python’即可

1、实现的功能

使用C++部署一个深度学习网络,并通过fastAPI对外提供服务。深度学习网络需要输入要推理的图像,最终返回推理结果和处理后的图像

2、C++推理端

在推理端有一个fastSAMModel类,类里面有一个推理接口detect,此函数需要输入图像等一些参数,返回处理后的图像和一些推理结果。只要是实例化fastSAMModel并调用detect函数就可以实现推理。

class fastSAMModel {
public:
  explicit fastSAMModel(const std::string &engine_file_path,
                                const int input_w, const int input_h);
  cv::Mat detect(
       cv::Mat &colorImage,
       cv::Mat &deptImage,float fx,float fy,float cx,float cy,std::vector<std::vector<float>>& objMessage);
};

3、中间层

此中间层也是有C++实现,主要作用是接收python传入的图像数据并对数据进行转换成cv::Mat格式供给推理使用;接收推理返回的参数,并把其转换成python相关格式传给python。实现如下

#include "include/fastSAMModel.h"
#include <cstring>
using namespace fastsammodel;
extern "C" {
fastSAMModel *fastSAMModel_new(const char *engine_file_path, const int input_w,
                               const int input_h) {
  return new fastSAMModel(std::string(engine_file_path), input_w, input_h);
}
void fastSAMModel_delete(fastSAMModel *obj) { delete obj; }
// python调用的接口,返回图像的数据
unsigned char *fastSAMModel_detect(fastSAMModel *obj, int colorRows,
                                   int colorCols, unsigned char *colorData,
                                   int grayRows, int grayCols,
                                   unsigned char *grayData, float fx, float fy,
                                   //以上是传入参数,以下是传出参数
                                   float cx, float cy, int *outRows,
                                   int *outCols, float **outArray,
                                   int *outArraySize) {
  //把python图像转换成cv::Mat格式
  cv::Mat colorImage(colorRows, colorCols, CV_8UC3, colorData);
  cv::Mat grayImage(grayRows, grayCols, CV_8UC1, grayData);
  // 打印输入图像的尺寸
  std::cout << "Input Color Image Size: " << colorImage.cols << " x "
            << colorImage.rows << std::endl;
  std::cout << "Input Gray Image Size: " << grayImage.cols << " x "
            << grayImage.rows << std::endl;
  // 显示接收到的彩色图像
  // cv::imshow("Received Color Image", colorImage);
  // cv::waitKey(1000); // 等待1毫秒以更新窗口
  std::vector<std::vector<float>> objMessage;
  cv::Mat processedImage =
      obj->detect(colorImage, grayImage, fx, fy, cx, cy, objMessage);

  //把返回的cv::Mat格式的图像转换成方便返回的格式
  *outRows = processedImage.rows;
  *outCols = processedImage.cols;
  size_t data_size = processedImage.total() * processedImage.elemSize();
  unsigned char *output = new unsigned char[data_size];
  std::memcpy(output, processedImage.data, data_size);

  // 转换 std::vector<std::vector<float>> 为平面数组
  int totalSize = 0;
  for (auto &subVec : objMessage) {
    totalSize += subVec.size();
  }

  *outArray = new float[totalSize]; // 分配内存
  int idx = 0;
  for (auto &subVec : objMessage) {
    for (float val : subVec) {
      (*outArray)[idx++] = val;
    }
  }
  *outArraySize = totalSize;
  return output;
}
//用于释放内存
void fastSAMModel_deleteData(unsigned char *data) { delete[] data; }
void fastSAMModel_freeMemory(float *ptr) { delete[] ptr; }
}

4、编译成动态库

编译成so动态库主要是为了python导入调用

cmake_minimum_required(VERSION 2.8.12)

set(CMAKE_CUDA_ARCHITECTURES 60 61 62 70 72 75 86)
set(CMAKE_CUDA_COMPILER /usr/local/cuda/bin/nvcc)

project(SAMModel LANGUAGES CXX CUDA)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3 -g")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_BUILD_TYPE Release)
option(CUDA_USE_STATIC_CUDA_RUNTIME OFF)

# CUDA
find_package(CUDA REQUIRED)
set(CUDA_LIBRARIES /usr/local/cuda-12.2/lib64/)
message(STATUS "CUDA Libs: \n${CUDA_LIBRARIES}\n")
message(STATUS "CUDA Headers: \n${CUDA_INCLUDE_DIRS}\n")

# OpenCV
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV Libs: \n${OpenCV_LIBS}\n")
message(STATUS "OpenCV Libraries: \n${OpenCV_LIBRARIES}\n")
message(STATUS "OpenCV Headers: \n${OpenCV_INCLUDE_DIRS}\n")

# TensorRT
set(TensorRT_INCLUDE_DIRS /usr/src/TensorRT-8.6.1.6/include)
set(TensorRT_LIBRARIES /usr/src/TensorRT-8.6.1.6/lib)


list(APPEND INCLUDE_DIRS
        ${CUDA_INCLUDE_DIRS}
        ${OpenCV_INCLUDE_DIRS}
        ${TensorRT_INCLUDE_DIRS}
        )

list(APPEND ALL_LIBS
        ${CUDA_LIBRARIES}
        ${OpenCV_LIBRARIES}
        ${TensorRT_LIBRARIES}
        )
        
include_directories(${INCLUDE_DIRS})
add_executable(detectByImage
        detectbyImage.cpp
        include/fastSAMModel.cpp
        )
target_link_directories(detectByImage PUBLIC ${ALL_LIBS})
target_link_libraries(detectByImage PUBLIC nvinfer nvinfer_plugin cudart ${OpenCV_LIBS} )

# Create a shared library from the specified source files
add_library(fastSamDet SHARED  include/fastSAMNMSbox.hpp include/fastSAMModel.cpp FastSamrWrapper.cpp)
# Link the target library against the OpenCV libraries
target_link_directories(fastSamDet PUBLIC "/usr/local/cuda-12.2/lib64/" "/usr/src/TensorRT-8.6.1.6/lib" ${OpenCV_LIBRARIES})
target_link_libraries(fastSamDet PUBLIC nvinfer nvinfer_plugin cudart ${OpenCV_LIBS})


5、python调用

5.1、首先定义C++中的数据类型

# 定义 C++ 库中结构和函数( 类)
class fastSAMModel(ctypes.Structure):
    pass

5.2、加载共享库

# 加载共享库
self.lib = ctypes.CDLL('./build/libfastSamDet.so')

5.3、设置构造函数中的参数

        # 设置构造函数和析构函数的参数类型和返回类型
        self.lib.fastSAMModel_new.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_int]
        self.lib.fastSAMModel_new.restype = ctypes.POINTER(fastSAMModel)

        self.lib.fastSAMModel_delete.argtypes = [ctypes.POINTER(fastSAMModel)]

        self.lib.fastSAMModel_detect.argtypes = [
            ctypes.POINTER(fastSAMModel), 
            ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_ubyte),
            ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_ubyte),
            ctypes.c_float, ctypes.c_float, ctypes.c_float, ctypes.c_float,
            ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int),
            ctypes.POINTER(ctypes.POINTER(ctypes.c_float)), ctypes.POINTER(ctypes.c_int)
        ]
        self.lib.fastSAMModel_detect.restype = ctypes.POINTER(ctypes.c_ubyte)

        self.lib.fastSAMModel_deleteData.argtypes = [ctypes.POINTER(ctypes.c_ubyte)]

5.4、创建实例

        # 创建模型实例
        engine_file_path = b'./build/fast_sam_1024_cpu_g.engine'
        input_w, input_h = 1024, 1024  # 示例输入尺寸
        self.model = self.lib.fastSAMModel_new(engine_file_path, input_w, input_h)

5.5、调用函数

    def fastsamDet(self,color_image,gray_image,fx, fy, cx, cy):
        # 获取图像数据
        color_data = color_image.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))
        gray_data = gray_image.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))
        # 准备输出尺寸变量
        out_rows = ctypes.c_int()
        out_cols = ctypes.c_int()

        # 准备输出参数
        outArray = ctypes.POINTER(ctypes.c_float)()
        outArraySize = ctypes.c_int()
        # 调用检测函数
        processed_data = self.lib.fastSAMModel_detect(
            self.model, color_image.shape[0], color_image.shape[1], color_data,
            gray_image.shape[0], gray_image.shape[1], gray_data,
            fx, fy, cx, cy, ctypes.byref(out_rows), ctypes.byref(out_cols),
            ctypes.byref(outArray), ctypes.byref(outArraySize)
        )
        # 将返回的数据转换为 NumPy 数组
        processed_image = np.ctypeslib.as_array(processed_data, shape=(out_rows.value, out_cols.value, 3))
        # 确保图像数据是连续的
        processed_image = np.ascontiguousarray(np.copy(processed_image), dtype=np.uint8)

        self.lib.fastSAMModel_deleteData(processed_data)
        # 将返回的数据转换为 Python 列表
        result_list = [outArray[i] for i in range(outArraySize.value)]
        # 记得释放在 C++ 中分配的内存
        self.lib.fastSAMModel_freeMemory(outArray)  # 假设你有一个专门用来释放内存的函数
        return processed_image,result_list

文章来源:https://blog.csdn.net/u011573853/article/details/135470745
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。