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类型,可能就会没有问题。
这里只是指出碰到的问题,也给你们提供一种解决问题的方法和思路