工控编程吧

标题: VS2019通过C语言直接调用PYTHON库 [打印本页]

作者: qq263946146    时间: 2021-6-1 13:33
标题: VS2019通过C语言直接调用PYTHON库
本想将写好的PYTHON文件打包成DLL供VS2019使用。
打包一下成众多文件,发再1个多GB,打包成独立exe文件也有400MB。
两行代码就这么大,看来也没啥意义再打包了。
python环境安装好了,就直接在本地用吧。
用vs2019直接调用python写好的py文件就好,也很方便。

这里记录下操作过程遇到的坑与解决方法。
也是第一次接触python,折腾的够呛。
首先也是自行安装VS2019,Anacoda3,pycharm.
我都是使用最新版本的64位。
可参考先前写的帖子。
https://www.gkbc8.com/forum.php?mod=viewthread&tid=15933

产生用pycharm或VS2019编写一个PY文件用于测试。
内容如下,涉及的第三方库都可以在Anacoda3里下载安装。
我这里是测试使用EASYOCR库。
主要是想通过VS2019直接调用下面的函数ocr。
  1. from gettext import gettext
  2. import easyocr

  3. # 结果为rect,文本,可信度 [([[189, 75], [469, 75], [469, 165], [189, 165]], '愚园路', 0.3754989504814148) ]
  4. # result = reader.readtext('d:/1.bmp')  #
  5. # 结果为简单的字符数组,如['愚园路', '西', '东', '315', '309', 'Yuyuan Rd.', 'W', 'E'];

  6. # result = reader.readtext('d:/1.bmp', detail=0, paragraph=True)


  7. # file = open('C:/Users/baikhgmv/Desktop/' + 'new' + '.txt', 'w')
  8. # file.close()

  9. # print(result)
  10. # gettext(message=1)

  11. reader = easyocr.Reader(['ch_sim', 'en'], gpu=False)  # 仅需初始化一次;


  12. def typeof(variate):
  13.     variate_type = None
  14.     if isinstance(variate, int):
  15.         variate_type = "int"
  16.     elif isinstance(variate, str):
  17.         variate_type = "str"
  18.     elif isinstance(variate, float):
  19.         variate_type = "float"
  20.     elif isinstance(variate, list):
  21.         variate_type = "list"
  22.     elif isinstance(variate, tuple):
  23.         variate_type = "tuple"
  24.     elif isinstance(variate, dict):
  25.         variate_type = "dict"
  26.     elif isinstance(variate, set):
  27.         variate_type = "set"
  28.     return variate_type


  29. def com(s):
  30.     print(s)
  31.     rst = '123'
  32.     return rst


  33. def ocr(filepath):
  34.     rst = reader.readtext(filepath, detail=0, paragraph=True)
  35.     print(typeof(rst))
  36.     print(rst)
  37.     return rst
复制代码
自己用VS2019建立下个DOS,空的工程,
新建一文件test.cpp。复制下面的内容,再设置路径。
  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. //#include "detect_text.h"
  4. //#pragma comment(lib,"OCRDLL.lib")

  5. #include <string>
  6. #include <Python.h>
  7. #include<iostream>
  8. #include<Windows.h>

  9. using namespace std;


  10. wchar_t* utf_8ToUnicode(const char* u8s)
  11. {
  12.         int wcsLen = MultiByteToWideChar(CP_UTF8, NULL, u8s, (int)strlen(u8s), NULL, NULL)+1;
  13.         wchar_t* wcString = new wchar_t[wcsLen];
  14.         ZeroMemory(wcString, wcsLen);
  15.         MultiByteToWideChar(CP_UTF8, NULL, u8s, (int)strlen(u8s), wcString, wcsLen);
  16.         return wcString;
  17. }
  18. char* unicodeToAnsi(wchar_t* wcString)
  19. {
  20.         int len = WideCharToMultiByte(CP_ACP, NULL, wcString, -1, NULL, NULL, NULL, NULL)+1;
  21.         char* str = new char[len];
  22.         ZeroMemory(str, len);
  23.         WideCharToMultiByte(CP_ACP, NULL, wcString, -1, str, len, NULL, NULL);
  24.         return str;
  25. }
  26. int main()
  27. {
  28.         //<>初始化python模块
  29.         Py_SetPythonHome(L"D:\\ProgramData\\Anaconda3\\envs\\easyocr");
  30.         Py_Initialize();
  31.         if (!Py_IsInitialized())
  32.         {
  33.                 cout << "初始化失败" << endl;
  34.                 Py_Finalize();
  35.                 return 0;
  36.         }

  37.         PyRun_SimpleString("import sys");
  38.         PyRun_SimpleString("sys.path.append('./')");//设置python模块搜寻位置,文件放在.cpp文件一起
  39.         PyObject* pModule = NULL;
  40.         PyObject* pFunc   = NULL;
  41.         PyObject* pArg    = NULL;
  42.         pModule = PyImport_ImportModule("ocr");//Python文件名
  43.         if (!pModule)
  44.         {
  45.                 cout << "py文件导入失败" << endl;
  46.         }
  47.         else
  48.         {
  49.                 pFunc = PyObject_GetAttrString(pModule, "ocr");//Python文件中的函数名  
  50.                 if (!pFunc)
  51.                 {
  52.                         cout << "函数导入失败" << endl;
  53.                         Py_Finalize();
  54.                 }
  55.                 PyObject* pyParams = Py_BuildValue("(s)", "D:\\1.bmp");//c++类型转python类型
  56.                 pArg = PyEval_CallObject(pFunc, pyParams);//调用函数
  57.                
  58.                 if (PyList_Check(pArg))
  59.                 {
  60.                         PyObject* list_item = NULL;
  61.                         char* pStr = NULL;//c类型的列表元素
  62.                         for (int sb=0; sb < PyObject_Size(pArg); sb++)
  63.                         {
  64.                                 //根据下标取出python列表中的元素,再转为字符串;
  65.                                 list_item = PyList_GetItem(pArg, sb);                               
  66.                                 PyArg_Parse(list_item, "s", &pStr);
  67.                                
  68.                                 //python3默认为utf8编码,将其转为ansi,正常显示结果;
  69.                                 wchar_t* p = NULL;
  70.                                 char* p2 = NULL;
  71.                                 p  = utf_8ToUnicode(pStr);
  72.                                 p2 = unicodeToAnsi(p);
  73.                                 cout << p2 << "\r\n" << endl;
  74.                                 //
  75.                                 if (p)
  76.                                         delete[]p;
  77.                                 if (p2)
  78.                                         delete[]p2;
  79.                         }
  80.                 }
  81.         }
  82.         char a = getchar();
  83.         Py_Finalize();
  84.         return 0;
  85. }
复制代码
路径我的设置是
头文件路径
D:\ProgramData\Anaconda3\envs\easyocr\include
库文件路径
D:\ProgramData\Anaconda3\envs\easyocr\libs
D:\ProgramData\Anaconda3为Anaconda3的安装位置,
我使用Anaconda3创建了一个新的环境easyocr,
所以使用此环境下的路径。
直接编译工程,正常生成exe程序。
将刚才的py文件复制一份到exe程序与test.cpp都一份。
一个是编译时会用到,一个是运行时会用到。
直接进行程序。
不出意外,会有如下提示错误。
mkl-service第三方库我在Anaconda3创建的环境easyocr里,是有安装的,
版本也是匹配的,最后大量查阅网络,是路径问题。
  1. D:\ProgramData\Anaconda3\envs\easyocr\lib\site-packages\numpy\__init__.py:138: UserWarning: mkl-service package failed to import, therefore Intel(R) MKL initialization ensuring its correct out-of-the box operation under condition when Gnu OpenMP had already been loaded by Python process is not assured. Please install mkl-service package, see http://github.com/IntelPython/mkl-service
  2.   from . import _distributor_init
  3. py文件导入失败
复制代码

解决方法如下。
电脑系统环境变量Path添加python环境的三个路径。
如我的
系统环境设置,重启电脑
D:\ProgramData\Anaconda3\envs\easyocr
D:\ProgramData\Anaconda3\envs\easyocr\Scripts
D:\ProgramData\Anaconda3\envs\easyocr\Library\bin
测试后,反复测试还是不行。
直接放弃,关机睡觉。
第二天继续开机测试,一切OK了。
经过反复测试,确定了原因。
系统环境设置后,重启电脑才能正常,重要的事搞三遍。
系统环境设置,重启电脑
系统环境设置,重启电脑
系统环境设置,重启电脑
真恶心。

最后
在C++调用python库前还得Py_SetPythonHome。
调用函数设置
Py_SetPythonHome(L"D:\\ProgramData\\Anaconda3\\envs\\easyocr");
或也通过添加系统环境变量PYTHONHOME == D:\\ProgramData\\Anaconda3\\envs\\easyocr。
我已放弃折腾,在本地能用就好,也不在乎如何搞更加简便。
等后期有时间了,系统熟悉python编程。

好在python用的人多,遇到 的问题一搜都有答案,就是折腾人。
一切编译OK,运行程序。
效果如下
(, 下载次数: 5)