Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

360 lines
11 KiB

"""
A vtkTkImageViewerWidget for python, which is based on the
vtkTkImageWindowWidget.
Specify double=1 to get a double-buffered window.
Created by David Gobbi, Nov 1999
"""
import Tkinter
import math, os, sys
import vtk
from vtkLoadPythonTkWidgets import vtkLoadPythonTkWidgets
class vtkTkImageViewerWidget(Tkinter.Widget):
"""
A vtkTkImageViewerWidget for Python.
Use GetImageViewer() to get the vtkImageViewer.
Create with the keyword double=1 in order to generate a
double-buffered viewer.
Create with the keyword focus_on_enter=1 to enable
focus-follows-mouse. The default is for a click-to-focus mode.
"""
def __init__(self, master, cnf={}, **kw):
"""
Constructor.
Keyword arguments:
iv -- Use passed image viewer instead of creating a new one.
double -- If True, generate a double-buffered viewer.
Defaults to False.
focus_on_enter -- If True, use a focus-follows-mouse mode.
Defaults to False where the widget will use a click-to-focus
mode.
"""
# load the necessary extensions into tk
vtkLoadPythonTkWidgets(master.tk)
try: # use specified vtkImageViewer
imageViewer = kw['iv']
except KeyError: # or create one if none specified
imageViewer = vtk.vtkImageViewer()
doubleBuffer = 0
try:
if kw['double']:
doubleBuffer = 1
del kw['double']
except:
pass
# check if focus should follow mouse
if kw.get('focus_on_enter'):
self._FocusOnEnter = 1
del kw['focus_on_enter']
else:
self._FocusOnEnter = 0
kw['iv'] = imageViewer.GetAddressAsString("vtkImageViewer")
Tkinter.Widget.__init__(self, master, 'vtkTkImageViewerWidget',
cnf, kw)
if doubleBuffer:
imageViewer.GetRenderWindow().DoubleBufferOn()
self.BindTkImageViewer()
def __getattr__(self,attr):
# because the tk part of vtkTkImageViewerWidget must have
# the only remaining reference to the ImageViewer when
# it is destroyed, we can't actually store the ImageViewer
# as an attribute but instead have to get it from the tk-side
if attr == '_ImageViewer':
addr = self.tk.call(self._w, 'GetImageViewer')[5:]
return vtk.vtkImageViewer('_%s_vtkImageViewer_p' % addr)
raise AttributeError, self.__class__.__name__ + \
" has no attribute named " + attr
def GetImageViewer(self):
return self._ImageViewer
def Render(self):
self._ImageViewer.Render()
def BindTkImageViewer(self):
imager = self._ImageViewer.GetRenderer()
# stuff for window level text.
mapper = vtk.vtkTextMapper()
mapper.SetInput("none")
t_prop = mapper.GetTextProperty()
t_prop.SetFontFamilyToTimes()
t_prop.SetFontSize(18)
t_prop.BoldOn()
t_prop.ShadowOn()
self._LevelMapper = mapper
actor = vtk.vtkActor2D()
actor.SetMapper(mapper)
actor.SetLayerNumber(1)
actor.GetPositionCoordinate().SetValue(4,22)
actor.GetProperty().SetColor(1,1,0.5)
actor.SetVisibility(0)
imager.AddActor2D(actor)
self._LevelActor = actor
mapper = vtk.vtkTextMapper()
mapper.SetInput("none")
t_prop = mapper.GetTextProperty()
t_prop.SetFontFamilyToTimes()
t_prop.SetFontSize(18)
t_prop.BoldOn()
t_prop.ShadowOn()
self._WindowMapper = mapper
actor = vtk.vtkActor2D()
actor.SetMapper(mapper)
actor.SetLayerNumber(1)
actor.GetPositionCoordinate().SetValue(4,4)
actor.GetProperty().SetColor(1,1,0.5)
actor.SetVisibility(0)
imager.AddActor2D(actor)
self._WindowActor = actor
self._LastX = 0
self._LastY = 0
self._OldFocus = 0
self._InExpose = 0
# bindings
# window level
self.bind("<ButtonPress-1>",
lambda e,s=self: s.StartWindowLevelInteraction(e.x,e.y))
self.bind("<B1-Motion>",
lambda e,s=self: s.UpdateWindowLevelInteraction(e.x,e.y))
self.bind("<ButtonRelease-1>",
lambda e,s=self: s.EndWindowLevelInteraction())
# Get the value
self.bind("<ButtonPress-3>",
lambda e,s=self: s.StartQueryInteraction(e.x,e.y))
self.bind("<B3-Motion>",
lambda e,s=self: s.UpdateQueryInteraction(e.x,e.y))
self.bind("<ButtonRelease-3>",
lambda e,s=self: s.EndQueryInteraction())
self.bind("<Expose>",
lambda e,s=self: s.ExposeTkImageViewer())
self.bind("<Enter>",
lambda e,s=self: s.EnterTkViewer())
self.bind("<Leave>",
lambda e,s=self: s.LeaveTkViewer())
self.bind("<KeyPress-e>",
lambda e,s=self: s.quit())
self.bind("<KeyPress-r>",
lambda e,s=self: s.ResetTkImageViewer())
def GetImageViewer(self):
return self._ImageViewer
def Render(self):
self._ImageViewer.Render()
def _GrabFocus(self):
self._OldFocus=self.focus_get()
self.focus()
def EnterTkViewer(self):
if self._FocusOnEnter:
self._GrabFocus()
def LeaveTkViewer(self):
if self._FocusOnEnter and (self._OldFocus != None):
self._OldFocus.focus()
def ExposeTkImageViewer(self):
if (self._InExpose == 0):
self._InExpose = 1
self.update()
self._ImageViewer.Render()
self._InExpose = 0
def StartWindowLevelInteraction(self,x,y):
if not self._FocusOnEnter:
self._GrabFocus()
viewer = self._ImageViewer
self._LastX = x
self._LastY = y
self._Window = float(viewer.GetColorWindow())
self._Level = float(viewer.GetColorLevel())
# make the window level text visible
self._LevelActor.SetVisibility(1)
self._WindowActor.SetVisibility(1)
self.UpdateWindowLevelInteraction(x,y)
def EndWindowLevelInteraction(self):
# make the window level text invisible
self._LevelActor.SetVisibility(0)
self._WindowActor.SetVisibility(0)
self.Render()
def UpdateWindowLevelInteraction(self,x,y):
# compute normalized delta
dx = 4.0*(x - self._LastX)/self.winfo_width()*self._Window
dy = 4.0*(self._LastY - y)/self.winfo_height()*self._Level
# abs so that direction does not flip
if (self._Window < 0.0):
dx = -dx
if (self._Level < 0.0):
dy = -dy
# compute new window level
window = self._Window + dx
if (window < 0.0):
level = self._Level + dy
else:
level = self._Level - dy
viewer = self._ImageViewer
viewer.SetColorWindow(window)
viewer.SetColorLevel(level)
self._WindowMapper.SetInput("Window: %g" % window)
self._LevelMapper.SetInput("Level: %g" % level)
self.Render()
def ResetTkImageViewer(self):
# Reset: Set window level to show all values
viewer = self._ImageViewer
input = viewer.GetInput()
if (input == None):
return
# Get the extent in viewer
z = viewer.GetZSlice()
input.SetUpdateExtent(-99999,99999,-99999,99999,z,z)
input.Update()
(low,high) = input.GetScalarRange()
viewer.SetColorWindow(high - low)
viewer.SetColorLevel((high + low) * 0.5)
self.Render()
def StartQueryInteraction(self,x,y):
if not self._FocusOnEnter:
self._GrabFocus()
# Query PixleValue stuff
self._WindowActor.SetVisibility(1)
self.UpdateQueryInteraction(x,y)
def EndQueryInteraction(self):
self._WindowActor.SetVisibility(0)
self.Render()
def UpdateQueryInteraction(self,x,y):
viewer = self._ImageViewer
input = viewer.GetInput()
z = viewer.GetZSlice()
# y is flipped upside down
y = self.winfo_height() - y
# make sure point is in the whole extent of the image.
(xMin,xMax,yMin,yMax,zMin,zMax) = input.GetWholeExtent()
if (x < xMin or x > xMax or y < yMin or \
y > yMax or z < zMin or z > zMax):
return
input.SetUpdateExtent(x,x,y,y,z,z)
input.Update()
numComps = input.GetNumberOfScalarComponents()
text = ""
for i in xrange(numComps):
val = input.GetScalarComponentAsDouble(x,y,z,i)
text = "%s %.1f" % (text,val)
self._WindowMapper.SetInput("(%d, %d): %s" % (x,y,text))
self.Render()
#-----------------------------------------------------------------------------
# an example of how to use this widget
if __name__ == "__main__":
canvas = vtk.vtkImageCanvasSource2D()
canvas.SetNumberOfScalarComponents(3)
canvas.SetScalarType(3)
canvas.SetExtent(0,511,0,511,0,0)
canvas.SetDrawColor(100,100,0)
canvas.FillBox(0,511,0,511)
canvas.SetDrawColor(200,0,200)
canvas.FillBox(32,511,100,500)
canvas.SetDrawColor(100,0,0)
canvas.FillTube(550,20,30,400,5)
canvas.SetDrawColor(255,255,255)
canvas.DrawSegment3D(10,20,0,90,510,0)
canvas.SetDrawColor(200,50,50)
canvas.DrawSegment3D(510,90,0,10,20,0)
# Check segment clipping
canvas.SetDrawColor(0,200,0)
canvas.DrawSegment(-10,30,30,-10)
canvas.DrawSegment(-10,481,30,521)
canvas.DrawSegment(481,-10,521,30)
canvas.DrawSegment(481,521,521,481)
# Check Filling a triangle
canvas.SetDrawColor(20,200,200)
canvas.FillTriangle(-100,100,190,150,40,300)
# Check drawing a circle
canvas.SetDrawColor(250,250,10)
canvas.DrawCircle(350,350,200.0)
# Check drawing a point
canvas.SetDrawColor(250,250,250)
canvas.DrawPoint(350,350)
canvas.DrawPoint(350,550)
# Test filling functionality
canvas.SetDrawColor(55,0,0)
canvas.DrawCircle(450,350,80.0)
canvas.SetDrawColor(100,255,100)
canvas.FillPixel(450,350)
# Create the GUI: two renderer widgets and a quit button
frame = Tkinter.Frame()
widget = vtkTkImageViewerWidget(frame,width=512,height=512,double=1)
viewer = widget.GetImageViewer()
viewer.SetInput(canvas.GetOutput())
viewer.SetColorWindow(256)
viewer.SetColorLevel(127.5)
button = Tkinter.Button(frame,text="Quit",command=frame.quit)
widget.pack(side='top',padx=3,pady=3,fill='both',expand='t')
frame.pack(fill='both',expand='t')
button.pack(fill='x')
frame.mainloop()