当前位置: 首页 > news >正文

如何将Python函数打包成.so库?

将Python函数打包成.so库的基本流程

  1. 安装依赖

    • 安装Cython:pip install cython
    • 安装OpenCV的Python包和开发库:
      pip install opencv-python
      # Ubuntu系统安装OpenCV开发库
      sudo apt-get install libopencv-dev
      
  2. 编写Cython代码.pyx文件):

    • 使用cdefcpdef定义C/C++接口。
    • 处理Python对象与C/C++类型的转换。
  3. 配置setup.py

    • 使用Cython.Build.cythonize编译代码。
    • 指定头文件路径和链接库(如OpenCV)。
  4. 编译生成.so文件

    • 运行 python setup.py build_ext --inplace
  5. 测试生成的库

    • 在Python中导入.so文件并调用函数。

示例:图像亮度调整库(使用OpenCV)

目录结构
project/
├── imgproc.pyx    # Cython代码
├── setup.py       # 编译配置
└── test.py        # 测试脚本

1. Cython代码(imgproc.pyx
# distutils: language=c++
# cython: language_level=3

# 导入C++标准库和OpenCV
from libcpp.string cimport string
from libc.math cimport abs
cimport numpy as np
import numpy as np

# 导入OpenCV的C++接口
cdef extern from "opencv2/opencv.hpp" namespace "cv":
    cdef cppclass Mat:
        Mat()
        int rows, cols, channels()
        uchar* data

    Mat imread(const string& filename, int flags)
    b imwrite(const string& filename, const Mat& img)
    void cvtColor(Mat& src, Mat& dst, int code)

# Python接口函数
cpdef adjust_brightness(str input_path, str output_path, float alpha=1.0, int beta=0):
    cdef string c_input = input_path.encode('utf-8')
    cdef string c_output = output_path.encode('utf-8')
    
    # 读取图像
    cdef Mat image = imread(c_input, 1)  # 1表示彩色图
    if image.rows == 0:
        raise ValueError("无法读取图像文件: " + input_path)
    
    # 调整亮度/对比度:image = alpha * image + beta
    cdef Mat adjusted_image
    image.convertTo(adjusted_image, -1, alpha, beta)
    
    # 保存图像
    if not imwrite(c_output, adjusted_image):
        raise RuntimeError("保存图像失败: " + output_path)

2. 编译配置(setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import numpy as np

# 配置OpenCV的头文件和库路径(根据系统实际路径调整)
opencv_inc = '/usr/local/include/opencv4'  # 常见路径
opencv_libdir = '/usr/local/lib'

extensions = [
    Extension(
        name="imgproc",
        sources=["imgproc.pyx"],
        language="c++",
        include_dirs=[np.get_include(), opencv_inc],
        libraries=["opencv_core", "opencv_highgui", "opencv_imgcodecs", "opencv_imgproc"],
        library_dirs=[opencv_libdir],
        extra_compile_args=["-std=c++11"],  # 启用C++11标准
    )
]

setup(ext_modules=cythonize(extensions, compiler_directives={'language_level' : "3"}))

3. 编译并测试
  1. 编译

    python setup.py build_ext --inplace
    

    生成 imgproc.cpython-xxx-linux-gnu.so

  2. 测试脚本(test.py

    import imgproc
    
    input_path = "input.jpg"
    output_path = "output.jpg"
    
    # 增加亮度(alpha=1.2,亮度增量beta=50)
    imgproc.adjust_brightness(input_path, output_path, alpha=1.2, beta=50)
    print("处理完成!")
    

常见问题与解决方案

1. 头文件找不到(fatal error: opencv2/opencv.hpp: No such file or directory
  • 原因:OpenCV开发头文件未安装或路径配置错误。
  • 解决
    # 安装OpenCV开发包
    sudo apt-get install libopencv-dev
    # 或手动指定头文件路径(修改setup.py中的opencv_inc)
    
2. 链接错误(undefined reference to cv::imread()
  • 原因:未正确链接OpenCV库(如缺少opencv_imgcodecs)。
  • 解决:检查setup.pylibraries是否包含所有依赖的OpenCV组件。
3. Python字符串到C++ string的转换错误
  • 现象:传入非字符串类型或编码错误。
  • 解决:在Cython中使用.encode('utf-8')显式转换字符串。
4. 图像保存失败(RuntimeError: 保存图像失败
  • 原因:输出路径无写入权限或格式不支持。
  • 解决:检查路径权限并使用OpenCV支持的格式(如.jpg/.png)。
5. 生成的.so文件无法导入
  • 原因:依赖的OpenCV动态库未找到。
  • 解决
    # 添加OpenCV库路径到LD_LIBRARY_PATH
    export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
    

高级优化:直接处理NumPy数组

如果需要直接传递NumPy数组(避免文件IO),需处理数据指针转换:

# 在imgproc.pyx中添加
cpdef adjust_brightness_np(np.ndarray img, float alpha=1.0, int beta=0):
    cdef Mat image
    cdef np.ndarray[np.uint8_t, ndim=3] img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)  # 确保通道顺序
    image = Mat(img_bgr.shape[0], img_bgr.shape[1], CV_8UC3, <uchar*>img_bgr.data)
    # ...处理并返回numpy数组

注意:需处理OpenCV(BGR)与NumPy(RGB)的通道顺序差异。


通过上述步骤,你可以将Python图像处理函数高效地编译为.so库,并在其他Python项目中直接调用。

相关文章:

  • 制定产品宽高比相关标准的考量维度
  • Openai Dashboard可视化微调大语言模型
  • 代码随想录算法【Day52】
  • SWAT| 水文 | SWAT模型(四):气象数据库制备(附Python代码)
  • 【Pandas】pandas Series sample
  • LeeCode题库第二十八题
  • 使用Open WebUI下载的模型文件(Model)默认存放在哪里?
  • Python strip() 方法详解:用途、应用场景及示例解析(中英双语)
  • react(9)-redux
  • Java四大框架深度剖析:MyBatis、Spring、SpringMVC与SpringBoot
  • react 踩坑记 too many re-renders.
  • Three.js 快速入门教程【七】常见几何体类型
  • ROS 2入门 - 机器人操作系统ROS2的安装
  • Mac下Python版本管理,适用于pyenv不起作用的情况
  • Dify怎么创建数据交易的智能体
  • [GESP202406 六级] 二叉树
  • [C++]使用纯opencv部署yolov12目标检测onnx模型
  • 开启开源新时代:DeepSeek引领人工智能技术开放化
  • YOLOv8与BiFormer注意力机制的融合:提升多场景目标检测性能的研究
  • Visual studio 2022 将打开文件的方式由单击改为双击
  • 赣州蓉江新区党工委原书记王凌主动交代问题,正接受审查调查
  • 首付款12.5亿美元!三生制药与辉瑞就国产双抗达成合作协议
  • 山西晋城一网红徒步野游线路据传发生驴友坠崖,当地已宣布封路
  • 种植耐旱作物、启动备用水源,甘肃各地多举措应对旱情
  • 新时代,新方志:2025上海地方志论坛暨理论研讨会举办
  • 中国新闻发言人论坛在京举行,郭嘉昆:让中国声音抢占第一落点