Получил исключение boost :: python :: error_already_set on boost :: python :: import ("cv2") - PullRequest
2 голосов
/ 08 июля 2019

Я получил исключение boost::python::error_already_set при вызове boost::python::import("cv2")

Сначала я написал скрипт на python pymod.py:

import sys
...

и импортировал pymod.py с помощью boost::python в коде cpp:

...
boost::python::import("pymod");
...

хорошо работает.

Но когда я добавляю cv2 в pymod.py:

import sys, cv2

boost::python::import("pymod")сгенерировал исключение:

terminate called after throwing an instance of 'boost::python::error_already_set'

Обратите внимание, что Python-скрипт с import cv2 может быть вызван Python:

python pymod.py

без ошибок.

Итак, я попыталсяcpp-версия импорта cv2 с boost::python и выброшено то же исключение.Код следующий:

#include <boost/dll/import.hpp>
#include <boost/python.hpp>

int main(int nArgCnt, char *ppArgs[]) {
    Py_Initialize();
    boost::python::object pySys = boost::python::import("cv2");
    return 0;
}


Обновление 1:

Я также проверил источник boost_1_65_1/libs/python/src/import.cpp и нашел реализацию boost::python::import:

object BOOST_PYTHON_DECL import(str name)
{
  // should be 'char const *' but older python versions don't use 'const' yet.
  char *n = python::extract<char *>(name);
  python::handle<> module(PyImport_ImportModule(n));
  return python::object(module);
}

И я пытаюсь напрямую использовать PyImport_ImportModule, но тоже не получилось:

#include <boost/dll/import.hpp>
#include <boost/python.hpp>
#include <Python.h>
#include <iostream>

int main(int nArgCnt, char *ppArgs[]) {
    Py_Initialize();
    // numpy, sys and other modules can be load! VERY STRANGE!!
    auto pMod = PyImport_ImportModule("cv2");
    std::cout << pMod << std::endl;
    return 0;
}

этот код выводит следующие выходные данные:

['/usr/local/lib/python3.6/dist-packages', '/usr/local/lib/python3.6/dist-packages/cv2/python-3.6', '/home/devymex/3rdparty/opencv-4.0.1/build/python_loader', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/devymex/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages/mxnet-1.3.1-py3.6.egg', '/usr/local/lib/python3.6/dist-packages/graphviz-0.8.4-py3.6.egg', '/usr/local/lib/python3.6/dist-packages/typing-3.6.6-py3.6.egg', '/usr/local/lib/python3.6/dist-packages/typing_extensions-3.6.6-py3.6.egg', '/usr/local/lib/python3.6/dist-packages/onnx-1.5.0-py3.6-linux-x86_64.egg', '/usr/lib/python3/dist-packages']
0

Но я очень уверен, что командаpython3 -c "import cv2" работает без проблем.Таким образом, это не имеет значения для повышения.


Обновление 2:

PyErr_Print(); дает следующую информацию:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/cv2/__init__.py", line 89, in <module>
    bootstrap()
  File "/usr/local/lib/python3.6/dist-packages/cv2/__init__.py", line 79, in bootstrap
    import cv2
  File "/usr/local/lib/python3.6/dist-packages/cv2/__init__.py", line 89, in <module>
    bootstrap()
  File "/usr/local/lib/python3.6/dist-packages/cv2/__init__.py", line 23, in bootstrap
    raise ImportError('ERROR: recursion is detected during loading of "cv2" binary extensions. Check OpenCV installation.')
ImportError: ERROR: recursion is detected during loading of "cv2" binary extensions. Check OpenCV installation.

__init__.py:

'''
OpenCV Python binary extension loader
'''
import os
import sys

try:
    import numpy
    import numpy.core.multiarray
except ImportError:
    print('OpenCV bindings requires "numpy" package.')
    print('Install it via command:')
    print('    pip install numpy')
    raise

# TODO
# is_x64 = sys.maxsize > 2**32

def bootstrap():
    import sys
    if hasattr(sys, 'OpenCV_LOADER'):
        print(sys.path)
        raise ImportError('ERROR: recursion is detected during loading of "cv2" binary extensions. Check OpenCV installation.')
    sys.OpenCV_LOADER = True

    DEBUG = False
    if hasattr(sys, 'OpenCV_LOADER_DEBUG'):
        DEBUG = True

    import platform
    if DEBUG: print('OpenCV loader: os.name="{}"  platform.system()="{}"'.format(os.name, str(platform.system())))

    LOADER_DIR=os.path.dirname(os.path.abspath(__file__))

    PYTHON_EXTENSIONS_PATHS = []
    BINARIES_PATHS = []

    g_vars = globals()
    l_vars = locals()

    if sys.version_info[:2] < (3, 0):
        from cv2.load_config_py2 import exec_file_wrapper
    else:
        from . load_config_py3 import exec_file_wrapper

    def load_first_config(fnames, required=True):
        for fname in fnames:
            fpath = os.path.join(LOADER_DIR, fname)
            if not os.path.exists(fpath):
                if DEBUG: print('OpenCV loader: config not found, skip: {}'.format(fpath))
                continue
            if DEBUG: print('OpenCV loader: loading config: {}'.format(fpath))
            exec_file_wrapper(fpath, g_vars, l_vars)
            return True
        if required:
            raise ImportError('OpenCV loader: missing configuration file: {}. Check OpenCV installation.'.format(fnames))

    load_first_config(['config.py'], True)
    load_first_config([
        'config-{}.{}.py'.format(sys.version_info[0], sys.version_info[1]),
        'config-{}.py'.format(sys.version_info[0])
    ], True)

    if DEBUG: print('OpenCV loader: PYTHON_EXTENSIONS_PATHS={}'.format(str(l_vars['PYTHON_EXTENSIONS_PATHS'])))
    if DEBUG: print('OpenCV loader: BINARIES_PATHS={}'.format(str(l_vars['BINARIES_PATHS'])))

    for p in reversed(l_vars['PYTHON_EXTENSIONS_PATHS']):
        sys.path.insert(1, p)

    if os.name == 'nt':
        os.environ['PATH'] = ';'.join(l_vars['BINARIES_PATHS']) + ';' + os.environ.get('PATH', '')
        if DEBUG: print('OpenCV loader: PATH={}'.format(str(os.environ['PATH'])))
    else:
        # amending of LD_LIBRARY_PATH works for sub-processes only
        os.environ['LD_LIBRARY_PATH'] = ':'.join(l_vars['BINARIES_PATHS']) + ':' + os.environ.get('LD_LIBRARY_PATH', '')

    if DEBUG: print('OpenCV loader: replacing cv2 module')
    del sys.modules['cv2']
    import cv2

    try:
        import sys
        del sys.OpenCV_LOADER
    except:
        pass

    if DEBUG: print('OpenCV loader: DONE')

bootstrap()

Как решить эту проблему?

1 Ответ

1 голос
/ 08 июля 2019

Наконец-то я получил решение:


#include <boost/python/numpy.hpp>
#include <boost/python/extract.hpp>
#include <boost/python.hpp>

#include <iostream>

namespace py = boost::python;

int main(int nArgCnt, char *ppArgs[]) {
    Py_Initialize();
    py::object pySys = py::import("sys");
    auto pySysPaths = py::extract<py::list>(pySys.attr("path"))();

    //Important! Add an empty path to the head of searching paths
    pySysPaths.insert<std::string>(0, "");

    py::object pyCv2 = py::import("cv2");
    return 0;
}

Объяснение

Если вы используете команду python some_script.py, список путей поиска модулей был изменен: пустой путьстрока будет вставлена ​​в начало списка:

['', '/usr/local/lib/python3.6/dist-packages', blah, blah, blah, ...]

Вы можете найти строки 67, 68 из __init__.py OpenCV:

    for p in reversed(l_vars['PYTHON_EXTENSIONS_PATHS']):
        sys.path.insert(1, p)

Затем путь библиотеки OpenCV (cv2.cpython-36m-x86_64-linux-gnu.so) правильно вставлен в список.И import cv2 в строке 79 из __init__.py, просто загружающей файл cv2.cpython-36m-x86_64-linux-gnu.so напрямую, до сих пор все хорошо работает с другим путем поиска.

Но в вызове cpp все по-другому.Без программы python никто не добавил пустой путь поиска в заголовок sys.path, поэтому __init__.py сгенерировал незаслуженный список путей поиска:

['/usr/local/lib/python3.6/dist-packages', '/usr/local/lib/python3.6/dist-packages/cv2/python-3.6', '/home/devymex/3rdparty/caffe/python', blah, blah, blah, ...]

Обратите внимание на реальное местоположение /usr/local/lib/python3.6/dist-packages/cv2/python-3.6/cv2.cpython-36m-x86_64-linux-gnu.soна втором месте, поэтому строка 79 в __init__.py вводится в рекурсивный вызов __init__.py вместо загрузки cv2.cpython-36m-x86_64-linux-gnu.so

Вот и вся история.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...