如何将特定的C模块移植到python3?

2024-09-30 00:35:57 发布

您现在位置:Python中文网/ 问答频道 /正文

有一个thinningpip包,目前只使用Python2编译。在

当我用sudo pip install thinning安装它,然后尝试import thinning时,我得到一个错误:

ImportError: /usr/lib/python3.5/site-packages/thinning.cpython-35m-x86_64-linux-gnu.so: undefined symbol: Py_InitModule3

我想这是因为Python3不再使用Py_InitModule3。 以下是完整的c源文件:

^{pr2}$

我已经开始读Porting Extension Modules to Python 3,但我必须承认我几乎听不懂。在

我试图通过一些其他代码调整将Py_InitModule更改为python3模拟PyModule_Create,但没有成功。不幸的是,这个细化模块对我们的应用程序来说是一个很难依赖的模块。所以,我现在很困惑,没有时间和知识如何将这个模块移植到Python3。在


Tags: 模块installpippyimportlibusr错误
1条回答
网友
1楼 · 发布于 2024-09-30 00:35:57

发生了什么变化:

注意:我无法真正深入了解guo_hall_thinning函数本身的功能。我所知道的是,它使用numpy C-API的一小部分来获取和返回作为ndarray的数据;我找不到任何关于它们的文档被修改,所以应该可以继续使用。在

现在,确实改变了模块的初始化方式;通过这一点,我可以帮助您将其导入到Python3发行版中。我也在使用3.5来实现这一点,尽管我相信3.x家族的老版本之间的差异不应该存在于或者是向后兼容的。在

如您所述,一般信息在Porting to Python 3文档中提供,其中包含有关Module Initialization and state中初始化阶段的详细信息。新的变化在PEP 3121中进行了描述,这本书本身是一本不错但富有挑战性的读物。在

现在,它的要旨可以归纳为两点:

A)模块现在定义在一个专用的^{}结构中:

struct PyModuleDef{
  PyModuleDef_Base m_base;  /* To be filled out by the interpreter */
  Py_ssize_t m_size; /* Size of per-module data */
  PyMethodDef *m_methods;
  inquiry m_reload;
  traverseproc m_traverse;
  inquiry m_clear;
  freefunc m_free;
};

这个新结构包含一些额外的成员,这些成员保存模块的名称和文档。为了简单起见,成员^{}, ^{}, ^{} and ^{} provide additional control during initialization/finalization but, we can opt to leave them as ^{}.以及设置为m_size的模块m_size是为了简单起见,设置这些值通常是为了支持多个解释器/多个初始化而完成的,应该更为棘手。在

因此,简而言之,thinning模块的新模块结构可以如下所示:

^{pr2}$

aa第一期就到了!在

新的初始化函数,也就是说你需要给initthinning一个大的整容。

新的模块初始化函数返回一个PyObject *,现在命名为PyInit_<module_name>。在里面(嘿,明白了吗?)new modules are created with ^{}使用我们定义的结构并返回初始化的模块。现在更漂亮了,看起来像这样:

/* ==== Initialize the C_test functions ====================== */
PyObject *
PyInit_thinning(void){
    // create module
    PyObject *module = PyModule_Create(&moduledef);

    // handle probable error
    if (module == NULL)
        return NULL;

    PyModule_AddStringConstant(module, "__author__", "Adrian Neumann <adrian_neumann@gmx.de>");
    PyModule_AddStringConstant(module, "__version__", "1.2.3");
    import_array();  // Must be present for NumPy.  Called first after above line.

    // return newly created module
    return module;
}

安装模块:

所有这些都是为了初始化模块。您可以下载模块(正如您所做的那样,我相信)找到thinning_folder/src/c_thinning.c文件,并将之前的所有内容替换为:

/* ==== Guo Hall Thinning =========

包括以下内容:

#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION

#include "Python.h"
#include "arrayobject.h"
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <limits.h>

static PyObject *guo_hall_thinning(PyObject *self, PyObject *args);
int _guo_hall_thinning(unsigned char* binary_image, int width, int height);


/* ==== Set up the methods table ====================== */
static PyMethodDef thinningMethods[] = {
    {"guo_hall_thinning",guo_hall_thinning, METH_VARARGS,
    "Takes a 2D numpy UBYTE array in C-order and thins it in place using the algorithm by Guo and Hall."
    "Images that come out of cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) have the right format."
    "\n\n"
    "We assume that the dimensions of the image fit into an int on your platform. If your computer for some"
    "reason has a 2 byte int and lots of memory so that the image can become too large, bad things can happen."
    "\n\n"
    "interface:\n"
    "\tguo_hall_thinning(segmented_image)"
    "\tsegmented_image is a NumPy matrix,"
    "\treturns the same NumPy matrix (thinned)"},
    {NULL, NULL, 0, NULL}     /* Sentinel - marks the end of this structure */
};

static struct PyModuleDef moduledef = {
        PyModuleDef_HEAD_INIT,
        "thinning",
        "Thinning of segmented images. See https://bitbucket.org/adrian_n/thinning.",
        -1,
        thinningMethods,
        NULL,
        NULL,
        NULL,
        NULL
};

/* ==== Initialize the C_test functions ====================== */
PyObject *
PyInit_thinning(void){
    PyObject *module = PyModule_Create(&moduledef);

    if (module == NULL)
        return NULL;

    PyModule_AddStringConstant(module, "__author__", "Adrian Neumann <adrian_neumann@gmx.de>");
    PyModule_AddStringConstant(module, "__version__", "1.2.3");
    import_array();  // Must be present for NumPy.  Called first after above line.
    return module;
}

/* ==== Guo Hall Thinning =========
// Leave the rest as it was

然后,导航到包含setup.py的顶层目录并运行:

python setup.py install

像往常一样。可能会弹出一些编译警告,但可以安全地忽略这些警告。如果一切顺利,您将获得成功的安装,并且以下情况不会导致严重的seg fault

>>> from thinning import guo_hall_thinning
>>> print(guo_hall_thinning.__doc__)
Takes a 2D numpy UBYTE array in C-order and thins it in place using the algorithm by Guo and Hall.Images that come out of cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) have the right format.

We assume that the dimensions of the image fit into an int on your platform. If your computer for somereason has a 2 byte int and lots of memory so that the image can become too large, bad things can happen.

interface:
    guo_hall_thinning(segmented_image)  segmented_image is a NumPy matrix,  returns the same NumPy matrix (thinned)

它似乎在运行:):

我进一步编辑了c_thinning.c中的源代码,以打印出每次迭代中更改的元素的数量。它似乎在改变事情,但我不明白它使用的是什么基本标准,因为我还没有读过相应的论文。在

简言之,guo_hall_thinning(ndarr)显然是在适当的位置进行了“细化”。这意味着在执行之后,作为参数提供的原始数组将被更改。所以,检查一下表格:

gray_img == guo_hall_thinning(gray_img)

总是TrueHint: check for equality between numpy arrays with ^{})。在

我做了一个测试,你可以直观地看到正在发生的变化,我相信这个测试也可以在你的机器上重现:

# dtype = 'B' is UBYTE
>>> n = numpy.ndarray(shape=(100, 200), dtype='B')
>>> n
array([[ 40, 159,  95, ..., 114, 114,  97],
       [121,  95, 108, ..., 114, 101,  32],
       [ 48, 161,  90, ..., 127,   0,   0],
       ..., 
       [110,  32,  97, ..., 124,   1,   0],
       [124,   5,   0, ...,   0,   0, 131],
       [  1,   0,  25, ...,   0, 125,  17]], dtype=uint8)
>>> thinning.guo_hall_thinning(n)
  Array height 100 Array width: 200

Value of `changed` during 0 iteration is: 1695 
Value of `changed` during 1 iteration is: 1216 
Value of `changed` during 2 iteration is: 808 
Value of `changed` during 3 iteration is: 493 
Value of `changed` during 4 iteration is: 323 
Value of `changed` during 5 iteration is: 229 
Value of `changed` during 6 iteration is: 151 
Value of `changed` during 7 iteration is: 90 
Value of `changed` during 8 iteration is: 46 
Value of `changed` during 9 iteration is: 27 
Value of `changed` during 10 iteration is: 11 
Value of `changed` during 11 iteration is: 8 
Value of `changed` during 12 iteration is: 7 
Value of `changed` during 13 iteration is: 4 
Value of `changed` during 14 iteration is: 0 
Value of `ok` is: 0

# array returned
array([[ 40, 159,  95, ..., 114, 114,  97],
       [121,   0,   0, ..., 114,   0,  32],
       [ 48,   0,   0, ..., 127,   0,   0],
       ..., 
       [110,   0,  97, ..., 124,   1,   0],
       [124,   5,   0, ...,   0,   0, 131],
       [  1,   0,  25, ...,   0, 125,  17]], dtype=uint8)

所以我猜它确实有用:-)。在

相关问题 更多 >

    热门问题