罠がいっぱいあるので忘れないように。
個人的な作業用にGUIで動かせるPythonソフトを作っていたんですが、他の人から使わせてほしいということでexe化して配布することになった
……のはいいんですが、これがどうも Anaconda の Python 3.6 だと罠がいっぱいあり、しかも社内ネットがやたらとアクセス制限だらけで、やっとこさ最小構成で実現できたのでメモ。
Python 3.6.1 :: Anaconda 4.4.0 (64 bit)
opencv-python 3.3.0.10
cx-Freeze 5.0.2
結局 cx-Freeze による exe 化がうまくいきました。
とりあえずインストール。
pip install --upgrade cx_Freeze
今はexe化をするのが目的なので、以下のサンプルプログラムをお借りして、受け取った写真を漫画風にするという GUI を作ってみたいと思います。
この画像フィルタリングソフトに、ファイル選択と表示のGUIを作ったデモがこちら。
PyQtでファイルを選択して表示というGUIは以下を参考にさせて頂きました。
import sys import numpy.core._methods import numpy.lib.format import numpy as np import cv2 import PyQt5.QtWidgets as gui from PyQt5.QtGui import QPixmap # 加工後の画像を表示 class SubWindow(gui.QDialog): def __init__(self, fname, parent): self.parent = parent gui.QDialog.__init__(self, parent) self.fname = fname def show(self): hbox = gui.QHBoxLayout(self) pixmap = QPixmap(self.fname) self.label = gui.QLabel(self) self.label.setPixmap(pixmap) self.label.setGeometry(160, 40, 80, 30) hbox.addWidget(self.label) self.setLayout(hbox) self.move(300, 200) self.setWindowTitle(self.fname) self.exec_() # 画像を漫画風に加工 # https://algorithm.joho.info/programming/python/opencv-manga-filter-py/ class ProcessManga(): def manga_filter(self, src, screen, th1=60, th2=150): gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) screen = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY) screen = cv2.resize(screen,(gray.shape[1],gray.shape[0])) edge = 255 - cv2.Canny(gray, 80, 120) gray[gray <= th1] = 0 gray[gray >= th2] = 255 gray[ np.where((gray > th1) & (gray < th2)) ] = screen[ np.where((gray > th1)&(gray < th2)) ] return cv2.bitwise_and(gray, edge) def run(self, fname, fname_scr, fname_mod): img = cv2.imread(fname) screen = cv2.imread(fname_scr) manga = self.manga_filter(img, screen) cv2.imwrite(fname_mod, manga) # ファイル選択画面 class MainWindow(gui.QWidget): def __init__(self, parent=None): gui.QMainWindow.__init__(self, parent) layout = gui.QGridLayout() form = gui.QFormLayout() # 入力画像とスクリーントーンのファイルを選択 self.inputText = gui.QLineEdit() btnSepFile = gui.QPushButton(u'...') btnSepFile.setMaximumWidth(40) btnSepFile.clicked.connect(self.chooseDbFile) boxSepFile = gui.QHBoxLayout() boxSepFile.addWidget(self.inputText) boxSepFile.addWidget(btnSepFile) form.addRow(u'入力画像を選択', boxSepFile) self.inputTextScr = gui.QLineEdit() btnSepFileScr = gui.QPushButton(u'...') btnSepFileScr.setMaximumWidth(40) btnSepFileScr.clicked.connect(self.chooseDbFileScr) boxSepFileScr = gui.QHBoxLayout() boxSepFileScr.addWidget(self.inputTextScr) boxSepFileScr.addWidget(btnSepFileScr) form.addRow(u'スクリーントーンを選択', boxSepFileScr) # 実行ボタン boxCtrl = gui.QHBoxLayout() makeWindowButton = gui.QPushButton('実行') makeWindowButton.clicked.connect(self.makeWindow) boxCtrl.addWidget(makeWindowButton) layout.addLayout(form,0,0) layout.addLayout(boxCtrl,1,0) self.setLayout(layout) self.resize(300,100) def makeWindow(self): fname = self.inputText.text() fname_scr = self.inputTextScr.text() fname_mod = fname + '_mod.png' pm = ProcessManga() pm.run(fname, fname_scr, fname_mod) subWindow = SubWindow(fname_mod, parent=self) subWindow.show() def chooseDbFile(self): dialog = gui.QFileDialog() dialog.setFileMode(gui.QFileDialog.ExistingFile) if dialog.exec_(): fileNames = dialog.selectedFiles() for f in fileNames: self.inputText.setText(f) return return self.inputText.setText('') def chooseDbFileScr(self): dialog = gui.QFileDialog() dialog.setFileMode(gui.QFileDialog.ExistingFile) if dialog.exec_(): fileNames = dialog.selectedFiles() for f in fileNames: self.inputTextScr.setText(f) return return self.inputTextScr.setText('') if __name__ == '__main__': app = gui.QApplication(sys.argv) myapp = MainWindow() myapp.show() sys.exit(app.exec_())
まず普通に作るところまではよくて、なぜか以下の2つをインポートしないとexeがうまく動きません…。(つまずきポイント1)
import numpy.core._methods import numpy.lib.format
こちらを gui.py として、cx_Freeze のビルド用にもう一つファイルを用意します。こちらも以下を参考にさせて頂いて、setup.py として保存します。
# cx_Freeze 用セットアップファイル import sys from cx_Freeze import setup, Executable import os os.environ['TCL_LIBRARY'] = "C:\\Users\\****\\AppData\\Local\\Continuum\\Anaconda3\\tcl\\tcl8.6" os.environ['TK_LIBRARY'] = "C:\\Users\\****\\AppData\\Local\\Continuum\\Anaconda3\\tcl\\tk8.6" include_files = ["C:\\Users\\****\\AppData\\Local\\Continuum\\Anaconda3\\DLLs\\tcl86t.dll", "C:\\Users\\****\\AppData\\Local\\Continuum\\Anaconda3\\DLLs\\tk86t.dll"] build_exe_options = {'include_files': include_files} base = None # GUI=有効, CUI=無効 にする if sys.platform == 'win32' : base = 'Win32GUI' # exe にしたい python ファイルを指定 exe = Executable(script = 'gui.py', base = base) # セットアップ setup(name = 'test', version = '0.1', description = 'GUI tool for TG', options = {'build_exe': build_exe_options}, executables = [exe])
今回のデモでは不要なんですが、元のソフトが Anaconda だと TCL/TK の LIBRARY が見えないと怒られてしまい、無理やり環境変数に仕込んだ上でddlの場所を教える必要がありました (つまずきポイント2)
python setup.py build
そして上を実行すると、build/exe.win-amd64-3.6/gui.exe が完成です!だがまだ動かない……… (つまずきポイント3)
C:\Users\***\AppData\Local\Continuum\Anaconda3\Library\plugins\platforms というフォルダを、gui.exe と同じディレクトリにコピーすると、やっと Python ベースの exe ファイルが完成して配布となりました。
一応研究が本職なんですが、俺はなんで最近こんなエンジニアみたいなことをしてるんだろうか…。まあいいや、もし使ってみて何かあればフィードバックを頂ければです。
(も・ω・ち)

- 作者: 築山節
- 出版社/メーカー: NHK出版
- 発売日: 2005/11/08
- メディア: 新書
- 購入: 36人 クリック: 158回
- この商品を含むブログ (128件) を見る