Eel で 画像データを相互変換する

Uncategorized
562 words

Eel を使うと Python から HTML を呼んだり、その逆で HTML から Python を呼び出すことができます。

今回はその Eel を使って、Python で読み込んだ画像データを HTMLに送って画面に表示したり、表示してある画像を Python に送って OpenCV でグレースケール化して戻すってことをやってみたいと思います。

環境

ソースコード

実際に動くソースコードは GitHub に上げてあるので、ここでは要点だけ説明します。

Python 実行時に HTML を表示する処理

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
import asyncio
import eel

async def main():
eel.init('web')
eel.start('index.html', port=0, size=(450, 560))
pass

if __name__ == '__main__':
try:
asyncio.run(main())
except Exception:
pass

「web」フォルダ内の「index.html」を開くように設定しています。

画像読み込み時の処理

JavaScript

1
2
3
4
5
6
7
async get_img() {
// Pythonから画像データ(Base64文字列)を読み込む
const img_base64 = await eel.get_img()();

// 画面に表示
this.img_src = 'data:image/png;base64,' + img_base64;
},

「eel.get_img」でPython を呼び出しています。

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@eel.expose
def get_img():
# ファイルを開くダイアログの表示
filename = filedialog.askopenfilename(
title="画像ファイルを開く",
filetypes=[("Image file", ".bmp .png .jpg .tif")],
initialdir="./"
)

# 画像ファイルを開いてbase64に変換
with open(filename, 'br') as f1:
img_base64 = base64.b64encode(f1.read())

# base64を文字列で返却
return img_base64.decode()

画像を Base64 に変換して、Base64の文字列を HTML に返却しています。

グレースケール化時の処理

JavaScript

1
2
3
4
5
6
7
8
9
10
async gray_scale() {
let img = this.img_src;
img = img.replace('data:image/png;base64,', '');

// Pythonでグレースケール変換
const img_base64 = await eel.gray_scale(img)();

// 画面に表示
this.img_src = 'data:image/png;base64,' + img_base64;
}

画面から Base64文字列の画像を取得して、Python に渡しています。

そして、戻ってきた画像データを再度画面に表示しています。

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@eel.expose
def gray_scale(img_str: str):
# バリナリデータ <- Base64文字列
img_binary: bytes = base64.b64decode(img_str)

# バイナリーストリーム <- バリナリデータ
img_binarystream: io.BytesIO = io.BytesIO(img_binary)

# PILイメージ <- バイナリーストリーム
img_pil: Image = Image.open(img_binarystream)

# numpy配列(RGBA) <- PILイメージ
img_numpy: np.ndarray = np.asarray(img_pil)

# numpy配列(GRAY) <- numpy配列(RGBA)
img_gray: np.ndarray = cv2.cvtColor(img_numpy, cv2.COLOR_RGBA2GRAY)

# Base64 <- numpy配列(GRAY)
result, dst_data = cv2.imencode('.png', img_gray)
img_base64: bytes = base64.b64encode(dst_data)

# base64を文字列で返却
return img_base64.decode()

受け取った Base64文字列を画像に変換してから、OpenCV を使ってグレースケール化し、再度Base64文字列に変換してHTMLに返却しています。