c++调用python失败解决方案

现象:

使用c++调用python时,根据网上搜到的教程使用python提供C API库调用时,发现只要py里包含了cv2库,在导入模块时就会报错。报错信息如下:

这个报错信息在不同的python版本可能具体信息稍有不同,但总的来说就是报错找不到cv2这个dll。但是如果直接用python运行py脚本是可以运行成功的。

原因分析:

省时间直接跳解决方法。

1.python文件分析

通过更改py文件发现即使是使用最简单的代码,只要import cv2,使用c++调用就会报错。

import sys
sys.OpenCV_LOADER_DEBUG = 1
import cv2
def add_fun(a,b):
    print(cv2.__version__)
    return a+b


if __name__ == '__main__':
    print(add_fun(2,3))

python环境下运行不报错,所以不是代码问题。根据网上教程尝试在py里手动添加path库路径

sys.path.append("E:\\ProgramData\\Anaconda3\\envs\\ctest\\Lib\\site-packages")
sys.path.append("E:\\ProgramData\\Anaconda3\\envs\\ctest\\Scripts")

发现依旧不行。手动添加第三方库路径可以解决某些库报错的情况,但是不适合cv2库报错。

2.c文件分析

#include <Python.h>
#include <iostream>

int main() {
     初始化Python解释器
    //_putenv_s("PYTHONHOME", "D:\\Users\\16092\\Python\\Python38");
    //_putenv_s("PYTHONPATH", "D:\\Users\\16092\\Python\\Python38\\Lib\\site-packages");
    //_putenv_s("PATH", "D:\\Users\\16092\\anaconda3\\envs\\bino_tracker\\Library\\bin;D:\\Users\\16092\\Python\\Python38\\Lib\\site-packages\\cv2;");
    
    _putenv_s("PYTHONHOME", "D:\\Users\\16092\\anaconda3\\envs\\bino_tracker");
    
    Py_Initialize();
   
    

    // 设置PYTHONPATH以包含你的Python文件的目录
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('.')");  // '.'表示当前目录


    /*PyRun_SimpleString("import sys");
    PyRun_SimpleString("print(sys.path)");*/


    // 导入Python模块
    PyObject* pName = PyUnicode_DecodeFSDefault("mytest");  // 模块名
    PyObject* pModule = PyImport_Import(pName);
    Py_DECREF(pName);

去掉py文件中的import cv2 ,发现可以调用成功,所以可以确定vs中配置的python库没有问题。

后面尝试修改调用方式,发现无论是使用最原始的python capi,还是使用boost 和qt 调用python,只要加了cv2模块,就会报错。报错信息大同小异都是找不到cv2模块。

又尝试在c++里面指定path发现依然报错。

3.环境分析

由于已经能够确定代码没有问题,所以最后的可能只能是环境问题。由于报错信息是缺少cv2 DLL文件。使用本地搜索工具发现没有cv2.dll文件,只有cv2.pyd文件。而python调用的也是这个文件。所以大概率是这个文件的问题。尝试复制这个文件到当前目录发现还是不行。

解决方案:

由于报错是cv2.dll但是只有cv2.pyd库,所以猜测是因为cv2.pyd的依赖在c++里找不到。使用Dependency Walker分析cv2.pyd的依赖,发现了很奇怪的事

这个pyd文件依赖了python3.dll。将python3.dll拷贝到与py文件同目录,发现调用成功。

总结:

网上c++python互相调用的代码很多,但是关于环境配置教程比较少。我使用的是vs2022根据教程在c++附加目录,和链接器输入,分别添加了头文件和库目录后,进行编译vs会提示没有python38.dll文件,这个提示和你使用的lib相对应。此时将这个dll放入项目目录,是可以编译过去的,但是因为py中有时导入的第三方库引用了其它的dll,这个时候就会加载失败,但是输出的报错信息又不明确,这是个巨坑。所以以后其它类似报错也可以用此方法排查。

此外我使用的是vs2022+conda +python3.8,有文章说conda环境不能使用,实测是可以的。至于上面提到的在py文件中手动添加第三方库的做法是适用于某些情况的,实测不适用于cv2模块。

还有一点是注意c++代码里加载的是哪个python环境,如果不设置回去加载系统环境变量里的python环境,建议手动指定,保持与直接运行py文件的环境一致,这样方便打包移植。

最后,调用pyd方法和py文件方法一模一样。教程网上很多,这里就不写了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值