2016-10-27 2 views
5

Pyinstaller에서 코드를 실행하면 tiff 판독기가 정상적으로 작동합니다.Pyinstaller .exe에서 _tiffile 모듈을 찾을 수 없습니다. - 압축 된 일부 이미지를로드하는 속도가 매우 느립니다.

enter image description here

UserWarning: ImportError: No module named '_tifffile'. Loading of some compressed images will be very slow. Tifffile.c can be obtained at http://www.lfd.uci.edu/~gohlke 

그리고 충분한 확인이 초 정도 걸릴하는 데 사용되는 TIFF 파일은 이제 분 정도 걸릴 수 있습니다 NumPy와 배열로로드 : 사용 pyInstaller 중에 동결 후 나는 다음과 같은 경고를 얻을.

다음은 문제에 초점을 맞춘 간단한 코드입니다. this one과 같은 예제 tiff를로드하면 문제없이 빠르게로드해야합니다.

C:\Python35\python.exe C:\Python35\Scripts\pyinstaller.exe --additional-hooks-dir=. --clean --win-private-assemblies tiffile_problems.py을 사용하는 경우 위의 오류 메시지와 함께 작동하는 .exe 파일을 실행해야합니다. 같은 티파니를로드하려고하면 이제는 훨씬 더 오래 걸립니다.

tiffile_problems.py

#!/usr/bin/env python3 

import os 
import sys 
import traceback 
import numpy as np 
import matplotlib.pyplot as plt 

from PyQt4.QtGui import * 
from PyQt4.QtCore import * 

sys.path.append('..') 

from MBE_for_SO.util import fileloader, fileconverter 

class NotConvertedError(Exception): 
    pass 

class FileAlreadyInProjectError(Exception): 
    def __init__(self, filename): 
    self.filename = filename 

class Widget(QWidget): 
    def __init__(self, project, parent=None): 
    super(Widget, self).__init__(parent) 

    if not project: 
     self.setup_ui() 
     return 

    def setup_ui(self): 
    vbox = QVBoxLayout() 

    ## Related to importing Raws 
    self.setWindowTitle('Import Raw File') 

    #vbox.addWidget(QLabel('Set the size all data are to be rescaled to')) 

    grid = QGridLayout() 

    vbox.addLayout(grid) 
    vbox.addStretch() 

    self.setLayout(vbox) 
    self.resize(400, 220) 

    self.listview = QListView() 
    self.listview.setStyleSheet('QListView::item { height: 26px; }') 
    self.listview.setSelectionMode(QAbstractItemView.NoSelection) 
    vbox.addWidget(self.listview) 

    hbox = QVBoxLayout() 
    pb = QPushButton('New Video') 
    pb.clicked.connect(self.new_video) 
    hbox.addWidget(pb) 

    vbox.addLayout(hbox) 
    vbox.addStretch() 
    self.setLayout(vbox) 


    def convert_tif(self, filename): 
    path = os.path.splitext(os.path.basename(filename))[0] + '.npy' 
    #path = os.path.join(self.project.path, path) 

    progress = QProgressDialog('Converting tif to npy...', 'Abort', 0, 100, self) 
    progress.setAutoClose(True) 
    progress.setMinimumDuration(0) 
    progress.setValue(0) 

    def callback(value): 
     progress.setValue(int(value * 100)) 
     QApplication.processEvents() 

    try: 
     fileconverter.tif2npy(filename, path, callback) 
     print('Tifffile saved to wherever this script is') 
    except: 
     # qtutil.critical('Converting tiff to npy failed.') 
     progress.close() 
    return path 

    def to_npy(self, filename): 
    if filename.endswith('.raw'): 
     print('No raws allowed') 
     #filename = self.convert_raw(filename) 
    elif filename.endswith('.tif'): 
     filename = self.convert_tif(filename) 
    else: 
     raise fileloader.UnknownFileFormatError() 
    return filename 

    def import_file(self, filename): 
    if not filename.endswith('.npy'): 
     new_filename = self.to_npy(filename) 
     if not new_filename: 
     raise NotConvertedError() 
     else: 
     filename = new_filename 

    return filename 

    def import_files(self, filenames): 
    for filename in filenames: 
     try: 
     filename = self.import_file(filename) 
     except NotConvertedError: 
     # qtutil.warning('Skipping file \'{}\' since not converted.'.format(filename)) 
     print('Skipping file \'{}\' since not converted.'.format(filename)) 
     except FileAlreadyInProjectError as e: 
     # qtutil.warning('Skipping file \'{}\' since already in project.'.format(e.filename)) 
     print('Skipping file \'{}\' since already in project.'.format(e.filename)) 
     except: 
     # qtutil.critical('Import of \'{}\' failed:\n'.format(filename) +\ 
     # traceback.format_exc()) 
     print('Import of \'{}\' failed:\n'.format(filename) + traceback.format_exc()) 
     # else: 
     # self.listview.model().appendRow(QStandardItem(filename)) 

    def new_video(self): 
    filenames = QFileDialog.getOpenFileNames(
     self, 'Load images', QSettings().value('last_load_data_path'), 
     'Video files (*.npy *.tif *.raw)') 
    if not filenames: 
     return 
    QSettings().setValue('last_load_data_path', os.path.dirname(filenames[0])) 
    self.import_files(filenames) 

class MyPlugin: 
    def __init__(self, project): 
    self.name = 'Import video files' 
    self.widget = Widget(project) 

    def run(self): 
    pass 

if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    app.aboutToQuit.connect(app.deleteLater) 
    w = QMainWindow() 
    w.setCentralWidget(Widget(None)) 
    w.show() 
    app.exec_() 
    sys.exit() 

fileconverter.py

#!/usr/bin/env python3 

import os 
import numpy as np 

import tifffile as tiff 

class ConvertError(Exception): 
    pass 

def tif2npy(filename_from, filename_to, progress_callback): 
    with tiff.TiffFile(filename_from) as tif: 
    w, h = tif[0].shape 
    shape = len(tif), w, h 
    np.save(filename_to, np.empty(shape, tif[0].dtype)) 
    fp = np.load(filename_to, mmap_mode='r+') 
    for i, page in enumerate(tif): 
     progress_callback(i/float(shape[0]-1)) 
     fp[i] = page.asarray() 

def raw2npy(filename_from, filename_to, dtype, width, height, 
    num_channels, channel, progress_callback): 
    fp = np.memmap(filename_from, dtype, 'r') 
    frame_size = width * height * num_channels 
    if len(fp) % frame_size: 
     raise ConvertError() 
    num_frames = len(fp)/frame_size 
    fp = np.memmap(filename_from, dtype, 'r', 
     shape=(num_frames, width, height, num_channels)) 
    np.save(filename_to, np.empty((num_frames, width, height), dtype)) 
    fp_to = np.load(filename_to, mmap_mode='r+') 
    for i, frame in enumerate(fp): 
     progress_callback(i/float(len(fp)-1)) 
     fp_to[i] = frame[:,:,channel-1] 

fileloader.py

#!/usr/bin/env python3 

import numpy as np 

class UnknownFileFormatError(Exception): 
    pass 

def load_npy(filename): 
    frames = np.load(filename) 
    # frames[np.isnan(frames)] = 0 
    return frames 

def load_file(filename): 
    if filename.endswith('.npy'): 
    frames = load_npy(filename) 
    else: 
    raise UnknownFileFormatError() 
    return frames 

def load_reference_frame_npy(filename, offset): 
    frames_mmap = np.load(filename, mmap_mode='c') 
    if frames_mmap is None: 
    return None 
    frame = np.array(frames_mmap[offset]) 
    frame[np.isnan(frame)] = 0 
    frame = frame.swapaxes(0, 1) 
    if frame.ndim == 2: 
    frame = frame[:, ::-1] 
    elif frame.ndim == 3: 
    frame = frame[:, ::-1, :] 
    return frame 

def load_reference_frame(filename, offset=0): 
    if filename.endswith('.npy'): 
    frame = load_reference_frame_npy(filename, offset) 
    else: 
    raise UnknownFileFormatError() 
    return frame 

왜? 어떻게 해결할 수 있습니까? 나는 tifffile.py, tifffile.cpython-35.pyc, tifffile.c을 찾아서 .exe와 같은 디렉토리에 배치했습니다. 효과가 없습니다. _tifffile.cp35-win_amd64.pyd은 pyinstaller에 의해 만들어지고 .exe와 같은 디렉터리에 배치됩니다. 다른 옵션을 사용할 수 있는지 모르겠습니다.

tifffile_problems.spec

# -*- mode: python -*- 

block_cipher = None 


a = Analysis(['tiffile_problems.py'], 
      pathex=['C:\\Users\\Cornelis\\PycharmProjects\\tester\\MBE_for_SO'], 
      binaries=None, 
      datas=None, 
      hiddenimports=[], 
      hookspath=[], 
      runtime_hooks=[], 
      excludes=[], 
      win_no_prefer_redirects=False, 
      win_private_assemblies=True, 
      cipher=block_cipher) 
pyz = PYZ(a.pure, a.zipped_data, 
      cipher=block_cipher) 
exe = EXE(pyz, 
      a.scripts, 
      exclude_binaries=True, 
      name='tiffile_problems', 
      debug=False, 
      strip=False, 
      upx=True, 
      console=True) 
coll = COLLECT(exe, 
       a.binaries, 
       a.zipfiles, 
       a.datas, 
       strip=False, 
       upx=True, 
       name='tiffile_problems') 

tiffile.spec 코드를 검사에서 C:\Python35\python.exe C:\Python35\Scripts\pyinstaller.exe --additional-hooks-dir=. --clean --win-private-assemblies --onefile tiffile_problems.py

# -*- mode: python -*- 

block_cipher = None 


a = Analysis(['tiffile_problems.py'], 
      pathex=['C:\\Users\\Cornelis\\PycharmProjects\\tester\\MBE_for_SO'], 
      binaries=None, 
      datas=None, 
      hiddenimports=[], 
      hookspath=['.'], 
      runtime_hooks=[], 
      excludes=[], 
      win_no_prefer_redirects=False, 
      win_private_assemblies=True, 
      cipher=block_cipher) 
pyz = PYZ(a.pure, a.zipped_data, 
      cipher=block_cipher) 
exe = EXE(pyz, 
      a.scripts, 
      a.binaries, 
      a.zipfiles, 
      a.datas, 
      name='tiffile_problems', 
      debug=False, 
      strip=False, 
      upx=True, 
      console=True) 

답변

1

나는 이상한 생각이 듭니다. 여기에 문제가되는 __package__이 있습니다. 수정 프로그램의 정확한 이유를 추적하지 못했지만 최신 업데이트 pyinstaller을 사용하여 해결 된 것으로 보입니다. 당신의 버전을 확인합니다 :

→ pyinstaller --version 3.2.1

및 업데이트는 원래 물었을 때 2017 그래서이 도움이하지 않았을 년 1 월 15 일에 만들어졌다

→ pip3 install --upgrade pyinstaller

로 업그레이드하지만, 확실히 도움이됩니다.

0

를 사용하여, tifffile.py 생각된다 _tifffile라는 모듈을 찾고있는 것 같다 컴파일 된 C 확장의 예상 이름 :

try: 
    if __package__: 
     from . import _tifffile 
    else: 
     import _tifffile 
except ImportError: 
    warnings.warn(
     "ImportError: No module named '_tifffile'. " 
     "Loading of some compressed images will be very slow. " 
     "Tifffile.c can be obtained at http://www.lfd.uci.edu/~gohlke/") 

tifffile.cpython-35.pyctiffile.py에서 생성 된 바이트 코드입니다. 당신은 그걸로 귀찮게 할 필요가 없습니다.

.c 파일만으로는 도움이되지 않습니다. 사용 가능한 파이썬 확장을 생성하려면 컴파일해야합니다. _tiffile.cp35-win_amd64.pyd (시스템 및 파이썬 버전/설치에 따라 달라질 수 있음)이라는 이름이 필요하므로 import _tifffile에서 사용할 수 있습니다.

컴파일 작업을 수행하지 않으면 위압적 인 작업이 될 수 있습니다. 최대로 생각한다면 Python documentation을 사용하면 시작할 수 있습니다. same Compiler과 Python 버전이 컴파일 된 설정이 필요합니다.

그러나 더 간단한 해결책이있을 수 있습니다.코드가 고정되기 전에 정상적으로 작동하면 컴파일 된 확장이 시스템에 올바르게 설치되어있을 가능성이 있습니다. Pyinstaller는 tifffile.py을 찾을 수 있고 만족하기 때문에 아마도 그것을 놓칩니다. Python 디렉토리에 올바른 .pyd 파일이 있는지 확인하고 .pyd 파일을 포함하도록 지정한 .spec file Pyinstaller를 프로젝트에 맞게 수정할 수 있는지 확인하십시오.

+0

동결하기 전에 코드에 문제가 없습니다. Tiff 파일은 멋지고 빠르게로드됩니다. _tifffile.cp35-win_amd64.pyd는 pyinstaller에 의해 만들어지며 .exe가 들어있는 디렉토리에서 찾을 수 있습니다. 귀하의 링크를 통해 읽었지만 .spec에 _tifffile.cp35-win_amd64.pyd를 포함시키는 방법을 모르겠습니다. .spec을 질문에 추가했습니다. – Frikster

+0

나는 datas = [('_tifffile.cp35-win_amd64.pyd')]를 분석의 스펙 필드에 넣으려고했습니다. 그러나 내가 pyinstaler를 실행할 때 나는 그 스펙이 어떻게 되돌아 왔는지 알았다. – Frikster

+0

ok nvm .pyd 파일을 포함하도록 사양을 수정했습니다. 그러나 파일이 기본적으로 .exe가 포함 된 dir에 이미 배치되어 있기 때문에 예상 할 수있는 차이가 없습니다. 이것은 자연스럽게 나에게 무슨 일이 일어나는지 궁금해하게합니까? .c 파일이 이미 컴파일되었고 바로 거기에 import _tifffile을 사용하여 가져 오지 않는 이유는 무엇입니까? – Frikster

1

나는 실제로 인터넷을 둘러보고 놀기로 결정하면서 실제로 업서를 통해 이걸 보았습니다.

kazemakase는 정상적으로 실행될 때 올바르게 실행됩니다. __package__는 None이며, 패키지화 된 __package__가 tifffile로 설정되고 첫 번째 조건이 실행되고 모듈 tifffile에 상대적으로됩니다.

if __package__: 
    from . import _tifffile 
else: 
    import _tifffile 

난 그냥 새 폴더에 빈 __init__.py 파일을 생성, 사이트 패키지에 tifffile 폴더를 생성 tifffile.py을 배치하여, 수동으로 모듈 tifffile 변환, _tifffile.pyd 사이트 패키지에서 tifffile 폴더에 넣고 import 문을 변경하면됩니다.

import tifffile.tifffile as tiff 

전체 프로젝트에서 도움이된다면 잘 모르겠습니다. 그리고 내가 원래 http://www.lfd.uci.edu/~gohlke/pythonlibs/의 휠을 사용하여 컴파일 단계를 저장하기 위해 설치 했으므로 마일리지가 다를 수 있습니다. 처음에는 2.7에서 위의 작업을 수행했지만 3.5에서 수행 할 수있는 일부 테스트에서 제대로 작동하는 것으로 보입니다. 원래 생성 된 파일에서 테스트했을 때 .spec 파일에 아무것도 넣지 않아도됩니다.

+0

그래서 답을 확인하고 싶습니다. 그러나 나는 aconz2의 간단한 솔루션을 먼저 시도해 보았고 (또한 제거하고 고치 휠에서 tifffile을 다시 설치했다.) 이제 이전 pyinstaller 버전 (3.2)으로 되돌리려 고 할 때 오류를 복제 할 수 없습니다! 방금 고정되어 고정되어 있습니다! 엄청 이상해. 이것은 내가 지금 일하는 것이 기쁘다는 이유로 다른 우발적 인 변화가 있었는지 여부를 파고 들지 않기 때문에 답을 테스트 할 수 없다는 것을 의미합니다. 어느 쪽이든, 나는 당신에게 오류를 어디에서 왔는지 설명하는 것이 더 낫기 때문에 +1을 주겠다. – Frikster

+0

No probs .. 어쨌든 당신이 setuptools/packaging을 업그레이 드 했으므로 재시험을 할 수 없다고 생각합니다. – muggy

관련 문제