DjangoフレームワークでMATLABを接続して画像を出力する方法

1. MATLAB Engine APIのインストールと検証

1.1 MATLAB Engine APIのインストール

MATLAB公式サイトにはPythonとの接続用のAPIがあります。

公式サイトアドレス:MATLAB Engine API for Pythonのインストールスクリプト - MATLAB & Simulink - MathWorks 日本

Windowsシステムでは、コンピュータにインストールされているMATLABのアドレスにあるpythonフォルダ(このフォルダにはsetup.pyファイルがあります)を見つける必要があります。

私の場合はE:\MATLAB\extern\engines\pythonです。

cmdをそのアドレスに切り替えて、python setup.py installと入力してEnterキーを押すだけです。

1.2 インストールの検証

PyCharmでこのパッケージをインポートします。

パッケージが赤色で表示されないことを確認します。

これでMATLAB Engine APIのインストールは成功です。

注意点として、このAPIはユーザーのコンピュータの環境変数のPython環境に基づいてダウンロードされるため、実行可能なのはコンピュータの環境変数のPython環境のみです。仮想環境では動作しません。したがって、コンパイラでは正しい環境を選択することを忘れないでください。

2. PythonでMATLAB関数を実行する

PythonでMATLAB関数を呼び出すのは非常に簡単で、MATLABパッケージのエンジンを起動するだけです。

以下の例で説明します:

% mat.m
function a = mat()
    a = 'こんにちは、世界!';
end
import matlab.engine

# MATLABエンジンを起動し、エンジンオブジェクトを変数engに割り当てる
eng = matlab.engine.start_matlab()

# MATLAB関数を呼び出す
print(eng.mat())

# MATLABエンジンを閉じる
eng.quit()

mat関数の実行結果は「こんにちは、世界!」を返します。

Pythonではまずmatlabパッケージをインポートし、MATLABエンジンを初期化してengに割り当てます。その後のMATLAB関数の呼び出し操作はすべてengが行い、最後にエンジンを閉じます。

これは出力結果です:

3. Djangoで接続してMATLABを実行する

DjangoでMATLAB関数を呼び出すのは、単純なPythonでの呼び出しとは異なります。

まず、以前の考え方に基づいてhelloworldコードを書いてみましょう:

%mat.m
function returning = mat()
    returning = 'こんにちは世界';
end
from django.shortcuts import render
import matlab.engine

def helloworld(request):
    eng = matlab.engine.start_matlab()
    a = eng.mat()
    eng.quit()
    return render(request, 'helloworld.html', {"n1": a})
<!--helloworld.html-->

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello World Display</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
        }
        img {
            max-width: 100%;
            height: auto;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>Hello World Display</h1>
    <div>{{ n1 }}</div>
</body>
</html>

このコードは理論的には実行成功後、フロントエンドインターフェースに「こんにちは世界」と表示されるはずです。

しかし、実際は

後で原因がMATLABのエンジンがその関数のパスを見つけられない可能性があるとわかりました。

解決策はコードに1行追加することです:

eng.cd('/*関数が存在するフォルダ*/', nargout=0)

私の場合、修正後のコードは以下の通りです:

def helloworld(request):
    eng = matlab.engine.start_matlab()
    eng.cd('D:\PycharmProjects\djangotest3\index', nargout=0)
    a = eng.mat()
    eng.quit()
    return render(request, 'helloworld.html', {"n1": a})

実行してみましょう

実行成功!

これでMATLAB関数を実行し、データをフロントエンドインターフェースに表示することが成功しました。

最後の項目だけが残っています。

4. DjangoでMATLABの実行結果の画像を表示する

画像を表示するには、まず画像を取得する必要があります。これが最も難しい部分です。多くの方法を試した後、最終的にGPTが生成したコードが実行に成功しました。この方法では、MATLABの画像ハンドルを取得した後、画像をBase64エンコード形式でテンプレートに渡す必要があります。

まず、MATLABエンジンを起動し、m関数を呼び出してグラフィックハンドルを取得します

# MATLABエンジンを起動
eng = matlab.engine.start_matlab()
eng.cd('D:\PycharmProjects\djangotest3\index', nargout=0)

# MATLABスクリプトファイルを実行
eng.eval("run('test.m');",  nargout=0)
# 現在のグラフィックハンドルを取得
fig_handle = eng.gcf()

# 画像データをPythonに転送
matlab_image_data = eng.getframe(fig_handle, nargout=1)

次に、画像データ形式を確認し、変換します。データ形式が期待通りであれば、画像データをNumPy配列に変換します。そうでなければ、例外をスローします

# データ型を確認し、NumPy配列に変換
if isinstance(matlab_image_data, dict) and 'cdata' in matlab_image_data:
    matlab_image = np.asarray(matlab_image_data['cdata'], dtype=np.uint8)
else:
    raise ValueError("MATLABからの予期せぬ画像データ形式")

エンジンを閉じます

eng.quit()

NumPy配列の画像データをPIL画像オブジェクトに変換します

image = Image.fromarray(matlab_image)

PIL画像オブジェクトをバイトストリームに変換し、Base64エンコードを行います

# PIL画像オブジェクトをバイトストリームに変換
image_stream = BytesIO()
image.save(image_stream, format='PNG')  # 実際の状況に応じて画像形式を選択できます

# バイトストリームのBase64エンコードを取得
image_base64 = base64.b64encode(image_stream.getvalue()).decode('utf-8')

最後に、Base64エンコードされた画像データをテンプレートに渡し、テンプレートをレンダリングします

# 画像データをテンプレートに渡す
return render(request, 'imgshow.html', {'image_data': image_base64})

以下は完全なコードです:

%test.m
% xの範囲を定義、-10から10まで
x = -10:0.1:10;
% y = 3 * xを計算
y = 3 * x;
% 折れ線グラフを描画
plot(x, y)
% グラフのタイトルを追加
title('y = 3 * x')
% x軸とy軸のラベルを追加
xlabel('x')
ylabel('y')
% グリッドを表示
grid on
<!--imgshow.html-->

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MATLAB Image</title>
</head>
<body>
    <h1>MATLAB Image</h1>
    <img src="data:image/png;base64,{{ image_data }}" alt="MATLAB Image">
</body>
</html>
from PIL import Image
from django.shortcuts import render
import numpy as np
import matlab.engine
from io import BytesIO
import base64

def imgshow(request):
    # MATLABエンジンを起動
    eng = matlab.engine.start_matlab()
    eng.cd('D:\PycharmProjects\djangotest3\index', nargout=0)

    # MATLABスクリプトファイルを実行
    eng.eval("run('test.m');",  nargout=0)
    # 現在のグラフィックハンドルを取得
    fig_handle = eng.gcf()

    # 画像データをPythonに転送
    matlab_image_data = eng.getframe(fig_handle, nargout=1)
    # データ型を確認し、NumPy配列に変換
    if isinstance(matlab_image_data, dict) and 'cdata' in matlab_image_data:
        matlab_image = np.asarray(matlab_image_data['cdata'], dtype=np.uint8)
    else:
        raise ValueError("MATLABからの予期せぬ画像データ形式")

    # MATLABエンジンを閉じる
    eng.quit()

    # 画像データをPIL画像オブジェクトに変換
    image = Image.fromarray(matlab_image)
    image.show()

    # PIL画像オブジェクトをバイトストリームに変換
    image_stream = BytesIO()
    image.save(image_stream, format='PNG')  # 実際の状況に応じて画像形式を選択できます

    # バイトストリームのBase64エンコードを取得
    image_base64 = base64.b64encode(image_stream.getvalue()).decode('utf-8')

    # 画像データをテンプレートに渡す
    return render(request, 'imgshow.html', {'image_data': image_base64})

最終出力結果:

もちろん、より簡単な方法も存在する可能性は排除できませんが、能力の限界と関連チュートリアルがないため、現時点ではこの方法しか正常に実行できないようです。

これでDjangoでのMATLABの一連の操作が完了しました。

タグ: Django MATLAB Python Web開発 画像処理

6月2日 20:29 投稿