【pythonnet準備+確認編】C#にpythonで作った処理を組み込む

C#とpythonのイラスト プログラミング
C#とpythonのイラスト

概要

pythonで作った処理(主にはtensorflow, pytorch等のディープラーニング系)をGUIから動かして結果を表示したいということがあると思います。

tkinterやpyqtで作っても良いですが、C#のフォームの良さを活かすことで手早くGUIが作ることができます。

また、C#は製造業で使用する検査システム等でよく使われるため、組み込みができると便利です。

tensorflowで作ったモデルを使ってアプリを作るところまでの手順を記事したいと思います。
本記事はまずは準備と動作確認編です。

実際に簡単なフォームアプリを作って、準備と動作確認してみます。
2023年4月最新の方法です。

準備ができた方は実践編も参考にしてみてください

前提条件

開発の環境
visualstudio2019 community Version 16.7.7
NuGet パッケージ マネージャー 5.7.0
Anaconda Navigator 1.9.12

C#の環境

.NET Framework 4.7.2

pythonの環境

Python 3.8.5
tensorflow 2.3.0
numpy 1.18.5

C#からpythonnetを呼び出して使ってみる

フォームにラベルを配置してnumpyのバージョン表示、numpyでの簡単な計算をするアプリを作ってみようと思います。

フォームのアプリケーションを作る

注意ポイント:.NETフレームワークのバージョンを4.7以上にしてください

フォームアプリの選択画面
プロジェクト名とフレームワークのバージョン設定画面

プラットフォーム変更

注意ポイント:構成マネージャーをx64=64bitにしないとうまく動きません

Debugの右の▼ボタンをクリックして構成マネージャーをクリック

構成マネージャーの選択画面

アクティブソリューション プラットフォーム(P)の∨をクリック→新規作成をクリック

アクティブソリューションプラットフォームの設定画面

新しいプラットフォームを入力または選択してください(P)でx64を選択→OKをクリック

新ソリューションのプラットフォームの設定方法

Debugの右のAny CPUがx64に変わっていることを確認してください。

x64の設定画面

pythonnetの導入

以下の操作をしてください。

  1. ツール
  2. NuGetパッケージマネージャー
  3. ソリューションのNuGetパッケージの管理

管理画面が開きましたら以下の「pythonnet」を選択して

インストールしてください。

インストールできたら、ソリューションエクスプローラーに

Python.Runtime

が追加されていることを確認してください。

サンプルコードの作成

このようなフォームを作成してみてください

作成するフォームアプリの画面

ソースコード

using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Python.Runtime;

namespace pythonnet_numpy_test_2023
{
    public partial class Form1 : Form
    {
        // numpyのモジュールを格納する変数を定義

        private dynamic np;

        public Form1()
        {
            InitializeComponent();

            // *-------------------------------------------------------------------------
            // *  python環境をpythonnetに設定
            // *-------------------------------------------------------------------------

            // DLLの設定
            // pythonXX.dllが存在しているパスを定義
            var PYTHON_DLL_PATH = (@"自分のpython環境パス\pythonXX.dll");
            // PythonDLLに設定
            Runtime.PythonDLL = PYTHON_DLL_PATH;

            // python標準ライブラリの設定
            // python.exeが存在しているフォルダの指定
            var PYTHON_HOME = @"自分のpython環境パス";
            // 環境変数に定義
            Environment.SetEnvironmentVariable("PYTHONHOME", PYTHON_HOME, EnvironmentVariableTarget.Process);
            // PythonEngineのPythonHomeに設定
            PythonEngine.PythonHome = Environment.GetEnvironmentVariable("PYTHONHOME", EnvironmentVariableTarget.Process);

            // 外部ライブラリの設定
            // 外部ライブラリが存在しているフォルダの設定
            var MODULE_PATH = @"仮想環境のパス";
            // PythonPathに外部ライブラリを追加
            PythonEngine.PythonPath = string.Join(
                Path.PathSeparator.ToString(),
                new string[] {
                    PythonEngine.PythonPath,
                    Path.Combine(MODULE_PATH, @"Lib\site-packages"),
                }
            );

            // PythonEngineの初期化
            PythonEngine.Initialize();
            // pythonの処理をする=numpyの定義とバージョンをラベルに表示させる
            using (Py.GIL())
            {
                // numpyのインポート
                np = Py.Import("numpy");
                // numpyのバージョンを変数に格納
                dynamic np_version = np.__version__;
                // string型にして文字列と連結させラベルに表示
                labelNumpyVersion.Text = "numpyバージョン:" + np_version.ToString();
            }
        }

        /// <summary>
        /// numpyのライブラリを使った簡単な計算
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCalc_Click(object sender, EventArgs e)
        {
            // 簡単な計算をして変数に格納
            dynamic result = np.cos(np.pi / 3);
            // ToStringしなくても文字列にくっつけると勝手に型を変えてくれる
            labelResult.Text = "np.cos(np.pi / 3)=" + result;
        }
    }
}

基本的には通常のC#のフォームアプリを作成方法と変わりませんが、ポイントがいくつかあります。

1.フォームをロードするときにpythonnetの初期化をする

フォームをロードするときのメソッドに初期化のコードを追記しましょう。

追記する部分が3つあります。


(1)PythonのDLLのパスを設定

anacondaの場合は仮想環境ごとにpython自体もインストールしますので

Anaconda3\envs\環境名

を設定します。

venv等を使っている場合には公式のpythonインストーラーで入れるので

AppData\Local\Programs\Python\バージョンの毎のpython

の中にpythonXX.dllやpython.exeがあると思いますのでそのパスを設定します。

※XXにはpythonのバージョンが入ります ex)python3.8→38

 var PYTHON_DLL_PATH = (@"自分のpython環境パス\pythonXX.dll");

(2)Python.exeが存在するパスを設定

先ほど同様に

anacondaの場合は仮想環境ごとにpython自体もインストールしますので

Anaconda3\envs\環境名

を設定します。

venv等を使っている場合には公式のpythonインストーラーで入れるので

AppData\Local\Programs\Python\バージョンの毎のpython

の中にpythonXX.dllやpython.exeがあると思いますのでそのパスを設定します。

var PYTHON_HOME = @"自分のpython環境パス";

(3)外部ライブラリが存在するパスを設定

anacondaで仮想環境を作った場合は

Anaconda3\envs\環境名

venvで仮想環境を作った場合は

自分でパスを設定しますので

そのパスを設定してください。

var MODULE_PATH = @"仮想環境のパス";

2.実際にpythonのコードをC#で実装

1つポイントとしてフォームアプリの場合は色々なコントロールでnumpyを使いたいのでインポートしたときに格納するメンバー変数を定義しておく必要があります。
まとめると以下の通りになります。

メンバー変数の定義

    public partial class Form1 : Form
    {
        /// <summary>
        /// pythonライブラリを共有して使うための変数
        /// </summary>
        public dynamic np;

numpyの定義とバージョン情報の表示

            // pythonの処理をする=numpyの定義とバージョンをラベルに表示させる
            using (Py.GIL())
            {
                // numpyのインポート
                np = Py.Import("numpy");
                // numpyのバージョンを変数に格納
                dynamic np_version = np.__version__;
                // string型にして文字列と連結させラベルに表示
                labelNumpyVersion.Text = "numpyバージョン:" + np_version.ToString();
            }

numpyの使用

            // 簡単な計算をして変数に格納
            dynamic result = np.cos(np.pi / 3);

最後に

C#でpythonの処理をそのまま使えるとアプリの幅が広がると思いますので是非試してみてください。

また、準備ができた方は実践編も読んでみてください。

コメント

  1. […] C#にpythonで作った処理を組み込む【pythonnet準備+確認編 2021年2月最新】 […]

タイトルとURLをコピーしました