2016-12-08 5 views
2

を私は(大:1300x2000)のjpegフィギュアをロードしています、それ以上の50×50の正方形のグリッドを描画し、カラーコード、それまで各正方形をクリックし、matplotlibのに。しかし、私は、プログラムが私のクリックにはるかに遅れていることに気付き、合理的なスピードで約50個の正方形をすばやく見つけた場合、追いつくのに30秒かかります。私は誰かがスピードアップできるかどうか疑問に思います。あなたがコピー/貼り付け(scipy、numpy、matplotlib、pillow、tkinterを持っていれば)準備が整ったスクリプトは以下ですスピードアップ私のインタラクティブmatplotlibのフィギュア

アドバイスを歓迎します。私は、コードがうまく説明されていない場合は、医師の科学者がそう私を許してください午前:

import matplotlib 
import matplotlib.pyplot as plt 
import tkinter 
import tkinter.filedialog 
from matplotlib.figure import Figure 
import math, sys 
import numpy as np 
import scipy.io as sio 
from PIL import Image 
from numpy import arange, sin, pi 
#from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 
#matplotlib.matplotlib_fname() 
import os, re 

global stridesize, classnumber,x, im,fn, plt, fig, mask 

classnumber = 1 



def onmove(eve): 
    global x,im, plt 
    print(eve.ydata) 
    print(eve.button) 
    if (eve.ydata !=None) and (eve.xdata !=None): 
     if eve.button==1: 
      print(eve.button) 
      xcoord = int(eve.xdata) 
      ycoord = int(eve.ydata) 
      startX = math.floor(xcoord/stridesize)*stridesize 
      startY = math.floor(ycoord/stridesize)*stridesize 
      # print(eve.xdata, int(eve.ydata), stridesize) 
      if(classnumber==1): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([255,0,0]) 
      if(classnumber==2): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,255,0]) 
      if(classnumber==3): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,0,255]) 
      if(classnumber==4): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([255,0,255]) 
      if(classnumber==5): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([255,255,0]) 
      if(classnumber==6): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,255,255]) 
      if(classnumber==7): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([100,255,50]) 


     if eve.button==3: 
      xcoord = int(eve.xdata) 
      ycoord = int(eve.ydata) 
      startX = math.floor(xcoord/stridesize)*stridesize 
      startY = math.floor(ycoord/stridesize)*stridesize 
      print(eve.xdata, int(eve.ydata), stridesize) 
      mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,0,0]) 
     im.set_data(mask) 
     fig.canvas.draw() 




def onclick(event): 

    if (event.ydata !=None) and (event.xdata !=None): 
     global x, im, fig 
     if event.button==1: 
      xcoord = int(event.xdata) 
      ycoord = int(event.ydata) 
      startX = math.floor(xcoord/stridesize)*stridesize 
      startY = math.floor(ycoord/stridesize)*stridesize 
      print(event.xdata, int(event.ydata), stridesize) 
      if(classnumber==1): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([255,0,0]) 
      if(classnumber==2): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,255,0]) 
      if(classnumber==3): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,0,255]) 
      if(classnumber==4): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([255,0,255]) 
      if(classnumber==5): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([255,255,0]) 
      if(classnumber==6): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,255,255]) 
      if(classnumber==7): 
       mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([100,255,50]) 
      im.set_data(mask) 

     if event.button==3: 
      xcoord = int(event.xdata) 
      ycoord = int(event.ydata) 
      startX = math.floor(xcoord/stridesize)*stridesize 
      startY = math.floor(ycoord/stridesize)*stridesize 
      print(event.xdata, int(event.ydata), stridesize) 
      mask[startY:startY+stridesize,startX:startX+stridesize,:]=np.array([0,0,0]) 
      im.set_data(mask) 
     fig.canvas.draw() 


def onpress(event): 
    global classnumber, mask 
    if (event.key == 'e'): 
     print("YO") 
     mask[:,:,:]=0; 
     im.set_data(mask) 
     fig.canvas.draw() 

    if (event.key=='s'): 
     savemask(fn) 
    if (event.key=='r'): 
     plt.figure(); 
     plt.imshow(mask); 
     plt.show(); 
    if int(event.key) > 0 and int(event.key) <9 : 
     classnumber = int(event.key) 
     print(classnumber) 


def onrelease(event): 
    print(event.button) 
# im.set_data(mask) 




def savemask(fn): 
    # matrixname =os.path.basename(filename) 
    # matrixname = re.sub(r'\.jpg','',matrixname) 
    pre, ext = os.path.splitext(fn) 
    savename_default = os.path.basename(pre) 
    options = {} 
    options['defaultextension'] = '' 
    options['filetypes'] = [('mat files', '.mat')] 
    options['initialdir'] = '' 
    options['initialfile'] = savename_default 
    options['title'] = 'Save file' 


    f = tkinter.filedialog.asksaveasfile(**options) 
    if f is None: # asksaveasfile return `None` if aadialog closed with "cancel". 
     return 
    name = f.name 
    sio.savemat(name,{'mask':mask},do_compression=True) 
    f.close() 




root = tkinter.Tk() 
root.withdraw() 

options = {} 

options['defaultextension'] = '.jpg' 

options['filetypes'] = [('Jpeg', '.jpg')] 

options['initialdir'] = 'C:\\' 
options['initialfile']= '' 
options['parent'] = root 

options['title'] = 'This is a title' 


fn= tkinter.filedialog.askopenfilename(**options) 


img = Image.open(fn) 
x = np.asarray(img) 
x.setflags(write=1) 
#masksize= (x.shape[0],x.shape[1],4) 
mask= np.zeros(x.shape,'uint8') 
#mask[:,:,3]=0.2 
fig = plt.figure() 
fig.suptitle(r'Key codes: 1 = Tumour, 2 = stroma-hypocellular, 3=stroma cellular (inflammatory)' '\n4 = proteinaceous, 5= red cells, 6,7: anyother,''\nRight click: clear square''\n r: review mask, e: erase mask, o : open mask image, s : save mask image;') 


im=plt.imshow(x) 
im=plt.imshow(mask,alpha=.25) 
ax = plt.gca(); 

stridesize = 50; 

plt.rcParams['keymap.save']='' 
ax.set_yticks(np.arange(0, x.shape[0], stridesize)); 
ax.set_xticks(np.arange(0, x.shape[1], stridesize)); 

cid = fig.canvas.mpl_connect('button_press_event', onclick) 
cod = fig.canvas.mpl_connect('key_press_event', onpress) 
#cdd = fig.canvas.mpl_connect('motion_notify_event', onmove) 
cdr = fig.canvas.mpl_connect('button_release_event', onrelease) 

plt.grid(b=True, which='both', color='black',linestyle='-') 
# 
plt.show() 

plt.ion() 
+0

上記のコードに根本的に何が間違っているかを知りたい人にとっては、1行を変更すると速度が倍増しました。だから私はすべての呼び出しを変更しました:fig.canvas.draw()to fig.canvas.draw_idle() – Maelstorm

答えて

3

まず、私はすべてのコストでglobal変数の使用を避けることをお勧めします。代わりにclassを使用して置き換えることができます。あなたのコードで

import numpy as np 

import matplotlib 
matplotlib.use('Qt4Agg') 

from matplotlib import pyplot as plt 
from matplotlib.colors import ListedColormap 

class ColorCode(object): 

    def __init__(self, block_size=(50,50), colors=['red', 'green', 'blue'], alpha=0.3): 
     self.by, self.bx = block_size # block size 
     self.selected = 0 # selected color 
     self.colors = colors 
     self.cmap = ListedColormap(colors) # color map for labels 
     self.mask = None # annotation mask 
     self.alpha = alpha 
     # Plots 
     self.fig = plt.figure() 
     self.ax = self.fig.gca() 
     # Events 
     self.fig.canvas.mpl_connect('button_press_event', self.on_click) 
     self.fig.canvas.mpl_connect('key_press_event', self.on_key) 

    def color_code(self, img): 
     self.imshape = img.shape[:2] 
     self.mask = np.full(img.shape[:2], -1, np.int32) # masked labels 
     self.ax.imshow(img) # show image 
     self.ax.imshow(np.ma.masked_where(self.mask < 0, self.mask), cmap=self.cmap, 
         alpha=self.alpha, vmin=0, vmax=len(self.colors)) # show mask 
     # Run 
     plt.show(block=True) 
     return self.mask 

    def on_click(self, event): 
     if not event.inaxes or self.mask is None: 
      return 
     # Get corresponding coordinates 
     py, px = int(event.ydata), int(event.xdata) 
     cy, cx = py//self.by, px//self.bx # grid coordinates 
     ymin = cy * self.by 
     ymax = min((cy+1) * self.by, self.imshape[0]) 
     xmin = cx * self.bx 
     xmax = min((cx+1) * self.bx, self.imshape[1]) 
     # Update mask 
     if event.button == 1: 
      self.mask[ymin:ymax, xmin:xmax] = self.selected 
     elif event.button == 3: 
      self.mask[ymin:ymax, xmin:xmax] = -1 
     # Update figure 
     self.ax.images[1].set_data(np.ma.masked_where(self.mask < 0, self.mask)) 
     self.fig.canvas.draw_idle() 

    def on_key(self, event): 
     ikey = int(event.key) 
     if 0 <= ikey < len(self.colors): 
      self.selected = ikey 

主な相違点は次のとおりです:怒鳴るあなたのコードが何を意図するものの完全に動作する要約バージョン検索

  1. これは、グローバル変数を使用していないが、その代わり、それはクラスを使用しています - 変数。実行するのがより安全になり、拡張/変更が容易になります。代わりにアノテーションの3次元maskの着色

  2. は、注釈は、すべてのピクセルは、それが属するカラーに示す範囲[1, len(colors)]内の値を有する2次元mask、として保存されています。 ListedColormapを使用して、プロットのカスタムカラーマップを設定することによって、プロットに色を追加します。

  3. それはそれのトップセグメンテーションマスク上の画像とオーバーレイを描画します。マスクは最初に-1で塗りつぶされています。これはラベルがないことを意味します。 numpyのmasked arrayを使用すると、mask < 0が表示されないのプロットをプロットして、プロットを透明にして、mask < 0と他の場合はマスクすることができます。可能な色の

  4. リストは、クラスにパラメータとして提供されています。 0からlen(colors)までの色を選択できます(現在、キーボードの数字にバインドされています)。

  5. fig.canvas.draw_idlefig.canvas.drawよりもはるかに優れています。後者は、描画が終了するまでプログラムをブロックします。

  6. すべてがクラスにあるため、コードは非常にクリーンになります。

あなたにコードを呼び出すことができ:各ピ​​クセルは、それがタグ付けされた(-1なしている場合)魔女の色で示す数値を有する標識maskを含むであろう

>>> random_image = np.random.randn(1000,2000, 3) 
>>> result = ColorCode().color_code(random_image) 

result。最後に、異なるブロックサイズの場合はblock_size=(100,100)、マスクの不透明度が低い場合はalpha=0.5alpha=1の場合はNone)など、他のパラメータをColorCodeのコンストラクタに渡すことができます。

はそれがあなたのために働く、または少なくともあなたはそれからいくつかのアイデアをつかむことができることを願っています。

+0

ありがとう。確かに2倍以上の速度向上確かに – Maelstorm

+0

@Maelstormは、左クリック*と*右クリック*の違いを追加するために質問を編集しました。 *右クリック*で消去できるようになりました。さらに、 'click + redraw'ではなく、' path + release + redraw'を保存しながらマウスを押して移動すると、マウスを押しながら興味のある領域全体にドラッグすることができますボタンを放すと、それらのすべてがリリースされると、その色にペイントされます。しかし、それはコード化することは明らかに難しいだろう。 –

+0

これに別のバックエンドを使用することはできますか?私はPy3とPyQt5を持っていますが、私は 'matplotlib.use()'を変更してもPyQt4エラーを受け取り続けます。 – percusse

関連する問題