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

news/2025/2/22 14:30:15

将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
python">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

    python">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项目中直接调用。


http://www.niftyadmin.cn/n/5862392.html

相关文章

Unity游戏制作中的C#基础(4)数组声明和使用

一、数组的声明 在 C# 中&#xff0c;声明数组有多种方式&#xff0c;每种方式都有其适用的场景&#xff0c;下面为你逐一详细介绍&#xff1a; 1. 直接初始化声明 这种方式直观且便捷&#xff0c;在声明数组的同时就为其赋初值&#xff0c;让数组从诞生之初就拥有了具体的数据…

让浏览器AI起来:基于大模型Agent的浏览器自动化工具

最近有个非常火的项目,利用大模型Agent驱动浏览器完成各种操作,如网页搜索、爬虫分析、机票酒店预定、股票监控等,号称全面替代所有在浏览器上的操作,试用方式还是比较简单的,以下将进行简单介绍。 快速开始 通过pip安装: pip install browser-use安装web自动化框架:…

神经网络八股(三)

1.什么是梯度消失和梯度爆炸 梯度消失是指梯度在反向传播的过程中逐渐变小&#xff0c;最终趋近于零&#xff0c;这会导致靠前层的神经网络层权重参数更新缓慢&#xff0c;甚至不更新&#xff0c;学习不到有用的特征。 梯度爆炸是指梯度在方向传播过程中逐渐变大&#xff0c;…

c++ std::list使用笔记

c std::list使用笔记 1. 包含头文件2. 创建和初始化 std::list3. 添加元素4. 删除元素5. 访问元素6. 遍历 std::list7. 容量相关操作8. 其他常用操作9. 示例代码总结 std::list 是 C 标准库中的一个双向链表容器。与 std::vector 不同&#xff0c; std::list 不支持随机访问&…

单片机 Bootloade与二进制文件的生成

单片机的 Bootloader 是一种特殊的程序&#xff0c;负责在单片机上电后初始化硬件、更新用户应用程序&#xff08;固件&#xff09;&#xff0c;并将控制权移交给用户程序。以下是其运行机制和关键流程的详细说明&#xff1a; 1、单片机 Bootloader 的核心作用 固件更新&…

python入门 介绍及变量的使用

1.python介绍 python 是一门计算机语言 常见的计算机语言&#xff1a;python、java、C语言。。。 什么是计算机语言&#xff1a;就是让计算机知道你想干什么&#xff0c;把你的需求使用它能听懂的语言说出来 中国也有一门计算机语言&#xff1a;易语言 能认为是语言的本质上…

我使用windows笔记本通过远程桌面连接连接linux服务器,但是远程桌面连接显示“未启动对服务器的远程访问”,我应该怎么做才能使用笔记本连接服务器呢?

当使用 Windows 笔记本通过远程桌面连接 Linux 服务器时出现“未启动对服务器的远程访问”提示&#xff0c;可能是由于 Linux 服务器未开启远程桌面服务、防火墙限制、网络问题等原因导致。以下为你详细介绍不同的解决办法&#xff1a; 1. 在 Linux 服务器上开启远程桌面服务 …

力扣每日一题【算法学习day.131】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.用地毯覆盖后的最少白色砖块 题…