vscode c++和python联合编程——调用easyocr

1.vscode创建c++项目时,会生成两个最基本的配置文件(c_cpp_properties.json,tasks.json),一个是vscode编辑器的配置文件,一个是运行c++项目的调试文件

2.c_cpp_properties.json的相关配置

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**",
                "D:\\Anaconda\\envs\\torch_gpu\\include" //自己创建的虚拟环境,我的是torch_gpu虚拟环境,将该路径添加到这里,告诉编辑器我们在哪里可以找到相关头文件,例如Python.h,
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "compilerPath": "D:\\msys64\\mingw64\\bin\\gcc.exe",
            "cStandard": "c17",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "windows-gcc-x64"
        }
    ],
    "version": 4
}

3. tasks.json的相关配置

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cppbuild",
			"label": "C/C++: g++.exe 生成活动文件",
			"command": "D:\\msys64\\mingw64\\bin\\g++.exe",
			"args": [
				"-fdiagnostics-color=always",
				"-g",
				"${file}",
				"-o",
				"${fileDirname}\\${fileBasenameNoExtension}.exe",
                //主要添加以下6行,其中"-I","-L","-l"分别对应着g++的命令行参数
                //-I: 告诉编译器,头文件里的 include<package> 去哪儿找。
                //-L: 告诉编译器,添加一个要动态链接的目录
                //-l: 指定具体的动态链接库的名称
                "-I",
                "D:\\Anaconda\\envs\\torch_gpu\\include",
                "-L",
                "D:\\Anaconda\\envs\\torch_gpu\\libs",
                "-l",
                "python311",
			],
			"options": {
				"cwd": "${fileDirname}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": {
				"kind": "build",
				"isDefault": true
			},
			"detail": "编译器: D:\\msys64\\mingw64\\bin\\g++.exe"
		}
	]
}

4.此时随便编写一个测试代码来验证c++是否可以调用python

#include <iostream>
#include <Python.h>
using namespace std;

int main(){

    Py_Initialize();

    cout << "wrt" << endl;
    
    Py_Finalize();

}

这时会在终端上看见输出 wrt

5.基本的配置已经完成,接下来调用easyocr文字识别模块,找到在anaconda中自己创建的虚拟环境(我创建的虚拟环境是torch_gpu)下的easyocr源代码文件,具体路径参考:D:\Anaconda\envs\torch_gpu\Lib\site-packages         

在该路径下有easyocr文件夹

 将easyocr文件夹复制到vscode,就是你创建的c++项目目录下,大概是下面这样

6. 此时,直接写一个调用easyocr模块的代码,如下:


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

using namespace std;

int main(){

    Py_Initialize();
    
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./easyocr')");//添加当前工程中的easyocr目录路径
    
    PyObject *easyocr_module =  PyImport_ImportModule("easyocr");

    if (easyocr_module == NULL)
    {
        cerr << "failed to import easyocr module" << endl;
        PyErr_Print();
        return 1;
    }else{
        cout << "succeesly to import easyocr module" << endl;
    }

    Py_Finalize();
}

 但是会报错,我们来解决一下,具体错误如下:

运行的时候,python中的解释器不能识别例如 .easyocr 这样的写法,当前目录下的文件可以相互之间调用,所以类似于  from .easyocr import Reader 的报错,我们将其改为 from easyocr import Reader, 将 . 去掉。

7.改完之后,继续调试,你会发现还是会报错,具体错误如下:

无法找到模块cv2, 原因是没指明opencv-python-headless包的具体路径,在这提醒一下,easyocr文字识别模块需要opencv-python-headless,这个包里会涵盖一些必要的函数方法,这些方法在opencv-python里面是没有的。所以在代码中添加路径:

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

using namespace std;

int main(){

    Py_Initialize();
    
    PyRun_SimpleString("import sys");
    
    //以下两行代码,添加cv2模块的具体路径,参考这个路径,把你的路径添加进去,你会发现在site_packages中有cv2文件夹,这个就是导入的cv2模块
    PyRun_SimpleString("sys.path.append('D:/Anaconda/envs/torch_gpu/Lib/site-packages')");
    PyRun_SimpleString("import cv2");

    PyRun_SimpleString("sys.path.append('./easyocr')");
    PyObject *easyocr_module =  PyImport_ImportModule("easyocr");

    if (easyocr_module == NULL)
    {
        cerr << "failed to import easyocr module" << endl;
        PyErr_Print();
        return 1;
    }else{
        cout << "succeesly to import easyocr module" << endl;
    }

    Py_Finalize();
}

8.修改完之后,再次运行代码,你会发现又会出现一个问题,该错误表示尝试从一个正在执行 import 语句的模块中导入 Reader,但该模块在 import 执行的过程中还未完全初始化。

找到这个报错的文件__init__.py,将其中的两行代码注释掉,这两行代码可有可无,具体操作如下

9.修改完之后,保存该文件,再次运行,你会发现代码运行成功

 10.以上就是c++调用python实现easyocr模块的导入,导入成功之后,就可以进行后续的方法调用,主要是查看easyocr模块的Reader方法是否可以被调用,添加测试代码

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

using namespace std;

int main(){

    Py_Initialize();
    
    PyRun_SimpleString("import sys");
    
    //以下两行代码,添加cv2模块的具体路径,参考这个路径,把你的路径添加进去,你会发现在site_packages中有cv2文件夹,这个就是导入的cv2模块
    PyRun_SimpleString("sys.path.append('D:/Anaconda/envs/torch_gpu/Lib/site-packages')");
    PyRun_SimpleString("import cv2");

    PyRun_SimpleString("sys.path.append('./easyocr')");
    PyObject *easyocr_module =  PyImport_ImportModule("easyocr");

    if (easyocr_module == NULL)
    {
        cerr << "failed to import easyocr module" << endl;
        PyErr_Print();
        return 1;
    }else{
        cout << "succeesly to import easyocr module" << endl;
    }
    //测试Reader方法是否可以被调用
    PyObject *reader_class = PyObject_GetAttrString(easyocr_module, "Reader");

    if (reader_class == NULL || !PyCallable_Check(reader_class))
    {
        cerr << "failed to get easyocr reader class" << endl;
        PyErr_Print();
        Py_XDECREF(easyocr_module);
        return 1;
    }else{
        cout << "succeed to get easyocr reader class" << endl;
    }


    Py_Finalize();
}

运行该代码文件之后会报错,AttributeError: module 'easyocr' has no attribute 'Reader',找不到Reader这个类。

11.之后我开始不断做实验,又重新来了一遍,把原来工程目录下的easyocr文件夹删了,重新将在第5步中找到的easyocr文件重新复制粘贴到工程目录下,这次不对该文件夹中的文件做任何改动,运行测试代码文件,这个时候报的错就不一样了

报错显示,libiomp5md.dll这个动态库文件已经被初始化了,torch需要初始化它自带libiomp5md.dll文件,但是报错显示,在其他地方已经找到并初始化了这个文件,那解决方法就是找到这个文件并把它删了

12.按理说,应该直接删除你建立的虚拟环境下的libiomp5md.dll文件,也就是这个

但是删除之后,还是会报和以前一样的错误,那也就是说,删错了

继续在anaconda文件夹下找libiomp5md.dll文件,你会发现还有一个libiomp5md.dll文件

图片中的文件已经被我删了,你应该可以在你的文件目录下看到libiomp5md.dll文件,最好复制备份一份,具体为什么是删除这个目录下的libiomp5md.dll文件,我也不是很理解。删除之后继续运行测试代码文件

这时模型导入成功,方法也调用成功。 

13.总结

有可能,一开始就直接删除 libiomp5md.dll文件,之后再调用easyocr模块,就不会有这么多复杂的过程和报错,具体我没试,你们可以试试看。如果我后面还有报错以及代码跑不通的地方,我会继续解决并更新文章。

14.模型导入成功之后,开始实例化Reader对象。首先需要传递适当的参数,具体的代码如下:

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

using namespace std;

int main(){

    Py_Initialize();
    
    PyRun_SimpleString("import sys");
    
    //以下两行代码,添加cv2模块的具体路径,参考这个路径,把你的路径添加进去,你会发现在site_packages中有cv2文件夹,这个就是导入的cv2模块
    PyRun_SimpleString("sys.path.append('D:/Anaconda/envs/torch_gpu/Lib/site-packages')");
    PyRun_SimpleString("import cv2");

    PyRun_SimpleString("sys.path.append('./easyocr')");
    PyObject *easyocr_module =  PyImport_ImportModule("easyocr");

    if (easyocr_module == NULL)
    {
        cerr << "failed to import easyocr module" << endl;
        PyErr_Print();
        return 1;
    }else{
        cout << "succeesly to import easyocr module" << endl;
    }
    //测试Reader方法是否可以被调用
    PyObject *reader_class = PyObject_GetAttrString(easyocr_module, "Reader");

    if (reader_class == NULL || !PyCallable_Check(reader_class))
    {
        cerr << "failed to get easyocr reader class" << endl;
        PyErr_Print();
        Py_XDECREF(easyocr_module);
        return 1;
    }else{
        cout << "succeed to get easyocr reader class" << endl;
    }


    //设置参数
    PyObject *lang = PyList_New(1);
    PyList_SetItem(lang, 0, PyUnicode_FromString("en"));
    PyObject *args = PyTuple_New(1);
    PyTuple_SetItem(args, 0, lang);
    
    //对象实例化
    PyObject *reader_instance = PyObject_CallObject(reader_class, args);
    
    if (reader_instance == NULL)
    {
        cerr << "failed to create easyocr reader instance" << endl;
        PyErr_Print();
        Py_XDECREF(easyocr_module);
        Py_XDECREF(reader_class);
        return 1;
    }else{
        cout << "succeed to create easyocr reader instance" << endl;
    }


    Py_Finalize();
}

一开始的时候,会默认下载相关的语言模型以及文字识别模型,在Windows系统下,模型会下载在

C:\Users\你自己的用户名\.EasyOCR\model,这个模型参数文件只会被下载一次,以后会在该目录下自动查找。

 代码成功运行,此时用的是cpu

 如果你想自己设置Reader的参数,举个列子,在代码文件中添加一行

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

using namespace std;

int main(){

    Py_Initialize();
    
    PyRun_SimpleString("import sys");
    
    //以下两行代码,添加cv2模块的具体路径,参考这个路径,把你的路径添加进去,你会发现在site_packages中有cv2文件夹,这个就是导入的cv2模块
    PyRun_SimpleString("sys.path.append('D:/Anaconda/envs/torch_gpu/Lib/site-packages')");
    PyRun_SimpleString("import cv2");

    PyRun_SimpleString("sys.path.append('./easyocr')");
    PyObject *easyocr_module =  PyImport_ImportModule("easyocr");

    if (easyocr_module == NULL)
    {
        cerr << "failed to import easyocr module" << endl;
        PyErr_Print();
        return 1;
    }else{
        cout << "succeesly to import easyocr module" << endl;
    }
    //测试Reader方法是否可以被调用
    PyObject *reader_class = PyObject_GetAttrString(easyocr_module, "Reader");

    if (reader_class == NULL || !PyCallable_Check(reader_class))
    {
        cerr << "failed to get easyocr reader class" << endl;
        PyErr_Print();
        Py_XDECREF(easyocr_module);
        return 1;
    }else{
        cout << "succeed to get easyocr reader class" << endl;
    }


    //设置参数
    PyObject *lang = PyList_New(1);
    PyList_SetItem(lang, 0, PyUnicode_FromString("en"));
    PyObject *args = PyTuple_New(2);
    PyTuple_SetItem(args, 0, lang);
    
    //新添加的一行
    PyTuple_SetItem(args, 1, PyUnicode_FromString("False"));//设置参数gpu=False

    
    //对象实例化
    PyObject *reader_instance = PyObject_CallObject(reader_class, args);
    
    if (reader_instance == NULL)
    {
        cerr << "failed to create easyocr reader instance" << endl;
        PyErr_Print();
        Py_XDECREF(easyocr_module);
        Py_XDECREF(reader_class);
        return 1;
    }else{
        cout << "succeed to create easyocr reader instance" << endl;
    }


    Py_Finalize();
}

 运行代码之后,你会发现报错,

错误定位到torch的serialization.py这个源代码文件, assert hpu is not None, "HPU device module is not loaded",torch的源代码文件本身没有问题,最后根据代码报错回溯定位查找错误,你会发现自己传入的False参数是字符串类型,不是布尔值,导致在easyocr.py文件运行的时候,判断使用cpu,gpu还是其他设备时,出现错误

也就是if判断语句,根本不会执行。如果想自己传参数,注意类似的相关问题,把传递的值转化为easyocr需要的参数类型,这里把False字符类型转换成bool类型,可能就会没有问题。

这里只是指出碰到的问题,也给你们提供一种解决问题的方法和思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值