VS2017 vs c++ 调用python文件封装成.dll文件,供c#使用(亲测可用,欢迎留言!!)

看标题,咱就是说,c# 直接调用python 不就行了吗?

不好意思,上述简单的咱没试出来……所以转来转去(哭唧唧)

如果有后续试出来了再更新记录。

起因在于做图像分析时,甲方爸爸嫌弃halcon的许可证贵,所以要从简,这不就用开源的opencv了吗。但是c# 的opencv 没咋试过(事实是没啥人用,维护人少),工期紧,就看看python版的opencv能否被调用呗。话不多说,一步一步来吧,至少是实现了,错了勿喷接受指摘。

环境:python3.10  【安装在d:\python3.10这个路径中】

系统:win11

编译器:visual studio 2017

编译语言:python, c#, c++

1. vs2017 c++ 配置python的包含目录和库文件等等

1.创建visual c++ 控制台应用

2. 点击解决方案,右击属性。修改库目录文件为安装的python的路径。以下都是同理。

选了配置:所有配置,平台:所有平台。

这里要注意下,如果是python3.10就像这么写,python3.9就是python39.lib


3. 如果后期c++要调试的话,需要保证安装python debug的lib文件,不然会报错。

报错的信息,就是LINK:fatal error LNK1104:无法打开文件"pythonXX_d.lib"

点开添加或删除程序(win11),找到python版本,然后点击修改。

勾选后面两项,点击install。

2. 测试and生成.dll文件

1.编写c++测试脚本

浅浅看下我的preprocess_image.py文件,主要就是实现一个图像的裁剪的功能。

import cv2
import os


def resize_image(single_image_path, target_height=36, target_width=36):
    # # avoid image path is not utf-8 encoding
    image_path = single_image_path.encode('utf-8')
    # # open image
    image = cv2.imread(image_path.decode('utf-8'))
    if image is None:
        raise ValueError('image is None')
    else:
        # change image size 36 * 36
        output_image = cv2.resize(image, (target_width, target_height))
    return output_image

根据以上代码,打开.cpp文件,然后将以下代码拷贝进去。

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

//main函数名字为checktest
unsigned char checktest(string* image_path, int target_height, int target_width)
{
	Py_Initialize();

	PyRun_SimpleString("print('Hello Python!')\n");

	PyObject * pModule = NULL;
	PyObject * pFunc = NULL;
	PyObject * pDict = NULL;
    
    //文件名作为模块名
	pModule = PyImport_ImportModule("preprocess_image");
	if (pModule == NULL) {
		PyErr_Print();
		return 0;
	}
    //选取模块的函数
	pFunc = PyObject_GetAttrString(pModule, "resize_image");

    //创建参数组
	PyObject* pArgs = PyTuple_New(3);

    //一点要去查下"s","i","ii"的含义
	PyTuple_SetItem(pArgs, 0, Py_BuildValue("s", image_path));
	PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", target_height));
	PyTuple_SetItem(pArgs, 2, Py_BuildValue("i", target_width));
    
    //加上函数名和参数,去调用
	PyObject* pRet = PyObject_CallObject(pFunc, pArgs);
	
	unsigned char ans;
	PyArg_Parse(pRet, "B", &ans);//返回类型转换

	Py_Finalize();
	return ans;

}
2.很重要的一步,为了避免麻烦,可以直接将preprocess_image.py放在以下路径,避免找不到。

比如说,是debug,x64的环境,在本地调试的,可以放在以下路径里。

3.添加.h的头文件,并将主函数里面的函数名拷贝进来。

#pragma once
#include<string>
using namespace std;

extern "C" _declspec(dllexport) unsigned char checktest(string* image_path, int target_height, int target_width);

顺便将.h的头文件的项类型更改为”c/c++编译器“。

然后在.cpp里面的表头加上
 

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

点击生成->重新生成解决方案

然后报错:

1>MSVCRTD.lib(exe_main.obj) : error LNK2019: 无法解析的外部符号 main,该符号在函数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中被引用
1>C:\Users\Desktop\test_file\ConsoleApplication1\x64\Debug\ConsoleApplication1.exe : fatal error LNK1120: 1 个无法解析的外部命令

网上百度,是说没有main函数,好吧……——。——网上说的是对的,但是试了方法,发现是没有用,还是报这个错误。后来发现是没有将配置类型改成.dll类型。

4. 改成配置类型为 动态库(.dll)

5.添加.def文件

我看大家都添加了.def的文件,我一开始以为是报错的原因,后来发现不是,既然大家都是默许的,那我也加一遍吧。在源文件那里,添加.def文件。

 在.def文件里添加,前两行不用改,后面加上定义的函数。

LIBRARY
EXPORTS
checktest

以防万一,看下属性里面【模块定义文件】是不是刚刚创建的.def的文件。

点击重新生成解决方案,就会发现路径下存在了.dll和.lib文件了。

3. c# 调用dll 模块

1.创建一个窗体应用。
2.在窗体页面拖动一个label,用来查看到底有没有用。

3.将.dll拷贝到debug的环境中,然后将.py文件也拷贝进来。

在form1.cs中调用.dll模块

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        class CPPDLL
        {
            [DllImport(@"ConsoleApplication1.dll", EntryPoint = "checktest", CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
            public static extern byte checktest(string image_path);
        }

        private void label1_Click(object sender, EventArgs e)
        {
            string image_path = @"0.png";

            byte ans = CPPDLL.checktest(image_path);
            label1.Text = ans.ToString();

        }

    }
}
4.结果展示

点击调试按钮,然后点击label, label的文字就会转成204了.

大家可以自己试下……我的结果就是这样了,用简单的两个数求和也是对的,之前试过。

注意注意:不同编译语言,有个类型的转化,需要关注下,比如说c++中的图像类型(Mat)和c#的图像类型(Byte)的转化。

OKOK,今儿就到这,之后还可能更新,毕竟也还是有别的方法可以调用python的。

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值