質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PyInstaller

PyInstallerは、Pythonのスクリプトを一括でWindowsなどで動く実行可能ファイルに変換できるツールです。このツールを用いることで自作のPythonプログラムを別で使用する場合でもPythonをインストールする必要がありません。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

リソース

効果的な演算のために必要となる、メモリ・ディスク容量・CPUの性能や環境のこと。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3597閲覧

【Python/tifffile】.exeファイルでのtifffileエラー【PyInstaller】

netz-eng

総合スコア105

PyInstaller

PyInstallerは、Pythonのスクリプトを一括でWindowsなどで動く実行可能ファイルに変換できるツールです。このツールを用いることで自作のPythonプログラムを別で使用する場合でもPythonをインストールする必要がありません。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

リソース

効果的な演算のために必要となる、メモリ・ディスク容量・CPUの性能や環境のこと。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

0クリップ

投稿2020/08/16 08:13

編集2020/08/18 04:54

.exe形式のGUIでtifffileを使いたい

Tkinterを用いて、GUIの作成を行っています。
GUIの内容は「ボタンを押すと、cv2で読み込んだ画像を処理して、.tiff形式で保存する」というものです。

配布用にPyInstallerでコードを実行ファイル(.exe)化したところ、なぜかtifffileに関してのエラーが発生しました。
コードを直接コンソール画面に打ち込んでいるときには発生しなかったエラーです。
エラー内容について検索してみても、同じように困っている人が見つからなかったため、ここで質問します。

どなたかエラー解消方法にお心当たりのある方、ご回答よろしくお願いします。

発生している問題・エラーメッセージ

Exception in Tkinter callback Traceback (most recent call last): File "tkinter\__init__.py", line 1883, in __call__ File "sample.py", line 338, in btn_click storedata(t, tt, n, cap, TexName, TexNameT) File "sample.py", line 268, in storedata img2 = ti.imread(canny_path) File "tifffile\tifffile.py", line 712, in imread File "tifffile\tifffile.py", line 2651, in asarray File "tifffile\tifffile.py", line 5455, in asarray File "tifffile\tifffile.py", line 5320, in segments File "tifffile\tifffile.py", line 5309, in decode File "tifffile\tifffile.py", line 5038, in decode ValueError: TiffPage 0: <COMPRESSION.LZW: 5> requires the 'imagecodecs' package

正直、エラーの意味もよくわかっていません……。

該当のソースコード

python

1# sample.pyの中身 2import tkinter as tk 3from tkinter import filedialog, messagebox 4import cv2 5import tifffile as ti 6 7import os 8path = os.getcwd() 9 10root = tk.Tk() 11 12# 中略 13 14# 画像保存の関数 15def storedata(img_path, tt, n, cap, TexName, TexNameT): 16 img = cv2.imread(img_path) 17 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 18 canny = cv2.Canny(gray, 200, 400) 19 cv2.imwrite(canny_path, canny) 20# .tiff形式に変換。cv2.imwriteで.tiff形式にすると、表示時にエラーが発生する 21 img2 = ti.imread(canny_path) # <- エラー該当部分 22 ti.imsave(canny_path, img2) 23 # 中略 24 messagebox.showinfo("確認", "完了しました。") 25 26 27# ボタンクリック時の関数 28def btn_click(): 29 t = filedialog.askdiretory(initialdir=path, title="選択") 30# 中略 31# 関数呼び出し 32 storedata(t, tt, n, cap, TexName, TexNameT)  # <- エラー該当部分 33# t以外の変数はstoredata関数内で別の処理を行うために渡すもの。今回は省略 34 35btn = ttk.Button(text="sample", command=btn_click) 36btn.pack() 37 38 39root.mainlop()

実行してみると、cv2で保存した.tiffファイルのみが保存されており、そのあとの処理で行ったtifffileによる保存が行われていない状況でした。
その時点でエラーが出て処理が止まっているようで、メッセージボックスも表示されませんでした

.specファイル

PyInstallerの際に用いた.specファイルの中身です。

python

1# -*- mode: python ; coding: utf-8 -*- 2 3block_cipher = None 4 5import sys 6myLib = r"C:\~~~\anaconda3\Lib" 7myPkg = r"C:\~~~\anaconda3\envs\sample\Lib\site-packages" 8sys.path.append(myLib) 9sys.path.append(myPkg) 10 11 12a = Analysis(['sample.py'], 13 pathex=['C:\~~~\anaconda3'], 14 binaries=[], 15 datas=[], 16 hiddenimports=["pkg_resources.py2_warn", "pkg_resources.markers"], 17 hookspath=[], 18 runtime_hooks=[], 19 excludes=[], 20 win_no_prefer_redirects=False, 21 win_private_assemblies=False, 22 cipher=block_cipher, 23 noarchive=False) 24a.datas += [('AppIcon.ico', '.\AppIcon.ico', 'DATA')] 25pyz = PYZ(a.pure, a.zipped_data, 26 cipher=block_cipher) 27exe = EXE(pyz, 28 a.scripts, 29 a.binaries, 30 a.zipfiles, 31 a.datas, 32 [], 33 name='sample', 34 debug=False, 35 bootloader_ignore_signals=False, 36 strip=False, 37 upx=True, 38 upx_exclude=[], 39 runtime_tmpdir=None, 40 console=False, icon='AppIcon.ico') 41app = BUNDLE(exe, 42 name='sample.app', 43 icon='AppIcon.ico') 44coll = COLLECT(exe, 45 a.binaries, 46 a.zipfiles, 47 a.datas, 48 strip=False, 49 upx=True, 50 name='sample')

追記・試したこととエラー変更

「imagecodecsがありません」と言われているのはなんとなく分かったため、imagecodecsライブラリをインストールしてみました。
すると、エラー内容が下のようになりました。エラー箇所は恐らく同じです。

python

1DelayedImportError: could not import name 'lzw_decode' from 'imagecodecs'

「lzw_decodeがインポートできませんでした」と言われたため、sample.exeの元となるsample.py内で、

python

1from imagecodecs import lzw_decode

のコードを追加し、再度PyInstallerで.exe化しました。すると、エラーの内容が以下に変わりました。

python

1Traceback (most recent call last): 2 File "sample.py", line 286, in storedata 3 File "tifffile\tifffile.py", line 712, in imread 4 File "tifffile\tifffile.py", line 2651, in asarray 5 File "tifffile\tifffile.py", line 5455, in asarray 6 File "tifffile\tifffile.py", line 5320, in segments 7 File "tifffile\tifffile.py", line 5309, in decode 8 File "tifffile\tifffile.py", line 5270, in decode 9 File "imagecodecs\imagecodecs.py", line 459, in stub_decode 10imagecodecs.imagecodecs.DelayedImportError: could not import name 'lzw_decode' from 'imagecodecs'

流石に数千行ある内容すべてを転写するのは長すぎるため、↑のtifffile.pyと、imagecodecs.pyのエラー箇所を抜粋します。

python

1# tifffile.py 2 3# line 712 4return tif.asarray(**kwargs) 5# line 2651 6result = pages[0].asarray(out=out, maxworkers=maxworkers) 7# line 5455 8for in self.segments( 9 func=func, lock=lock, maxworkers=maxworkers, sort=True 10# line 5320 11yield decode(segments) 12# line 5309 13result = keyframe.decode(*args, **decodeargs) 14# line 5270 15data = decompress(data, out=size * dtype.itemsize)

python

1# imagecodecs.py 2 3# line 459 4if name.endswith('_decode'): 5 def stub_decode(*args, **kwargs): 6 f"""Stub for imagecodecs.{name}.""" 7 raise DelayedImportError(name) # <-- line 459

かなりマイナーなエラーで、非常に困っています。
解消方法にお心当たりのある方、是非よろしくお願いします。

補足情報(FW/ツールのバージョンなど)

Windows10
Python 3.8.3
OpenCV 4.4.0.40
tifffile 2020.8.13
PyInstaller 4.0
imagecodecs 2020.5.30

teamikl👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

エラーログからの推察です。実際に使ったことはないので
間違ってたらスイマセン。後で試してみますが、取り急ぎ解る範囲で。

tifffile の依存ライブラリの
imagecodecs の lzw_decode が遅延読込もしくは動的に読み込まれる為、
pyinstaller のモジュール解析で拾えない → 自分で指定する必要があるのだと思います。

具体的な指定方法は、binaries に、対象ライブラリの必要なファイルを調べ
pyd ファイルや dll ファイルを指定するといった流れ。

pyファイルならpyinstallerが勝手に対応してくれるはずなので、
該当箇所はC拡張や外部ライブラリになってるのではないでしょうか。


訂正

lzw_decode 関数は、Python の関数で ./imagecodecs/_imagecodecs.py ファイル内にありました。
C拡張ではありません。


追記

python

1# 問題の再現に用いた最小限のコード 2import tifffile 3img = tifffile.imread("IN.tiff") 4tifffile.imsave("OUT.tiff", img)

上記のコードで、LZW圧縮TIFFファイルの場合 問題の再現を確認しました。
※ 他の形式では、対応するcodecsが無いと同様のエラーが起こる可能性はあります。対象のファイル
次第。
※ もし動的リンクでdllファイル等 が必要な場合は、追加で binaries への設定が必要です。

python

1# pythonファイルで明示的インポート 2 3import imagecodecs._imcd

もしくは

# pyinstaller のオプション or spec ファイル編集 --hidden-import=imagecodecs._imcd

でどうでしょう。


When Things Go Wrong -- pyinstaller のトラブルシューティング

  • python -v で動的に読み込まれるモジュールを調べる
  • imagecodecs._shared は存在したが、imagecodecs._imcd は含まれていなかった
  • dist/APP_NAME/imagecodecs/ に _imcd を追加してみる → 動作成功
  • 解決策A: pyinstaller が動的インポートを探せるように、明示的 import
  • 解決策B: pyinstaller のオプション/ specファイル編集で指定する

投稿2020/08/18 06:06

編集2020/08/19 04:42
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

netz-eng

2020/08/18 07:05

ご回答ありがとうございます! どなたも回答を下さらないかと焦っていました(汗) こちらでも、_imagecodecs.pyの中にlzw_decode関数を見つけました。 ということは、binariesないしhiddenimportに、このファイルを指定すればいいんでしょうか? 少し時間がかかりますが、試してみます。
netz-eng

2020/08/18 07:25

a.binaries, hiddenimportsに、C:\Users\a284b\anaconda3\envs\Ormr\Lib\site-packages\imagecodecs\_imagecodecs.pyを入れてみましたが、どちらで試してもうまくいきませんでした。(エラー内容は、長くなったので省略させていただきます)
teamikl

2020/08/18 07:36

C拡張であれば binaries に追加だったのですが、 py ファイルのようなので、何処かファイルの先頭で 明示的にインポートするだけでも exe に含まれるようになると思います。 from imagecodecs import lzw_decode と試していた所を import imagecodecs._imagecodecs もしくは from imagecodecs._imagecodecs import lzw_decode への変更でlzw_decode の DelayedImportError はなくなると思います。 ですが、大元の問題解決になるかは不明で、他に依存モジュールがある場合は、 多分同様のエラーが出るので、追加で対応が必要です。
netz-eng

2020/08/18 10:48

.specファイル内で宣言してみましたが、同じエラーが出てしまいました。 というか、少し変なことが起きています。 sample.pyのなかで冒頭にfrom imagecodecs._imagecodecs import lzw_decodeを宣言しているにもかかわらず、そこは素通りで、あとに記述した関数内の「tifffile.imread」にのみ反応しています。 関数内でも宣言したほうがいいんでしょうか?
teamikl

2020/08/18 17:49 編集

LWZ 圧縮の tiff ファイルで試したところ、DelayedImportError を確認出来ました。 - 圧縮形式次第では発生しないので、他の回避策: imwrite のオプションで他を指定(未確認) - dist/APPNAME/imagecodecs フォルダ内を丸ごと差し替え(手作業で動作確認済) 詳しく調べてませんが pyinstaller のオプションで出来るはずです。hidden imports 辺り import を明示するのは動的にインポートしてるので、 pyinstaller のオプションを探した方が良さそうです。 他の案: --onefile 指定の場合は使えませんが、 ビルド用のバッチファイルを作り、pyinstaller 実行後に imagecodecs をコピーする。 追記: 必要なファイルは _imcd.cp38-win_amd64.pyd のみでした (※ファイル名の一部は環境により異なります)
netz-eng

2020/08/19 01:20

凄く詳細なところまで調べていただいて、ありがとうございます……! 今日帰宅次第、試してみます!
netz-eng

2020/08/19 11:17

ご回答の通り、.specファイル内のhiddenimportsに"imagecodecs._imcd"を指定したところ、無事動作を確認できました! わざわざライブラリまでインストールして調べていただき、本当にありがとうございます! 自分では八方手詰まりだったので、本当に助かりました……。 これからも困ったときはteratailで質問をすると思うので、また見かけた際にはお時間のあるときにお力添えいただけると嬉しいです。 重ね重ねありがとうございました!
smerkd

2021/12/05 20:48

You can also explicity add each decode to either your source code or hidden imports like so from imagecodecs import lzw_decode, jpeg_decode, png_decode, tiff_decode, gif_decode. I almost never have to copy the .pyd into the appdir as long as PyInstaller can determine source tree
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問