pythonスクリプトのexeファイル化 (pyinstaller)
やりたいこと
別PCへの配布 (python環境がないPC/開発者以外のPCで動作させたいツールなど)
簡単に起動させたい便利ツール (ドラッグアンドドロップでファイル情報を取得して起動など)
exe化の方法
pythonのexe化用ライブラリは複数存在するが、今回は最も手軽にできるpyinstallerを紹介する
環境
Windows10 (64bit)
Anaconda (python 3.5 64bit)
手順
pip install pyinstaller で pyinstallerをインストール
(初回のみ。anaconda 仮想環境を作っている場合はactivate コマンドで移動後に実行すること)
pyinstaller XXX.py -F でexeファイルを生成
exeファイルはpyinstallerを実行したカレントディレクトリに生成される『dist』フォルダ以下に出力される
-Fオプションをつけることで実行時に必要なファイルが1つのexeファイルに集約される
複数ファイルが含まれるpythonファイルをexe化したい場合、mainが記載されているpythonスクリプトを指定するとその他のファイルは自動で読み込まれる。
注意点
pythonのバージョン
pyinstallerはpython 2.X~3.7まで対応しているが、利用するライブラリによってはexeの生成や実行時にエラーがおきることが多い (特にpandas/matplotlib関連)
筆者の環境ではpython3.5が比較的安定していた。(pandas/matplotlibの処理に対しても問題なく生成できた)
ファイルの容量
生成されるexe容量は読み込むライブラリに依存し、数十MB~百MBになる。小さくしたい場合にはpython仮想環境に含まれるライブラリを必要最低限にするなどの工夫が必要となる
ファイルパスの取得
pythonのスクリプトファイルが存在するパスを取得する処理を記述したい場合によく記述する下記ではパスを取得できない。
import os
iDir = os.path.abspath(os.path.dirname(__file__))
上記の代わりにsysモジュールを使ってファイルパスを取得できる
import os import sys dpath = os.path.dirname(sys.argv[0])
ドラッグアンドドロップによるファイルパスの受け渡し
生成したexeファイルにファイルをドラッグアンドドロップすることで、外部パスを簡単に受け渡すことができる。
exeにドラッグアンドドロップされたファイルはsys.argv[1]で読み込める。 (複数ファイル渡す場合にはarg[2]以降で取得)
参考として、exeファイルにドラッグアンドドロップすると画像の横方向反転+グレースケール化をして表示するスクリプトを実装する。
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import cv2 import numpy as np import sys #データ読み込みクラス class Class_Img_PreProcessing(): ''' 画像データの前処理をまとめたクラス ''' def __init__(self,filepath="",cv2img = None): ''' コンストラクタ (filepath=指定したパス の画像の読み込み,もしくはcv2img=numpy形式データを代入) ''' if filepath !="" : #ファイルパスが指定された場合 self.img = cv2.imread(filepath) elif cv2img != None: #numpy形式データが入力された場合 self.img = cv2img else: self,img = None def get_gray_img(self,color_im= "None"): ''' グレースケール画像を取得する (color_im:カラー画像データ(option)) ''' if color_im is "None": if self.img is None: return None else: return cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) else: return cv2.cvtColor(color_im, cv2.COLOR_BGR2GRAY) def flip_img(self,mode="x"): ''' 画像を反転させる x: 横方向反転、y:縦方向反転 xy:両方向反転 ''' if self.img is None: return None else: if mode == "x": #X軸方向反転 result = cv2.flip(self.img,1) elif mode == "y": #Y軸方向反転 result = cv2.flip(self.img,0) elif mode == "xy": #両方向反転 result = cv2.flip(self.img,-1) else: result = self.img return result if __name__ == '__main__': target_ext = ['.jpg','.png','.tif'] for indx in range(1,len(sys.argv)): filename = sys.argv[indx] root, ext = os.path.splitext(filename) print(ext) for indx2 in range(len(target_ext)): if ext == target_ext[indx2]: img_inst = Class_Img_PreProcessing(filename) flip_img = img_inst.flip_img(mode="x") gray_img = img_inst.get_gray_img(color_im = flip_img) cv2.imshow("Windowname",gray_img) cv2.waitKey(0)
実装結果は下記サイトに保存済み