From 2cb19aef3b667ba76de46ed16f916f326f7cbc58 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 1 Mar 2015 18:44:00 -0500 Subject: [PATCH 001/242] Separating fvtk to windows utils and actors for now --- dipy/viz/actors.py | 385 +++++++++++++++++++++++++++++++++++++++++++++ dipy/viz/utils.py | 171 ++++++++++++++++++++ dipy/viz/window.py | 268 +++++++++++++++++++++++++++++++ 3 files changed, 824 insertions(+) create mode 100644 dipy/viz/actors.py create mode 100644 dipy/viz/utils.py create mode 100644 dipy/viz/window.py diff --git a/dipy/viz/actors.py b/dipy/viz/actors.py new file mode 100644 index 0000000000..d6eb41ee41 --- /dev/null +++ b/dipy/viz/actors.py @@ -0,0 +1,385 @@ + +from __future__ import division, print_function, absolute_import + +import numpy as np + +from dipy.viz.colormap import line_colors +from dipy.viz.fvtk.util import numpy_to_vtk_points, numpy_to_vtk_colors +from dipy.viz.fvtk.util import set_input, trilinear_interp + +# Conditional import machinery for vtk +from dipy.utils.optpkg import optional_package + +#import vtk +# Allow import, but disable doctests if we don't have vtk +vtk, have_vtk, setup_module = optional_package('vtk') +colors, have_vtk_colors, _ = optional_package('vtk.util.colors') +numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') + + + +def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, + lod=True, lod_points=10 ** 4, lod_points_size=3, + spline_subdiv=None, lookup_colormap=None): + """ Uses streamtubes to visualize polylines + + Parameters + ---------- + lines : list + list of N curves represented as 2D ndarrays + colors : array (N, 3), tuple (3,) or colormap + opacity : float + linewidth : float + tube_sides : int + lod : bool + use vtkLODActor rather than vtkActor + lod_points : int + number of points to be used when LOD is in effect + lod_points_size : int + size of points when lod is in effect + spline_subdiv : int + number of splines subdivision to smooth streamtubes + lookup_colormap : bool + add a default lookup table to the colormap + + Examples + -------- + >>> from dipy.viz import fvtk + >>> r=fvtk.ren() + >>> lines=[np.random.rand(10, 3), np.random.rand(20, 3)] + >>> colors=np.random.rand(2, 3) + >>> c=fvtk.streamtube(lines, colors) + >>> fvtk.add(r,c) + >>> #fvtk.show(r) + + Notes + ----- + Streamtubes can be heavy on GPU when loading many streamlines and therefore, + you may experience slow rendering time depending on system GPU. A solution + to this problem is to reduce the number of points in each streamline. In Dipy + we provide an algorithm that will reduce the number of points on the straighter + parts of the streamline but keep more points on the curvier parts. This can + be used in the following way + + from dipy.tracking.distances import approx_polygon_track + lines = [approx_polygon_track(line, 0.2) for line in lines] + """ + # Poly data with lines and colors + poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) + next_input = poly_data + + # Set Normals + poly_normals = set_input(vtk.vtkPolyDataNormals(), next_input) + poly_normals.ComputeCellNormalsOn() + poly_normals.ComputePointNormalsOn() + poly_normals.ConsistencyOn() + poly_normals.AutoOrientNormalsOn() + poly_normals.Update() + next_input = poly_normals.GetOutputPort() + + # Spline interpolation + if (spline_subdiv is not None) and (spline_subdiv > 0) : + spline_filter = set_input(vtk.vtkSplineFilter(), next_input) + spline_filter.SetSubdivideToSpecified() + spline_filter.SetNumberOfSubdivisions(spline_subdiv) + spline_filter.Update() + next_input = spline_filter.GetOutputPort() + + # Add thickness to the resulting lines + tube_filter = set_input(vtk.vtkTubeFilter(), next_input) + tube_filter.SetNumberOfSides(tube_sides) + tube_filter.SetRadius(linewidth) + #tube_filter.SetVaryRadiusToVaryRadiusByScalar() + tube_filter.CappingOn() + tube_filter.Update() + next_input = tube_filter.GetOutputPort() + + # Poly mapper + poly_mapper = set_input(vtk.vtkPolyDataMapper(), next_input) + poly_mapper.ScalarVisibilityOn() + poly_mapper.SetScalarModeToUsePointFieldData() + poly_mapper.SelectColorArray("Colors") + poly_mapper.GlobalImmediateModeRenderingOn() + #poly_mapper.SetColorModeToMapScalars() + poly_mapper.Update() + + # Color Scale with a lookup table + if is_colormap: + if lookup_colormap is None: + lookup_colormap = colormap_lookup_table() + poly_mapper.SetLookupTable(lookup_colormap) + poly_mapper.UseLookupTableScalarRangeOn() + poly_mapper.Update() + + # Set Actor + if lod: + actor = vtk.vtkLODActor() + actor.SetNumberOfCloudPoints(lod_points) + actor.GetProperty().SetPointSize(lod_points_size) + else: + actor = vtk.vtkActor() + + actor.SetMapper(poly_mapper) + actor.GetProperty().SetAmbient(0.1) # .3 + actor.GetProperty().SetDiffuse(0.15) # .3 + actor.GetProperty().SetSpecular(0.05) # .3 + actor.GetProperty().SetSpecularPower(6) + #actor.GetProperty().SetInterpolationToGouraud() + actor.GetProperty().SetInterpolationToPhong() + actor.GetProperty().BackfaceCullingOn() + actor.GetProperty().SetOpacity(opacity) + + return actor + + +def line(lines, colors=None, opacity=1, linewidth=1, + spline_subdiv=None, lookup_colormap=None): + """ Create an actor for one or more lines. + + Parameters + ------------ + lines : list of arrays representing lines as 3d points for example + lines = [np.random.rand(10,3),np.random.rand(20,3)] + represents 2 lines the first with 10 points and the second with + 20 points in x,y,z coordinates. + colors : array, shape (N,3) + Colormap where every triplet is encoding red, green and blue e.g. + + :: + r1,g1,b1 + r2,g2,b2 + ... + rN,gN,bN + + where + + :: + 0=>> from dipy.viz import fvtk + >>> r=fvtk.ren() + >>> lines=[np.random.rand(10,3), np.random.rand(20,3)] + >>> colors=np.random.rand(2,3) + >>> c=fvtk.line(lines, colors) + >>> fvtk.add(r,c) + >>> #fvtk.show(r) + """ + # Poly data with lines and colors + poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) + next_input = poly_data + + # use spline interpolation + if (spline_subdiv is not None) and (spline_subdiv > 0) : + spline_filter = set_input(vtk.vtkSplineFilter(), next_input) + spline_filter.SetSubdivideToSpecified() + spline_filter.SetNumberOfSubdivisions(spline_subdiv) + spline_filter.Update() + next_input = spline_filter.GetOutputPort() + + poly_mapper = set_input(vtk.vtkPolyDataMapper(), next_input) + poly_mapper.ScalarVisibilityOn() + poly_mapper.SetScalarModeToUsePointFieldData() + poly_mapper.SelectColorArray("Colors") + #poly_mapper.SetColorModeToMapScalars() + poly_mapper.Update() + + # Color Scale with a lookup table + if is_colormap: + + if lookup_colormap is None: + lookup_colormap = colormap_lookup_table() + + poly_mapper.SetLookupTable(lookup_colormap) + poly_mapper.UseLookupTableScalarRangeOn() + poly_mapper.Update() + + # Set Actor + actor = vtk.vtkActor() + actor.SetMapper(poly_mapper) + actor.GetProperty().SetLineWidth(linewidth) + actor.GetProperty().SetOpacity(opacity) + + return actor + + +def lines_to_vtk_polydata(lines, colors=None): + """ Create a vtkPolyData with lines and colors + + Parameters + ---------- + lines : list + list of N curves represented as 2D ndarrays + colors : array (N, 3), tuple (3,) or colormap + + + Returns + ---------- + poly_data : VTK polydata + is_colormap : bool, true if the input color array was a colormap + """ + + #Get the 3d points_array + points_array = np.vstack(lines) + + nb_lines = len(lines) + nb_points = len(points_array) + + lines_range = range(nb_lines) + + # Get lines_array in vtk input format + lines_array = [] + points_per_line = np.zeros([nb_lines],np.int64) + current_position = 0 + for i in lines_range: + current_len = len(lines[i]) + points_per_line[i] = current_len + + end_position = current_position + current_len + lines_array += [current_len] + lines_array += range(current_position,end_position) + current_position = end_position + + lines_array = np.array(lines_array) + + # Set Points to vtk array format + vtk_points = numpy_to_vtk_points(points_array) + + # Set Lines to vtk array format + vtk_lines = vtk.vtkCellArray() + vtk_lines.GetData().DeepCopy(numpy_support.numpy_to_vtk(lines_array)) + vtk_lines.SetNumberOfCells(len(lines)) + + is_colormap = False + # Get colors_array (reformat to have colors for each points) + # - if/else tested and work in normal simple case + if colors is None: #set automatic rgb colors + cols_arr = line_colors(lines) + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) + else: + cols_arr = np.asarray(colors) + if cols_arr.dtype == np.object: # colors is a list of colors + vtk_colors = numpy_to_vtk_colors(255 * np.vstack(colors)) + else: + if len(cols_arr) == nb_points: # one colors per points / colormap way + vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) + is_colormap = True + + elif cols_arr.ndim == 1: # the same colors for all points + vtk_colors = numpy_to_vtk_colors( + np.tile(255 * cols_arr, (nb_points, 1)) ) + + + elif cols_arr.ndim == 2: # map color to each line + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) + else: # colormap + # get colors for each vertex + cols_arr = trilinear_interp(cols_arr, points_array) + vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) + is_colormap = True + + vtk_colors.SetName("Colors") + + #Create the poly_data + poly_data = vtk.vtkPolyData() + poly_data.SetPoints(vtk_points) + poly_data.SetLines(vtk_lines) + poly_data.GetPointData().SetScalars(vtk_colors) + return poly_data, is_colormap + + +def colormap_lookup_table(scale_range=(0,1), hue_range=(0.8,0), + saturation_range=(1,1), value_range=(0.8,0.8)): + """ Default Lookup table for the colormap + """ + vtk_lookup_table = vtk.vtkLookupTable() + vtk_lookup_table.SetRange(scale_range) + vtk_lookup_table.SetTableRange(scale_range) + + vtk_lookup_table.SetHueRange(hue_range) + vtk_lookup_table.SetSaturationRange(saturation_range) + vtk_lookup_table.SetValueRange(value_range) + + vtk_lookup_table.Build() + return vtk_lookup_table + + +def scalar_bar(lookup_table): + """ Default Scalar bar actor for the colormap + + Deepcopy the lookup_table because sometime vtkPolyDataMapper delete it + """ + lookup_table_copy = vtk.vtkLookupTable() + lookup_table_copy.DeepCopy(lookup_table) + scalar_bar = vtk.vtkScalarBarActor() + scalar_bar.SetLookupTable(lookup_table_copy) + scalar_bar.SetNumberOfLabels(6) + + return scalar_bar + + + +def plot_stats( values, names=None, colors=np.array([0,0,0,255]), + lookup_table=None, scalar_bar=None): + """ Plots statstics in a new windows + """ + + nb_lines = len(values) + if colors.ndim == 1: + colors = np.repeat(colors.reshape((1,-1)),nb_lines,axis=0) + + chart = vtk.vtkChartXY() + chart.SetShowLegend(True) + + table = vtk.vtkTable() + table.SetNumberOfRows(values.shape[1]) + + for i in range(nb_lines): + value = values[i] + vtk_array= numpy_support.numpy_to_vtk(value,deep=1) + vtk_array.SetName(names[i]) + table.AddColumn(vtk_array) + + color = colors[i] * 255 + if i>0: + graph_line = chart.AddPlot(vtk.vtkChart.LINE) + graph_line.SetInput(table, 0, i) + graph_line.SetColor(color[0],color[1],color[2],color[3]) + #graph_line.GetPen().SetLineType(vtk.vtkPen.SOLID_LINE) + graph_line.SetWidth(2.0) + + if lookup_table is not None : + graph_line.SetMarkerStyle(vtk.vtkPlotPoints.CIRCLE) + graph_line.ScalarVisibilityOn() + graph_line.SetLookupTable(lookup_table) + graph_line.SelectColorArray(i) + + #render plot + view = vtk.vtkContextView() + view.GetRenderer().SetBackground(colors[0][0], colors[0][1], colors[0][2]) + view.GetRenderWindow().SetSize(400, 300) + view.GetScene().AddItem(chart) + + if scalar_bar is not None : + view.GetRenderer().AddActor2D(scalar_bar) + + return view diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py new file mode 100644 index 0000000000..2b95b25966 --- /dev/null +++ b/dipy/viz/utils.py @@ -0,0 +1,171 @@ + +from __future__ import division, print_function, absolute_import + +import numpy as np +from dipy.core.ndindex import ndindex + +# Conditional import machinery for vtk +from dipy.utils.optpkg import optional_package + +#import vtk +# Allow import, but disable doctests if we don't have vtk +vtk, have_vtk, setup_module = optional_package('vtk') +ns, have_numpy_support, _ = optional_package('vtk.util.numpy_support') + + +def numpy_to_vtk_points(points): + """ numpy points array to a vtk points array + """ + vtk_points = vtk.vtkPoints() + vtk_points.SetData(ns.numpy_to_vtk(np.asarray(points), deep=True)) + return vtk_points + + +def numpy_to_vtk_colors(colors): + """ numpy color array to a vtk color array + + if colors are not already in UNSIGNED_CHAR + you may need to multiply by 255. + + Example + ---------- + >>> vtk_colors = numpy_to_vtk_colors(255 * float_array) + """ + vtk_colors = ns.numpy_to_vtk(np.asarray(colors), deep=True, + array_type=vtk.VTK_UNSIGNED_CHAR) + return vtk_colors + + +def set_input(vtk_object, input): + """ Generic input for vtk data, + depending of the type of input and vtk version + + Example + ---------- + >>> poly_mapper = set_input(vtk.vtkPolyDataMapper(), poly_data) + """ + if isinstance(input,vtk.vtkPolyData): + if vtk.VTK_MAJOR_VERSION <= 5: + vtk_object.SetInput(input) + else: + vtk_object.SetInputData(input) + elif isinstance(input,vtk.vtkAlgorithmOutput): + vtk_object.SetInputConnection(input) + + vtk_object.Update() + return vtk_object + + +def evec_from_lines(lines, use_line_dir=True): + """ Get eigen vectors from lines directions in a 3x3 array + + if use_line_dir is set to False + only use the points position information + + """ + + if use_line_dir: + lines_dir = [] + for line in lines: + lines_dir += [line[1:] - line[0:-1]] + directions = np.vstack(lines_dir) + else: + points = np.vstack(lines) + centered_points = points - np.mean(points,axis=0) + norm = np.sqrt(np.sum(centered_points**2,axis=1, keepdims=True)) + directions = centered_points/norm + + U, e_val, e_vec = np.linalg.svd(directions, full_matrices=False) + return e_vec + + +def rotation_from_lines(lines, use_line_dir=True, use_full_eig=False): + """ Get the rotation from lines directions in vtk.vtkTransform() object + + if use_line_dir is set to False + only use the points position information + + if use_full_eig is set to True + the rotation will be the full eigen_vector matrix + (not only the Yaw and Pitch) + + Example + ---------- + >>> camera = renderer.GetActiveCamera() + >>> rotation = rotation_from_lines(lines) + >>> camera.ApplyTransform(rotation) + >>> fvtk.show(renderer) + """ + e_vec = evec_from_lines(lines, use_line_dir) + + matrix = vtk.vtkMatrix4x4() + + if use_full_eig: + for (i, j) in ndindex((3, 3)) : + matrix.SetElement(j, i, e_vec[i,j]) + + else: + v1 = e_vec[2] + v2 = np.array([0,0,1]) + v3 = np.cross(v1,v2) + v3 = v3/(np.sqrt(np.sum(v3**2))) + v4 = np.cross(v3,v1) + v4 = v4/(np.sqrt(np.sum(v4**2))) + + m1 = np.array([v1,v4,v3]) + cos = np.dot(v2,v1) + sin = np.dot(v2,v4) + m2 = np.array([[cos,sin,0],[-sin,cos,0],[0,0,1]]) + + m = np.dot( np.dot(m1.T,m2), m1) + + for (i, j) in ndindex((3, 3)) : + matrix.SetElement(i, j, m[i,j]) + + transform = vtk.vtkTransform() + transform.SetMatrix(matrix) + return transform + + +def trilinear_interp(input_array, indices): + """ Evaluate the input_array data at the given indices + """ + + assert (input_array.ndim > 2 )," array need to be at least 3dimensions" + assert (input_array.ndim < 5 )," dont support array with more than 4 dims" + + x_indices = indices[:,0] + y_indices = indices[:,1] + z_indices = indices[:,2] + + x0 = x_indices.astype(np.integer) + y0 = y_indices.astype(np.integer) + z0 = z_indices.astype(np.integer) + x1 = x0 + 1 + y1 = y0 + 1 + z1 = z0 + 1 + + #Check if xyz1 is beyond array boundary: + x1[np.where(x1==input_array.shape[0])] = x0.max() + y1[np.where(y1==input_array.shape[1])] = y0.max() + z1[np.where(z1==input_array.shape[2])] = z0.max() + + if input_array.ndim == 3: + x = x_indices - x0 + y = y_indices - y0 + z = z_indices - z0 + elif input_array.ndim == 4: + x = np.expand_dims(x_indices - x0, axis = 1) + y = np.expand_dims(y_indices - y0, axis = 1) + z = np.expand_dims(z_indices - z0, axis = 1) + + output = (input_array[x0,y0,z0]*(1-x)*(1-y)*(1-z) + + input_array[x1,y0,z0]*x*(1-y)*(1-z) + + input_array[x0,y1,z0]*(1-x)*y*(1-z) + + input_array[x0,y0,z1]*(1-x)*(1-y)*z + + input_array[x1,y0,z1]*x*(1-y)*z + + input_array[x0,y1,z1]*(1-x)*y*z + + input_array[x1,y1,z0]*x*y*(1-z) + + input_array[x1,y1,z1]*x*y*z) + + return output diff --git a/dipy/viz/window.py b/dipy/viz/window.py new file mode 100644 index 0000000000..23d5e14cdc --- /dev/null +++ b/dipy/viz/window.py @@ -0,0 +1,268 @@ +from __future__ import division, print_function, absolute_import + +# Conditional import machinery for vtk +from dipy.utils.optpkg import optional_package + +#import vtk +# Allow import, but disable doctests if we don't have vtk +vtk, have_vtk, setup_module = optional_package('vtk') +colors, have_vtk_colors, _ = optional_package('vtk.util.colors') +numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') + +if have_vtk: + + version = vtk.vtkVersion.GetVTKSourceVersion().split(' ')[-1] + major_version = vtk.vtkVersion.GetVTKMajorVersion() + + +def renderer(background=None): + """ Create a renderer. + + Parameters + ---------- + background : tuple + Initial background color of renderer + + Returns + ------- + v : vtkRenderer() object + Renderer. + + + Examples + -------- + >>> from dipy.viz import fvtk + >>> import numpy as np + >>> r=fvtk.ren() + >>> lines=[np.random.rand(10,3)] + >>> c=fvtk.line(lines, fvtk.colors.red) + >>> fvtk.add(r,c) + >>> #fvtk.show(r) + """ + ren = vtk.vtkRenderer() + if background is not None: + ren.SetBackground(background) + + return ren + + +ren = renderer() + +def add(ren, a): + """ Add a specific actor + """ + if isinstance(a, vtk.vtkVolume): + ren.AddVolume(a) + else: + ren.AddActor(a) + + +def rm(ren, a): + """ Remove a specific actor + """ + ren.RemoveActor(a) + + +def clear(ren): + """ Remove all actors from the renderer + """ + ren.RemoveAllViewProps() + + +def rm_all(ren): + """ Remove all actors from the renderer + """ + clear(ren) + + +def show(ren, title='Dipy', size=(300, 300), png_magnify=1): + """ Show window + + Notes + ----- + To save a screenshot press's' and check your current directory + for ``fvtk.png``. + + Parameters + ------------ + ren : vtkRenderer() object + As returned from function ``ren()``. + title : string + A string for the window title bar. + size : (int, int) + ``(width, height)`` of the window + png_magnify : int + Number of times to magnify the screenshot. + + Notes + ----- + If you want to: + + * navigate in the the 3d world use the left - middle - right mouse buttons + * reset the screen press 'r' + * save a screenshot press 's' + * quit press 'q' + + See also + --------- + dipy.viz.fvtk.record + + Examples + ---------- + >>> import numpy as np + >>> from dipy.viz import fvtk + >>> r=fvtk.ren() + >>> lines=[np.random.rand(10,3),np.random.rand(20,3)] + >>> colors=np.array([[0.2,0.2,0.2],[0.8,0.8,0.8]]) + >>> c=fvtk.line(lines,colors) + >>> fvtk.add(r,c) + >>> l=fvtk.label(r) + >>> fvtk.add(r,l) + >>> #fvtk.show(r) + + See also + ---------- + dipy.viz.fvtk.record + + """ + + ren.ResetCamera() + window = vtk.vtkRenderWindow() + window.AddRenderer(ren) + # window.SetAAFrames(6) + window.SetWindowName(title) + window.SetSize(size[0], size[1]) + style = vtk.vtkInteractorStyleTrackballCamera() + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(window) + #iren.SetPicker(picker) + + def key_press(obj, event): + + key = obj.GetKeySym() + if key == 's' or key == 'S': + print('Saving image...') + renderLarge = vtk.vtkRenderLargeImage() + if major_version <= 5: + renderLarge.SetInput(ren) + else: + renderLarge.SetInputData(ren) + renderLarge.SetMagnification(png_magnify) + renderLarge.Update() + writer = vtk.vtkPNGWriter() + writer.SetInputConnection(renderLarge.GetOutputPort()) + writer.SetFileName('fvtk.png') + writer.Write() + print('Look for fvtk.png in your current working directory.') + + iren.AddObserver('KeyPressEvent', key_press) + iren.SetInteractorStyle(style) + iren.Initialize() + #picker.Pick(85, 126, 0, ren) + window.Render() + iren.Start() + + # window.RemoveAllObservers() + # ren.SetRenderWindow(None) + window.RemoveRenderer(ren) + ren.SetRenderWindow(None) + + +def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, + out_path=None, path_numbering=False, n_frames=1, az_ang=10, + magnification=1, size=(300, 300), verbose=False): + """ This will record a video of your scene + + Records a video as a series of ``.png`` files of your scene by rotating the + azimuth angle az_angle in every frame. + + Parameters + ----------- + ren : vtkRenderer() object + as returned from function ren() + cam_pos : None or sequence (3,), optional + camera position + cam_focal : None or sequence (3,), optional + camera focal point + cam_view : None or sequence (3,), optional + camera view up + out_path : str, optional + output directory for the frames + path_numbering : bool + when recording it changes out_path ot out_path + str(frame number) + n_frames : int, optional + number of frames to save, default 1 + az_ang : float, optional + azimuthal angle of camera rotation. + magnification : int, optional + how much to magnify the saved frame + + Examples + --------- + >>> from dipy.viz import fvtk + >>> r=fvtk.ren() + >>> a=fvtk.axes() + >>> fvtk.add(r,a) + >>> #uncomment below to record + >>> #fvtk.record(r) + >>> #check for new images in current directory + """ + if ren is None: + ren = vtk.vtkRenderer() + + renWin = vtk.vtkRenderWindow() + renWin.AddRenderer(ren) + renWin.SetSize(size[0], size[1]) + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(renWin) + + # ren.GetActiveCamera().Azimuth(180) + + ren.ResetCamera() + + renderLarge = vtk.vtkRenderLargeImage() + if major_version <= 5: + renderLarge.SetInput(ren) + else: + renderLarge.SetInputData(ren) + renderLarge.SetMagnification(magnification) + renderLarge.Update() + + writer = vtk.vtkPNGWriter() + ang = 0 + + if cam_pos is not None: + cx, cy, cz = cam_pos + ren.GetActiveCamera().SetPosition(cx, cy, cz) + if cam_focal is not None: + fx, fy, fz = cam_focal + ren.GetActiveCamera().SetFocalPoint(fx, fy, fz) + if cam_view is not None: + ux, uy, uz = cam_view + ren.GetActiveCamera().SetViewUp(ux, uy, uz) + + cam = ren.GetActiveCamera() + if verbose: + print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) + print('Camera Focal Point (%.2f,%.2f,%.2f)' % cam.GetFocalPoint()) + print('Camera View Up (%.2f,%.2f,%.2f)' % cam.GetViewUp()) + + for i in range(n_frames): + ren.GetActiveCamera().Azimuth(ang) + renderLarge = vtk.vtkRenderLargeImage() + renderLarge.SetInput(ren) + renderLarge.SetMagnification(magnification) + renderLarge.Update() + writer.SetInputConnection(renderLarge.GetOutputPort()) + # filename='/tmp/'+str(3000000+i)+'.png' + if path_numbering: + if out_path is None: + filename = str(1000000 + i) + '.png' + else: + filename = out_path + str(1000000 + i) + '.png' + else: + filename = out_path + writer.SetFileName(filename) + writer.Write() + + ang = +az_ang From eb19eb8c42645a8fa436eea99b4124091adde84b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 1 Mar 2015 19:35:49 -0500 Subject: [PATCH 002/242] Added new test with possiblity of saving and analyzing output from fvtk --- dipy/viz/{actors.py => actor.py} | 5 ++-- dipy/viz/tests/test_fvtk_actors.py | 43 ++++++++++++++++++++++++++++++ dipy/viz/window.py | 3 ++- 3 files changed, 47 insertions(+), 4 deletions(-) rename dipy/viz/{actors.py => actor.py} (98%) create mode 100644 dipy/viz/tests/test_fvtk_actors.py diff --git a/dipy/viz/actors.py b/dipy/viz/actor.py similarity index 98% rename from dipy/viz/actors.py rename to dipy/viz/actor.py index d6eb41ee41..742cc22184 100644 --- a/dipy/viz/actors.py +++ b/dipy/viz/actor.py @@ -4,8 +4,8 @@ import numpy as np from dipy.viz.colormap import line_colors -from dipy.viz.fvtk.util import numpy_to_vtk_points, numpy_to_vtk_colors -from dipy.viz.fvtk.util import set_input, trilinear_interp +from dipy.viz.utils import numpy_to_vtk_points, numpy_to_vtk_colors +from dipy.viz.utils import set_input, trilinear_interp # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -17,7 +17,6 @@ numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') - def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, lod=True, lod_points=10 ** 4, lod_points_size=3, spline_subdiv=None, lookup_colormap=None): diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py new file mode 100644 index 0000000000..7230d22df1 --- /dev/null +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -0,0 +1,43 @@ +import numpy as np +import scipy as sp + +from dipy.viz import actor +from dipy.viz import window + +import numpy.testing as npt + + +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_streamtube_and_line_actors(): + + # Create a renderer + renderer = window.renderer() + + # Create 2 lines with 2 different colors + lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + colors = np.random.rand(2, 3) + c = actor.line(lines, colors) + window.add(renderer, c) + + # create streamtubes of the same lines and shift them a bit + c2 = actor.streamtube(lines, colors) + c2.SetPosition(2, 0, 0) + window.add(renderer, c2) + + # window.show(renderer) + + window.record(renderer, out_path='streamtube.png') + result = sp.misc.imread('streamtube.png') + bg = renderer.GetBackground() + + if bg == (0, 0, 0): + + npt.assert_equal(result.sum() > 0, True) + + else: + + raise ValueError('Renderer background not black') + + +test_streamtube_and_line_actors() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 23d5e14cdc..25342549e8 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -48,6 +48,7 @@ def renderer(background=None): ren = renderer() + def add(ren, a): """ Add a specific actor """ @@ -224,7 +225,7 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, if major_version <= 5: renderLarge.SetInput(ren) else: - renderLarge.SetInputData(ren) + renderLarge.SetInput(ren) renderLarge.SetMagnification(magnification) renderLarge.Update() From a8296d3da1268448f6124dca505c696b21183578 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 1 Mar 2015 20:39:08 -0500 Subject: [PATCH 003/242] NF: adding the capability of interacting with widgets and actors directly --- dipy/viz/tests/test_fvtk_widgets.py | 42 ++++++++++++++++++++++++++ dipy/viz/widget.py | 47 +++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 dipy/viz/tests/test_fvtk_widgets.py create mode 100644 dipy/viz/widget.py diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py new file mode 100644 index 0000000000..d39182c5dc --- /dev/null +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -0,0 +1,42 @@ +import numpy as np + +from dipy.viz import actor +from dipy.viz import window +from dipy.viz import widget + +import numpy.testing as npt + + +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_slider_widget(): + + renderer = window.renderer() + + # Create 2 lines with 2 different colors + lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) + c = actor.streamtube(lines, colors) + window.add(renderer, c) + + from dipy.viz.window import vtk + + ren_win = vtk.vtkRenderWindow() + ren_win.AddRenderer(renderer) + + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(ren_win) + + def print_status(obj, event): + print(obj) + print(event) + + slider = widget.slider(iren=iren, callback=print_status) + + iren.Initialize() + + ren_win.Render() + iren.Start() + + +test_slider_widget() diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py new file mode 100644 index 0000000000..57eb9c7c52 --- /dev/null +++ b/dipy/viz/widget.py @@ -0,0 +1,47 @@ + + +# Conditional import machinery for vtk +from dipy.utils.optpkg import optional_package + +#import vtk +# Allow import, but disable doctests if we don't have vtk +vtk, have_vtk, setup_module = optional_package('vtk') +colors, have_vtk_colors, _ = optional_package('vtk.util.colors') +numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') + + +def slider(iren, callback, min_value=0, max_value=255, value=125, + label="Slider", + coord1=(0.8, 0.5), coord2=(0.9, 0.5), + length=0.04, width=0.02, + cap_length=0.01, cap_width=0.01, + tube_width=0.005, + label_format="%0.0lf"): + """ Create a 2D slider with normalized window coordinates + """ + + slider_rep = vtk.vtkSliderRepresentation2D() + slider_rep.SetMinimumValue(min_value) + slider_rep.SetMaximumValue(max_value) + slider_rep.SetValue(value) + slider_rep.SetTitleText(label) + slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPoint1Coordinate().SetValue(*coord1) + slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPoint2Coordinate().SetValue(*coord2) + slider_rep.SetSliderLength(length) + slider_rep.SetSliderWidth(length) + slider_rep.SetEndCapLength(cap_length) + slider_rep.SetEndCapWidth(cap_width) + slider_rep.SetTubeWidth(tube_width) + + slider_rep.SetLabelFormat(label_format) + + slider = vtk.vtkSliderWidget() + slider.SetInteractor(iren) + slider.SetRepresentation(slider_rep) + slider.SetAnimationModeToAnimate() + slider.KeyPressActivationOff() + slider.AddObserver("InteractionEvent", callback) + slider.SetEnabled(True) + return slider From 7088a2065bfdfdf7c38beaa0e1da99e6fc65e6e5 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 1 Mar 2015 21:36:55 -0500 Subject: [PATCH 004/242] Removed button widget for now --- dipy/viz/tests/test_fvtk_widgets.py | 1 + dipy/viz/widget.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index d39182c5dc..ac2d95a9be 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -30,6 +30,7 @@ def test_slider_widget(): def print_status(obj, event): print(obj) print(event) + renderer.SetBackground(np.random.rand(3)) slider = widget.slider(iren=iren, callback=print_status) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 57eb9c7c52..4343a3eada 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -45,3 +45,5 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, slider.AddObserver("InteractionEvent", callback) slider.SetEnabled(True) return slider + + From dbc86c2de0a72769adc79b0243c8c0366d9adf28 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 2 Mar 2015 10:36:30 -0500 Subject: [PATCH 005/242] BF: when recording and renderer is already created don't reset the camera --- dipy/viz/tests/test_fvtk_actors.py | 37 +++++++++++++++++++++--------- dipy/viz/window.py | 5 ++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 7230d22df1..de5f8cd7d3 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -1,3 +1,4 @@ +import os import numpy as np import scipy as sp @@ -5,6 +6,21 @@ from dipy.viz import window import numpy.testing as npt +from nibabel.tmpdirs import TemporaryDirectory + + +def analyze_output(renderer, fname, cleanup=True): + result = sp.misc.imread(fname) + bg = renderer.GetBackground() + if bg == (0, 0, 0): + npt.assert_equal(result.sum() > 0, True) + else: + raise ValueError('The background of the renderer is not black') + + #if cleanup: + # os.remove(fname) + + return True @npt.dec.skipif(not actor.have_vtk) @@ -25,19 +41,18 @@ def test_streamtube_and_line_actors(): c2.SetPosition(2, 0, 0) window.add(renderer, c2) - # window.show(renderer) - - window.record(renderer, out_path='streamtube.png') - result = sp.misc.imread('streamtube.png') - bg = renderer.GetBackground() + window.show(renderer) - if bg == (0, 0, 0): + #with TemporaryDirectory() as tmpdir: + tmpdir = '' + fname = os.path.join(tmpdir, 'streamtube.png') + print(fname) + window.record(renderer, out_path=fname) + npt.assert_(analyze_output(renderer, fname)) - npt.assert_equal(result.sum() > 0, True) - - else: - raise ValueError('Renderer background not black') +if __name__ == "__main__": -test_streamtube_and_line_actors() + # npt.run_module_suite() + test_streamtube_and_line_actors() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 25342549e8..dbc8bd54be 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -136,7 +136,7 @@ def show(ren, title='Dipy', size=(300, 300), png_magnify=1): style = vtk.vtkInteractorStyleTrackballCamera() iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(window) - #iren.SetPicker(picker) + # iren.SetPicker(picker) def key_press(obj, event): @@ -219,7 +219,8 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, # ren.GetActiveCamera().Azimuth(180) - ren.ResetCamera() + if ren is None: + ren.ResetCamera() renderLarge = vtk.vtkRenderLargeImage() if major_version <= 5: From 06e950a3ea77754dd2b84b299597c23df5cdc77f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 2 Mar 2015 10:37:15 -0500 Subject: [PATCH 006/242] BF: Minor tab addition --- dipy/viz/window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index dbc8bd54be..69246eea6a 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -220,7 +220,7 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, # ren.GetActiveCamera().Azimuth(180) if ren is None: - ren.ResetCamera() + ren.ResetCamera() renderLarge = vtk.vtkRenderLargeImage() if major_version <= 5: From 21f310c7bd6496711920d4a62782ed2fb964e83b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 2 Mar 2015 18:39:56 -0500 Subject: [PATCH 007/242] Starting working on experimental butcher slicer of 3D and 4D images --- dipy/viz/actor.py | 110 ++++++++++++++++++++++++++--- dipy/viz/fvtk.py | 3 + dipy/viz/tests/test_fvtk_actors.py | 40 +++++++---- dipy/viz/utils.py | 76 ++++++++++++++++++++ 4 files changed, 204 insertions(+), 25 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 742cc22184..dc24ac9f2d 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -5,17 +5,98 @@ from dipy.viz.colormap import line_colors from dipy.viz.utils import numpy_to_vtk_points, numpy_to_vtk_colors -from dipy.viz.utils import set_input, trilinear_interp +from dipy.viz.utils import set_input, trilinear_interp, ndarray_to_vtkimagedata # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package -#import vtk # Allow import, but disable doctests if we don't have vtk vtk, have_vtk, setup_module = optional_package('vtk') colors, have_vtk_colors, _ = optional_package('vtk.util.colors') numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') +if have_vtk: + + version = vtk.vtkVersion.GetVTKSourceVersion().split(' ')[-1] + major_version = vtk.vtkVersion.GetVTKMajorVersion() + +def butcher(data, affine): + + image_data = ndarray_to_vtkimagedata(data) + + # Set the transform (identity if none given) +# transform = vtk.vtkTransform() +# if affine is not None: +# transform_matrix = vtk.vtkMatrix4x4() +# transform_matrix.DeepCopy(( +# affine[0][0], affine[0][1], affine[0][2], affine[0][3], +# affine[1][0], affine[1][1], affine[1][2], affine[1][3], +# affine[2][0], affine[2][1], affine[2][2], affine[2][3], +# affine[3][0], affine[3][1], affine[3][2], affine[3][3])) +# transform.SetMatrix(transform_matrix) +# transform.Inverse() + + # Set the reslicing +# image_resliced = vtk.vtkImageReslice() +# set_input(image_resliced, image_data) +# image_resliced.SetResliceTransform(transform) +# image_resliced.AutoCropOutputOn() +# image_resliced.SetInterpolationModeToLinear() +# image_resliced.Update() + + # Get back resliced image + im = image_data #image_resliced.GetOutput() + +# An outline provides context around the data. +# outline_data = vtk.vtkOutlineFilter() +# set_input(outline_data, im) +# +# mapOutline = vtk.vtkPolyDataMapper() +# mapOutline.SetInputConnection(outline_data.GetOutputPort()) +# outline_ = vtk.vtkActor() +# outline_.SetMapper(mapOutline) +# outline_.GetProperty().SetColor(1, 0, 0) + + # Now we are creating three orthogonal planes passing through the + # volume. Each plane uses a different texture map and therefore has + # diferent coloration. + + # Start by creatin a black/white lookup table. + lut = vtk.vtkLookupTable() + lut.SetTableRange(data.min(), data.max()) + lut.SetSaturationRange(0, 0) + lut.SetHueRange(0, 0) + lut.SetValueRange(0, 1) + lut.SetRampToLinear() + lut.Build() + + x1, x2, y1, y2, z1, z2 = im.GetExtent() + + print(x1, x2, y1, y2, z1, z2) + + # Create the first of the three planes. The filter vtkImageMapToColors + # maps the data through the corresponding lookup table created above. + # The vtkImageActor is a type of vtkProp and conveniently displays an + # image on a single quadrilateral plane. It does this using texture + # mapping and as a result is quite fast. (Note: the input image has to + # be unsigned char values, which the vtkImageMapToColors produces.) + # Note also that by specifying the DisplayExtent, the pipeline + # requests data of this extent and the vtkImageMapToColors only + # processes a slice of data. + plane_colors = vtk.vtkImageMapToColors() + plane_colors.SetLookupTable(lut) + set_input(plane_colors, im) + plane_colors.Update() + + saggital = vtk.vtkImageActor() + # set_input(saggital, plane_colors.GetOutput()) + saggital.GetMapper().SetInputConnection(plane_colors.GetOutputPort()) + saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) + # saggital.SetDisplayExtent(25, 25, 0, 49, 0, 49) + saggital.Update() + + return saggital + def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, lod=True, lod_points=10 ** 4, lod_points_size=3, @@ -132,7 +213,8 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, def line(lines, colors=None, opacity=1, linewidth=1, - spline_subdiv=None, lookup_colormap=None): + spline_subdiv=None, lod=True, lod_points=10 ** 4, lod_points_size=3, + lookup_colormap=None): """ Create an actor for one or more lines. Parameters @@ -211,6 +293,13 @@ def line(lines, colors=None, opacity=1, linewidth=1, poly_mapper.Update() # Set Actor + if lod: + actor = vtk.vtkLODActor() + actor.SetNumberOfCloudPoints(lod_points) + actor.GetProperty().SetPointSize(lod_points_size) + else: + actor = vtk.vtkActor() + actor = vtk.vtkActor() actor.SetMapper(poly_mapper) actor.GetProperty().SetLineWidth(linewidth) @@ -336,7 +425,6 @@ def scalar_bar(lookup_table): return scalar_bar - def plot_stats( values, names=None, colors=np.array([0,0,0,255]), lookup_table=None, scalar_bar=None): """ Plots statstics in a new windows @@ -344,9 +432,9 @@ def plot_stats( values, names=None, colors=np.array([0,0,0,255]), nb_lines = len(values) if colors.ndim == 1: - colors = np.repeat(colors.reshape((1,-1)),nb_lines,axis=0) + colors = np.repeat(colors.reshape((1, -1)), nb_lines, axis=0) - chart = vtk.vtkChartXY() + chart = vtk.vtkChartXY() chart.SetShowLegend(True) table = vtk.vtkTable() @@ -354,15 +442,15 @@ def plot_stats( values, names=None, colors=np.array([0,0,0,255]), for i in range(nb_lines): value = values[i] - vtk_array= numpy_support.numpy_to_vtk(value,deep=1) + vtk_array = numpy_support.numpy_to_vtk(value, deep=1) vtk_array.SetName(names[i]) table.AddColumn(vtk_array) color = colors[i] * 255 - if i>0: + if i > 0: graph_line = chart.AddPlot(vtk.vtkChart.LINE) graph_line.SetInput(table, 0, i) - graph_line.SetColor(color[0],color[1],color[2],color[3]) + graph_line.SetColor(color[0], color[1], color[2], color[3]) #graph_line.GetPen().SetLineType(vtk.vtkPen.SOLID_LINE) graph_line.SetWidth(2.0) @@ -372,13 +460,13 @@ def plot_stats( values, names=None, colors=np.array([0,0,0,255]), graph_line.SetLookupTable(lookup_table) graph_line.SelectColorArray(i) - #render plot + # render plot view = vtk.vtkContextView() view.GetRenderer().SetBackground(colors[0][0], colors[0][1], colors[0][2]) view.GetRenderWindow().SetSize(400, 300) view.GetScene().AddItem(chart) - if scalar_bar is not None : + if scalar_bar is not None: view.GetRenderer().AddActor2D(scalar_bar) return view diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 7f0addb66f..9226835509 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -1516,6 +1516,9 @@ def slicer(vol, voxsz=(1.0, 1.0, 1.0), plane_i=[0], plane_j=None, for k in range(vol.shape[2]): im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) + #from dipy.viz.utils import ndarray_to_vtkimagedata + #im = ndarray_to_vtkimagedata(vol) + # An outline provides context around the data. outlineData = vtk.vtkOutlineFilter() if major_version <= 5: diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index de5f8cd7d3..fdc031e405 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -17,20 +17,35 @@ def analyze_output(renderer, fname, cleanup=True): else: raise ValueError('The background of the renderer is not black') - #if cleanup: - # os.remove(fname) - return True +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_butcher(): + + renderer = window.renderer() + + # data = np.random.randint(0, 255, (50, 50, 50)) + data = (255 * np.random.rand(50, 50, 50)) + affine = np.eye(4) + + from dipy.viz import fvtk + #slicer = fvtk.slicer(data) + + slicer = actor.butcher(data, affine) + + window.add(renderer, slicer) + + window.show(renderer) + + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_streamtube_and_line_actors(): - # Create a renderer renderer = window.renderer() - # Create 2 lines with 2 different colors lines = [np.random.rand(10, 3), np.random.rand(20, 3)] colors = np.random.rand(2, 3) c = actor.line(lines, colors) @@ -41,18 +56,15 @@ def test_streamtube_and_line_actors(): c2.SetPosition(2, 0, 0) window.add(renderer, c2) - window.show(renderer) - - #with TemporaryDirectory() as tmpdir: - tmpdir = '' - fname = os.path.join(tmpdir, 'streamtube.png') - print(fname) - window.record(renderer, out_path=fname) - npt.assert_(analyze_output(renderer, fname)) + # window.show(renderer) + with TemporaryDirectory() as tmpdir: + fname = os.path.join(tmpdir, 'streamtube.png') + window.record(renderer, out_path=fname) + npt.assert_(analyze_output(renderer, fname)) if __name__ == "__main__": # npt.run_module_suite() - test_streamtube_and_line_actors() + test_butcher() diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 2b95b25966..e6fa26393e 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -169,3 +169,79 @@ def trilinear_interp(input_array, indices): input_array[x1,y1,z1]*x*y*z) return output + + +def rescale_to_uint8(data): + """ Rescales value of a ndarray to 8 bits unsigned integer + + This function rescales the values of the input between 0 and 255, + then copies it to a new 8 bits unsigned integer array. + + Parameters + ---------- + data : ndarray + + Return + ------ + uint8 : ndarray + + Note + ---- + NANs are clipped to 0. If min equals max, result will be all 0. + + """ + + temp = np.array(data, dtype=np.float64) + temp[np.isnan(temp)] = 0 + temp -= np.min(temp) + if np.max(temp) != 0.0: + temp /= np.max(temp) + temp *= 255.0 + temp = np.array(np.round(temp), dtype=np.uint8) + + return temp + + +def ndarray_to_vtkimagedata(data): + r""" Transforms ndarray into VTK tangible object + + Transforms an ndarray into a uint8 vtkImageData object. This + function uses rescale_to_uint8 so it can be streamed as a unsigned + char string to vtk. + + Parameters + ---------- + data : ndarray + + Return + ------ + vtkImageData + """ + + nb_composites = len(data.shape) + + if nb_composites == 3: + [sx, sy, sz] = data.shape + nb_channels = 1 + elif nb_composites == 4: + [sx, sy, sz, nb_channels] = data.shape + else: + raise ValueError('Only 3D and 4D arrays are supported') + + # Convert data to uint8 properly + uint8_data = rescale_to_uint8(data) + uint8_data = np.swapaxes(uint8_data, 0, 2) + string_data = uint8_data.tostring() + + # Set data importer + data_source = vtk.vtkImageImport() + data_source.CopyImportVoidPointer(string_data, len(string_data)) + data_source.SetDataScalarTypeToUnsignedChar() + data_source.SetNumberOfScalarComponents(nb_channels) + data_source.SetDataExtent(0, sx-1, 0, sy-1, 0, sz-1) + data_source.SetWholeExtent(0, sx-1, 0, sy-1, 0, sz-1) + #data_source.SetDataExtentToWholeExtent() + + data_source.Update() + + return data_source.GetOutput() \ No newline at end of file From 9fe80df643b6e3ded0e751894b8e207719325382 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 2 Mar 2015 20:56:39 -0500 Subject: [PATCH 008/242] NF: butcher reads data correctly --- dipy/viz/actor.py | 69 ++++++++++++++++++++---------- dipy/viz/tests/test_fvtk_actors.py | 3 +- dipy/viz/utils.py | 44 +------------------ 3 files changed, 50 insertions(+), 66 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index dc24ac9f2d..850e7d14c9 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -1,5 +1,5 @@ -from __future__ import division, print_function, absolute_import +#from __future__ import division, print_function, absolute_import import numpy as np @@ -22,30 +22,53 @@ def butcher(data, affine): - image_data = ndarray_to_vtkimagedata(data) + # im = ndarray_to_vtkimagedata(data) + + vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) + vol = vol.astype('uint8') + + im = vtk.vtkImageData() + if major_version <= 5: + im.SetScalarTypeToUnsignedChar() + I, J, K = vol.shape[:3] + im.SetDimensions(I, J, K) + voxsz = (1., 1., 1) + # im.SetOrigin(0,0,0) + im.SetSpacing(voxsz[2], voxsz[0], voxsz[1]) + if major_version <= 5: + im.AllocateScalars() + else: + im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) + + # copy data + # replace with ndindex + for i in range(vol.shape[0]): + for j in range(vol.shape[1]): + for k in range(vol.shape[2]): + im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) # Set the transform (identity if none given) -# transform = vtk.vtkTransform() -# if affine is not None: -# transform_matrix = vtk.vtkMatrix4x4() -# transform_matrix.DeepCopy(( -# affine[0][0], affine[0][1], affine[0][2], affine[0][3], -# affine[1][0], affine[1][1], affine[1][2], affine[1][3], -# affine[2][0], affine[2][1], affine[2][2], affine[2][3], -# affine[3][0], affine[3][1], affine[3][2], affine[3][3])) -# transform.SetMatrix(transform_matrix) -# transform.Inverse() + transform = vtk.vtkTransform() + if affine is not None: + transform_matrix = vtk.vtkMatrix4x4() + transform_matrix.DeepCopy(( + affine[0][0], affine[0][1], affine[0][2], affine[0][3], + affine[1][0], affine[1][1], affine[1][2], affine[1][3], + affine[2][0], affine[2][1], affine[2][2], affine[2][3], + affine[3][0], affine[3][1], affine[3][2], affine[3][3])) + transform.SetMatrix(transform_matrix) + transform.Inverse() # Set the reslicing -# image_resliced = vtk.vtkImageReslice() -# set_input(image_resliced, image_data) -# image_resliced.SetResliceTransform(transform) -# image_resliced.AutoCropOutputOn() -# image_resliced.SetInterpolationModeToLinear() -# image_resliced.Update() + image_resliced = vtk.vtkImageReslice() + image_resliced.SetInputData(im) + image_resliced.SetResliceTransform(transform) + image_resliced.AutoCropOutputOn() + image_resliced.SetInterpolationModeToLinear() + image_resliced.Update() # Get back resliced image - im = image_data #image_resliced.GetOutput() + #im = image_data #image_resliced.GetOutput() # An outline provides context around the data. # outline_data = vtk.vtkOutlineFilter() @@ -63,7 +86,8 @@ def butcher(data, affine): # Start by creatin a black/white lookup table. lut = vtk.vtkLookupTable() - lut.SetTableRange(data.min(), data.max()) + lut.SetTableRange(0, 255) + #print(data.min(), data.max()) lut.SetSaturationRange(0, 0) lut.SetHueRange(0, 0) lut.SetValueRange(0, 1) @@ -85,13 +109,14 @@ def butcher(data, affine): # processes a slice of data. plane_colors = vtk.vtkImageMapToColors() plane_colors.SetLookupTable(lut) - set_input(plane_colors, im) + plane_colors.SetInputConnection(image_resliced.GetOutputPort()) plane_colors.Update() saggital = vtk.vtkImageActor() # set_input(saggital, plane_colors.GetOutput()) saggital.GetMapper().SetInputConnection(plane_colors.GetOutputPort()) - saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) + #saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) + saggital.SetDisplayExtent(x1, x2, y1, y2, 25, 25) # saggital.SetDisplayExtent(25, 25, 0, 49, 0, 49) saggital.Update() diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index fdc031e405..40c9a37afb 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import os import numpy as np import scipy as sp @@ -30,7 +31,7 @@ def test_butcher(): data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) - from dipy.viz import fvtk + #from dipy.viz import fvtk #slicer = fvtk.slicer(data) slicer = actor.butcher(data, affine) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index e6fa26393e..2bff0b0410 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -202,46 +202,4 @@ def rescale_to_uint8(data): return temp -def ndarray_to_vtkimagedata(data): - r""" Transforms ndarray into VTK tangible object - - Transforms an ndarray into a uint8 vtkImageData object. This - function uses rescale_to_uint8 so it can be streamed as a unsigned - char string to vtk. - - Parameters - ---------- - data : ndarray - - Return - ------ - vtkImageData - """ - - nb_composites = len(data.shape) - - if nb_composites == 3: - [sx, sy, sz] = data.shape - nb_channels = 1 - elif nb_composites == 4: - [sx, sy, sz, nb_channels] = data.shape - else: - raise ValueError('Only 3D and 4D arrays are supported') - - # Convert data to uint8 properly - uint8_data = rescale_to_uint8(data) - uint8_data = np.swapaxes(uint8_data, 0, 2) - string_data = uint8_data.tostring() - - # Set data importer - data_source = vtk.vtkImageImport() - data_source.CopyImportVoidPointer(string_data, len(string_data)) - data_source.SetDataScalarTypeToUnsignedChar() - data_source.SetNumberOfScalarComponents(nb_channels) - data_source.SetDataExtent(0, sx-1, 0, sy-1, 0, sz-1) - data_source.SetWholeExtent(0, sx-1, 0, sy-1, 0, sz-1) - #data_source.SetDataExtentToWholeExtent() - - data_source.Update() - - return data_source.GetOutput() \ No newline at end of file +s \ No newline at end of file From bf9f3d0441b85d1f601f0cbe991c7ec7fef1b08a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 4 Mar 2015 14:47:27 -0500 Subject: [PATCH 009/242] NF: Dipy version is now shown in the fvtk window --- dipy/viz/window.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 69246eea6a..121d810370 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -3,6 +3,8 @@ # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package +from dipy import __version__ as dipy_version + #import vtk # Allow import, but disable doctests if we don't have vtk vtk, have_vtk, setup_module = optional_package('vtk') @@ -131,7 +133,8 @@ def show(ren, title='Dipy', size=(300, 300), png_magnify=1): window = vtk.vtkRenderWindow() window.AddRenderer(ren) # window.SetAAFrames(6) - window.SetWindowName(title) + + window.SetWindowName(title + ' ' + dipy_version) window.SetSize(size[0], size[1]) style = vtk.vtkInteractorStyleTrackballCamera() iren = vtk.vtkRenderWindowInteractor() @@ -147,7 +150,7 @@ def key_press(obj, event): if major_version <= 5: renderLarge.SetInput(ren) else: - renderLarge.SetInputData(ren) + renderLarge.SetInput(ren) renderLarge.SetMagnification(png_magnify) renderLarge.Update() writer = vtk.vtkPNGWriter() From 1a2dc5254246c60ce81964219aedf727ac5541ce Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 4 Mar 2015 18:48:36 -0500 Subject: [PATCH 010/242] Created new example --- dipy/viz/actor.py | 13 +++---- dipy/viz/tests/test_fvtk_actors.py | 16 +++++++- dipy/viz/utils.py | 3 -- doc/examples/interact_data.py | 59 ++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 doc/examples/interact_data.py diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 850e7d14c9..c1e7b66a3f 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -5,7 +5,8 @@ from dipy.viz.colormap import line_colors from dipy.viz.utils import numpy_to_vtk_points, numpy_to_vtk_colors -from dipy.viz.utils import set_input, trilinear_interp, ndarray_to_vtkimagedata +from dipy.viz.utils import set_input, trilinear_interp +from dipy.core.ndindex import ndindex # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -41,11 +42,9 @@ def butcher(data, affine): im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) # copy data - # replace with ndindex - for i in range(vol.shape[0]): - for j in range(vol.shape[1]): - for k in range(vol.shape[2]): - im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) + for index in ndindex(vol.shape): + i, j, k = index + im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) # Set the transform (identity if none given) transform = vtk.vtkTransform() @@ -116,7 +115,7 @@ def butcher(data, affine): # set_input(saggital, plane_colors.GetOutput()) saggital.GetMapper().SetInputConnection(plane_colors.GetOutputPort()) #saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) - saggital.SetDisplayExtent(x1, x2, y1, y2, 25, 25) + saggital.SetDisplayExtent(x1, x2, y1, y2, z2/2, z2/2) # saggital.SetDisplayExtent(25, 25, 0, 49, 0, 49) saggital.Update() diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 40c9a37afb..d437d5c398 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -31,12 +31,24 @@ def test_butcher(): data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) - #from dipy.viz import fvtk - #slicer = fvtk.slicer(data) + stream_actor = actor.line(streamlines) slicer = actor.butcher(data, affine) window.add(renderer, slicer) + window.add(renderer, stream_actor) + + window.show(renderer) + + with TemporaryDirectory() as tmpdir: + fname = os.path.join(tmpdir, 'butcher.png') + window.record(renderer, out_path=fname) + npt.assert_(analyze_output(renderer, fname)) + + slicer.SetDisplayExtent(0, 255, 0, 255, 149/3, 149/3) + # print(slicer.GetExtent()) + + slicer.Update() window.show(renderer) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 2bff0b0410..116a67fb26 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -200,6 +200,3 @@ def rescale_to_uint8(data): temp = np.array(np.round(temp), dtype=np.uint8) return temp - - -s \ No newline at end of file diff --git a/doc/examples/interact_data.py b/doc/examples/interact_data.py new file mode 100644 index 0000000000..d8d1b94d32 --- /dev/null +++ b/doc/examples/interact_data.py @@ -0,0 +1,59 @@ +import numpy as np +from dipy.viz import actor, window, widget + +# Change with Stanford data +dname = '/home/eleftherios/Data/Cunnane_Elef/08-111-609-AC15/work/' +import nibabel as nib +from nibabel import trackvis as tv + +img = nib.load(dname + 't1_brain_warp.nii.gz') +data = img.get_data() +affine = img.get_affine() + +streams, hdr = tv.read(dname + 'results/bundles/cst.right.trk', + points_space="rasmm") +streamlines = [s[0] for s in streams] + +streams, hdr = tv.read(dname + 'results/bundles/af.left.trk', + points_space="rasmm") +streamlines += [s[0] for s in streams] + +streams, hdr = tv.read(dname + 'results/bundles/cc_1.trk', + points_space="rasmm") +streamlines += [s[0] for s in streams] + +renderer = window.renderer() +stream_actor = actor.line(streamlines) +slicer = actor.butcher(data, affine) + +window.add(renderer, stream_actor) +window.add(renderer, slicer) + + +def change_slice(obj, event): + global slicer + z = int(np.round(obj.GetSliderRepresentation().GetValue())) + + print(obj) + print(event) + print(z) + slicer.SetDisplayExtent(0, 255, 0, 255, z, z) + slicer.Update() + +import vtk + +ren_win = vtk.vtkRenderWindow() +ren_win.AddRenderer(renderer) + +iren = vtk.vtkRenderWindowInteractor() +iren.SetRenderWindow(ren_win) + +slider = widget.slider(iren=iren, callback=change_slice) + +iren.Initialize() + + + +ren_win.Render() +iren.Start() + From 60e7b5dc4d508b197aa8f400631038fc500c3698 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 5 Mar 2015 16:19:10 -0500 Subject: [PATCH 011/242] NF: adding buttons is now possible but without normalized coordinates --- dipy/viz/tests/test_fvtk_widgets.py | 41 +++++++++++++++++++- dipy/viz/widget.py | 58 ++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index ac2d95a9be..c7fbeeb46e 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -6,7 +6,6 @@ import numpy.testing as npt - @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_slider_widget(): @@ -39,5 +38,43 @@ def print_status(obj, event): ren_win.Render() iren.Start() +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_button_widget(): + + from dipy.viz.window import vtk + + renderer = window.renderer() + + lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) + stream_actor = actor.streamtube(lines, colors) + + window.add(renderer, stream_actor) + + renderer.ResetCamera() + + ren_win = vtk.vtkRenderWindow() + ren_win.AddRenderer(renderer) + + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(ren_win) + + def callback(obj, event): + print(obj) + print('Pressed') + + button = widget.button(iren=iren, callback=callback) + + iren.Initialize() + + ren_win.Render() + iren.Start() + + + + +if __name__ == '__main__': -test_slider_widget() + #test_slider_widget() + test_button_widget() diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 4343a3eada..894ce8e95f 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -9,7 +9,6 @@ colors, have_vtk_colors, _ = optional_package('vtk.util.colors') numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') - def slider(iren, callback, min_value=0, max_value=255, value=125, label="Slider", coord1=(0.8, 0.5), coord2=(0.9, 0.5), @@ -47,3 +46,60 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, return slider +def compute_bounds(renderer, normalized_display_position, size): + upperRight = vtk.vtkCoordinate() + upperRight.SetCoordinateSystemToNormalizedDisplay() + upperRight.SetValue(normalized_display_position[0], normalized_display_position[1]) + bds = [0.0]*6 + bds[0] = upperRight.GetComputedDisplayValue(renderer)[0] - size[0] + bds[1] = bds[0] + size[0] + bds[2] = upperRight.GetComputedDisplayValue(renderer)[1] - size[1] + bds[3] = bds[2] + size[1] + return bds + + +def button(iren, callback): + + image1 = vtk.vtkPNGReader() + image1.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res.png') + image1.Update() + + image2 = vtk.vtkPNGReader() + image2.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res2.png') + image2.Update() + + #button_rep = vtk.vtkProp3DButtonRepresentation() + button_rep = vtk.vtkTexturedButtonRepresentation2D() + button_rep.SetNumberOfStates(1) + button_rep.SetButtonTexture(0, image1.GetOutput()) + #button_rep.SetButtonTexture(1, image2.GetOutput()) + + button_rep.SetPlaceFactor(1) + + + + #bds = compute_bounds(ren, (1.5, 1.5), (100, 100)) + #print(bds) + button_rep.PlaceWidget([0., 100, 50, 500, 0, 0]) + + #button_rep.PlaceWidget(bds) + + button = vtk.vtkButtonWidget() + button.SetInteractor(iren) + button.SetRepresentation(button_rep) + button.On() + button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) + + #ren = iren.GetRenderWindow().GetRenderers().GetFirstRenderer() + #bds = compute_bounds(ren, (.5, .5), (100, 100)) + #button_rep.PlaceWidget(bds) + + #button_rep.SetPlaceFactor(1) + + #button_rep.PlaceWidget((0.75, 0, 0), (250, 450)) + # see state changed + #http://vtk.org/gitweb?p=VTK.git;a=blob;f=Interaction/Widgets/Testing/Cxx/TestButtonWidget.cxx + #http://vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget + button.SetEnabled(True) + + return button \ No newline at end of file From 828e1aca258c4a410d67f5876b38926d6c224f41 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 5 Mar 2015 16:22:48 -0500 Subject: [PATCH 012/242] Added link for infor on normalized coordinates --- dipy/viz/widget.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 894ce8e95f..c0634c2a70 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -76,7 +76,8 @@ def button(iren, callback): button_rep.SetPlaceFactor(1) - + #READ THIS! + #http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget #bds = compute_bounds(ren, (1.5, 1.5), (100, 100)) #print(bds) From 0030bd4b832f258196ae9d5e60d3f08c1df5b88a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 5 Mar 2015 20:40:13 -0500 Subject: [PATCH 013/242] The button's rep (PlaceWidget) has to be called after Window render --- dipy/viz/tests/test_fvtk_widgets.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index c7fbeeb46e..bd395352f4 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -66,9 +66,17 @@ def callback(obj, event): button = widget.button(iren=iren, callback=callback) + from dipy.viz.widget import compute_bounds + iren.Initialize() ren_win.Render() + + bds = compute_bounds(renderer, (0.5, 0.5), (200, 100)) + + button.GetRepresentation().PlaceWidget(bds) + button.On() + iren.Start() From ac9e7905b8062732ea2d030ed3a6d2ba52e9e044 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 6 Mar 2015 14:23:06 -0500 Subject: [PATCH 014/242] Example now supports native img coords or world coords --- doc/examples/interact_data.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/examples/interact_data.py b/doc/examples/interact_data.py index d8d1b94d32..9da7de5945 100644 --- a/doc/examples/interact_data.py +++ b/doc/examples/interact_data.py @@ -1,15 +1,19 @@ import numpy as np from dipy.viz import actor, window, widget + # Change with Stanford data dname = '/home/eleftherios/Data/Cunnane_Elef/08-111-609-AC15/work/' import nibabel as nib from nibabel import trackvis as tv +world_coords = True + img = nib.load(dname + 't1_brain_warp.nii.gz') data = img.get_data() affine = img.get_affine() + streams, hdr = tv.read(dname + 'results/bundles/cst.right.trk', points_space="rasmm") streamlines = [s[0] for s in streams] @@ -22,9 +26,17 @@ points_space="rasmm") streamlines += [s[0] for s in streams] +if not world_coords: + from dipy.tracking.streamline import transform_streamlines + streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) + renderer = window.renderer() stream_actor = actor.line(streamlines) -slicer = actor.butcher(data, affine) + +if not world_coords: + slicer = actor.butcher(data, affine=np.eye(4)) +else: + slicer = actor.butcher(data, affine) window.add(renderer, stream_actor) window.add(renderer, slicer) From 18bb7e2091b48e062c320d1f55eb049ab9cf5097 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 11 Mar 2015 12:06:35 -0400 Subject: [PATCH 015/242] BF: Added 1 second delay before recording. This resolves problems when recording becomes too fast --- dipy/viz/window.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 121d810370..f4916269aa 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -4,6 +4,7 @@ from dipy.utils.optpkg import optional_package from dipy import __version__ as dipy_version +from time import sleep #import vtk # Allow import, but disable doctests if we don't have vtk @@ -47,8 +48,8 @@ def renderer(background=None): return ren - -ren = renderer() +if have_vtk: + ren = renderer() def add(ren, a): @@ -211,8 +212,11 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, >>> #fvtk.record(r) >>> #check for new images in current directory """ + if ren is None: ren = vtk.vtkRenderer() + else: + sleep(1) renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren) From 519b8d7d068e30430a8c011ac39780470f986808 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 11 Mar 2015 18:02:40 -0400 Subject: [PATCH 016/242] pep8 --- dipy/data/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dipy/data/__init__.py b/dipy/data/__init__.py index 5a72f9da18..765ffcf99e 100644 --- a/dipy/data/__init__.py +++ b/dipy/data/__init__.py @@ -28,7 +28,6 @@ def loads_compat(bytes): from dipy.core.gradients import GradientTable, gradient_table from dipy.core.sphere import Sphere, HemiSphere from dipy.sims.voxel import SticksAndBall -import numpy as np from dipy.data.fetcher import (fetch_scil_b0, read_scil_b0, fetch_stanford_hardi, @@ -43,7 +42,7 @@ def loads_compat(bytes): fetch_syn_data, read_syn_data, fetch_stanford_t1, - read_stanford_t1) + read_stanford_t1) from ..utils.arrfuncs import as_native_array from dipy.tracking.streamline import relist_streamlines From 7b9ec0436d6eed9241bf883231baf4ee9beec95a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 11 Mar 2015 18:07:11 -0400 Subject: [PATCH 017/242] NF: added support for offscreen snapshot --- dipy/viz/actor.py | 25 ++++++------ dipy/viz/tests/test_fvtk_actors.py | 46 +++++++++++----------- dipy/viz/window.py | 61 +++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 40 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index c1e7b66a3f..5a31c4c795 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,9 +21,8 @@ version = vtk.vtkVersion.GetVTKSourceVersion().split(' ')[-1] major_version = vtk.vtkVersion.GetVTKMajorVersion() -def butcher(data, affine): - # im = ndarray_to_vtkimagedata(data) +def butcher(data, affine): vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) vol = vol.astype('uint8') @@ -69,15 +68,15 @@ def butcher(data, affine): # Get back resliced image #im = image_data #image_resliced.GetOutput() -# An outline provides context around the data. -# outline_data = vtk.vtkOutlineFilter() -# set_input(outline_data, im) -# -# mapOutline = vtk.vtkPolyDataMapper() -# mapOutline.SetInputConnection(outline_data.GetOutputPort()) -# outline_ = vtk.vtkActor() -# outline_.SetMapper(mapOutline) -# outline_.GetProperty().SetColor(1, 0, 0) + # An outline provides context around the data. + # outline_data = vtk.vtkOutlineFilter() + # set_input(outline_data, im) + # + # mapOutline = vtk.vtkPolyDataMapper() + # mapOutline.SetInputConnection(outline_data.GetOutputPort()) + # outline_ = vtk.vtkActor() + # outline_.SetMapper(mapOutline) + # outline_.GetProperty().SetColor(1, 0, 0) # Now we are creating three orthogonal planes passing through the # volume. Each plane uses a different texture map and therefore has @@ -86,7 +85,7 @@ def butcher(data, affine): # Start by creatin a black/white lookup table. lut = vtk.vtkLookupTable() lut.SetTableRange(0, 255) - #print(data.min(), data.max()) + # print(data.min(), data.max()) lut.SetSaturationRange(0, 0) lut.SetHueRange(0, 0) lut.SetValueRange(0, 1) @@ -95,8 +94,6 @@ def butcher(data, affine): x1, x2, y1, y2, z1, z2 = im.GetExtent() - print(x1, x2, y1, y2, z1, z2) - # Create the first of the three planes. The filter vtkImageMapToColors # maps the data through the corresponding lookup table created above. # The vtkImageActor is a type of vtkProp and conveniently displays an diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index d437d5c398..5eb3d649a4 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -8,16 +8,18 @@ import numpy.testing as npt from nibabel.tmpdirs import TemporaryDirectory +from dipy.utils.six import string_types -def analyze_output(renderer, fname, cleanup=True): - result = sp.misc.imread(fname) +def analyze_output(renderer, im): + if isinstance(im, string_types): + im = sp.misc.imread(im) + bg = renderer.GetBackground() if bg == (0, 0, 0): - npt.assert_equal(result.sum() > 0, True) + npt.assert_equal(im.sum() > 0, True) else: raise ValueError('The background of the renderer is not black') - return True @@ -27,31 +29,30 @@ def test_butcher(): renderer = window.renderer() - # data = np.random.randint(0, 255, (50, 50, 50)) data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) + slicer = actor.butcher(data, affine) + window.add(renderer, slicer) - stream_actor = actor.line(streamlines) + # window.show(renderer) - slicer = actor.butcher(data, affine) + # copy pixels in numpy array directly + arr = window.snapshot(renderer, None) + npt.assert_(analyze_output(renderer, arr)) - window.add(renderer, slicer) - window.add(renderer, stream_actor) + # The slicer can cut directly a smaller part of the image + slicer.SetDisplayExtent(10, 30, 10, 30, 35, 35) + slicer.Update() + renderer.ResetCamera() - window.show(renderer) + window.add(renderer, slicer) + # save pixels in png file not a numpy array with TemporaryDirectory() as tmpdir: fname = os.path.join(tmpdir, 'butcher.png') - window.record(renderer, out_path=fname) + window.snapshot(renderer, fname) npt.assert_(analyze_output(renderer, fname)) - slicer.SetDisplayExtent(0, 255, 0, 255, 149/3, 149/3) - # print(slicer.GetExtent()) - - slicer.Update() - - window.show(renderer) - @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) @@ -71,13 +72,10 @@ def test_streamtube_and_line_actors(): # window.show(renderer) - with TemporaryDirectory() as tmpdir: - fname = os.path.join(tmpdir, 'streamtube.png') - window.record(renderer, out_path=fname) - npt.assert_(analyze_output(renderer, fname)) + arr = window.snapshot(renderer) + npt.assert_(analyze_output(renderer, arr)) if __name__ == "__main__": - # npt.run_module_suite() - test_butcher() + npt.run_module_suite() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index f4916269aa..5e6ff3630e 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -5,6 +5,8 @@ from dipy import __version__ as dipy_version from time import sleep +from dipy.viz.utils import set_input +from scipy.misc import imread #import vtk # Allow import, but disable doctests if we don't have vtk @@ -16,6 +18,7 @@ version = vtk.vtkVersion.GetVTKSourceVersion().split(' ')[-1] major_version = vtk.vtkVersion.GetVTKMajorVersion() + from vtk.util.numpy_support import vtk_to_numpy def renderer(background=None): @@ -201,6 +204,13 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, azimuthal angle of camera rotation. magnification : int, optional how much to magnify the saved frame + size : (int, int) + ``(width, height)`` of the window + verbose : bool + print information about the camera + sleep_time : float + Creates a small delay in seconds so that the renderer has enough + time to save the figure correctly. Examples --------- @@ -215,8 +225,6 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, if ren is None: ren = vtk.vtkRenderer() - else: - sleep(1) renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren) @@ -275,3 +283,52 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, writer.Write() ang = +az_ang + + +def snapshot(ren, fname=None, size=(300, 300)): + """ Saves a snapshot of the renderer in a file or in memory + + Parameters + ----------- + ren : vtkRenderer + as returned from function renderer() + fname : str or None + If None return numpy array otherwise save png file. + size : (int, int) + ``(width, height)`` of the window + + Returns + ------- + arr : ndarray or bool + If fname is None returns array or True otherwise. + """ + + width, height = size + + graphics_factory = vtk.vtkGraphicsFactory() + graphics_factory.SetOffScreenOnlyMode(1) + graphics_factory.SetUseMesaClasses(1) + + render_window = vtk.vtkRenderWindow() + render_window.SetOffScreenRendering(1) + render_window.AddRenderer(ren) + render_window.SetSize(width, height) + render_window.Render() + + window_to_image_filter = vtk.vtkWindowToImageFilter() + window_to_image_filter.SetInput(render_window) + window_to_image_filter.Update() + + if fname is None: + vtk_image = window_to_image_filter.GetOutput() + h, w, _ = vtk_image.GetDimensions() + vtk_array = vtk_image.GetPointData().GetScalars() + components = vtk_array.GetNumberOfComponents() + arr = vtk_to_numpy(vtk_array).reshape(h, w, components) + return arr + + writer = vtk.vtkPNGWriter() + writer.SetFileName(fname) + writer.SetInputConnection(window_to_image_filter.GetOutputPort()) + writer.Write() + return True From 3ce90bafad451154112bbda14777b7337f04400d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 11 Mar 2015 18:28:05 -0400 Subject: [PATCH 018/242] Starting looking into plotting bundles with maps --- doc/examples/interact_data.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/examples/interact_data.py b/doc/examples/interact_data.py index 9da7de5945..690796aa28 100644 --- a/doc/examples/interact_data.py +++ b/doc/examples/interact_data.py @@ -7,7 +7,7 @@ import nibabel as nib from nibabel import trackvis as tv -world_coords = True +world_coords = False img = nib.load(dname + 't1_brain_warp.nii.gz') data = img.get_data() @@ -31,7 +31,9 @@ streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) renderer = window.renderer() -stream_actor = actor.line(streamlines) + +# LOAD FA HERE +stream_actor = actor.line(streamlines, data) if not world_coords: slicer = actor.butcher(data, affine=np.eye(4)) @@ -64,8 +66,9 @@ def change_slice(obj, event): iren.Initialize() - - ren_win.Render() iren.Start() + +ren_win.RemoveRenderer(renderer) +renderer.SetRenderWindow(None) From 6669f34391851bf4c8b20d4ffa3230aa442c19b4 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 12 Mar 2015 17:22:36 -0400 Subject: [PATCH 019/242] Small update in interact_data --- doc/examples/interact_data.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/doc/examples/interact_data.py b/doc/examples/interact_data.py index 690796aa28..c0edb2e0f4 100644 --- a/doc/examples/interact_data.py +++ b/doc/examples/interact_data.py @@ -8,12 +8,21 @@ from nibabel import trackvis as tv world_coords = False +streamline_opacity = .5 +slicer_opacity = .5 +depth_peeling = False + img = nib.load(dname + 't1_brain_warp.nii.gz') data = img.get_data() affine = img.get_affine() +img_fa = nib.load(dname + 'results/metrics/fa.nii') +fa = img_fa.get_data() +affine_fa = img_fa.get_affine() + + streams, hdr = tv.read(dname + 'results/bundles/cst.right.trk', points_space="rasmm") streamlines = [s[0] for s in streams] @@ -32,14 +41,16 @@ renderer = window.renderer() -# LOAD FA HERE -stream_actor = actor.line(streamlines, data) +stream_actor = actor.streamtube(streamlines, fa) if not world_coords: slicer = actor.butcher(data, affine=np.eye(4)) else: slicer = actor.butcher(data, affine) +slicer.GetProperty().SetOpacity(slicer_opacity) +stream_actor.GetProperty().SetOpacity(streamline_opacity) + window.add(renderer, stream_actor) window.add(renderer, slicer) @@ -59,6 +70,15 @@ def change_slice(obj, event): ren_win = vtk.vtkRenderWindow() ren_win.AddRenderer(renderer) +if depth_peeling: + # http://www.vtk.org/Wiki/VTK/Depth_Peeling + ren_win.SetAlphaBitPlanes(1) + ren_win.SetMultiSamples(0) + renderer.SetUseDepthPeeling(1) + renderer.SetMaximumNumberOfPeels(10) + renderer.SetOcclusionRatio(0.1) + + iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(ren_win) @@ -67,8 +87,13 @@ def change_slice(obj, event): iren.Initialize() ren_win.Render() + +if depth_peeling: + dp_bool = str(bool(renderer.GetLastRenderingUsedDepthPeeling())) + print('Depth peeling used? ' + dp_bool) + iren.Start() -ren_win.RemoveRenderer(renderer) -renderer.SetRenderWindow(None) +# ren_win.RemoveRenderer(renderer) +# renderer.SetRenderWindow(None) From 6fa127e03fe8330b8edc571aed577ce1cb3d6f65 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 13 Mar 2015 14:32:33 -0400 Subject: [PATCH 020/242] RF: minor changes --- dipy/viz/fvtk.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 9226835509..f9bab44f03 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -33,6 +33,7 @@ colors, have_vtk_colors, _ = optional_package('vtk.util.colors') cm, have_matplotlib, _ = optional_package('matplotlib.cm') + if have_matplotlib: get_cmap = cm.get_cmap else: From dcc8a087d926e35054a90edf2c041f04d322d19f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 13 Mar 2015 14:34:02 -0400 Subject: [PATCH 021/242] Moved analyze snapshot to window --- dipy/viz/tests/test_fvtk_actors.py | 28 +++++++++------------------- dipy/viz/utils.py | 10 +++++----- dipy/viz/window.py | 25 ++++++++++++++++++++----- 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 5eb3d649a4..5b80a75bd8 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -3,28 +3,15 @@ import numpy as np import scipy as sp -from dipy.viz import actor -from dipy.viz import window +from dipy.viz import actor, window, utils import numpy.testing as npt from nibabel.tmpdirs import TemporaryDirectory -from dipy.utils.six import string_types - - -def analyze_output(renderer, im): - if isinstance(im, string_types): - im = sp.misc.imread(im) - - bg = renderer.GetBackground() - if bg == (0, 0, 0): - npt.assert_equal(im.sum() > 0, True) - else: - raise ValueError('The background of the renderer is not black') - return True @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) +@npt.dec.skipif(not window.have_imread) def test_butcher(): renderer = window.renderer() @@ -38,7 +25,7 @@ def test_butcher(): # copy pixels in numpy array directly arr = window.snapshot(renderer, None) - npt.assert_(analyze_output(renderer, arr)) + npt.assert_(window.analyze_snapshot(renderer, arr)) # The slicer can cut directly a smaller part of the image slicer.SetDisplayExtent(10, 30, 10, 30, 35, 35) @@ -50,12 +37,15 @@ def test_butcher(): # save pixels in png file not a numpy array with TemporaryDirectory() as tmpdir: fname = os.path.join(tmpdir, 'butcher.png') + # window.show(renderer) window.snapshot(renderer, fname) - npt.assert_(analyze_output(renderer, fname)) + # imshow(window.snapshot(renderer), origin='lower') + npt.assert_(window.analyze_snapshot(renderer, fname)) @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) +@npt.dec.skipif(not window.have_imread) def test_streamtube_and_line_actors(): renderer = window.renderer() @@ -71,11 +61,11 @@ def test_streamtube_and_line_actors(): window.add(renderer, c2) # window.show(renderer) - arr = window.snapshot(renderer) - npt.assert_(analyze_output(renderer, arr)) + npt.assert_(window.analyze_snapshot(renderer, arr)) if __name__ == "__main__": npt.run_module_suite() + # test_butcher() diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 116a67fb26..526bd6cc85 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -7,7 +7,7 @@ # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package -#import vtk +# import vtk # Allow import, but disable doctests if we don't have vtk vtk, have_vtk, setup_module = optional_package('vtk') ns, have_numpy_support, _ = optional_package('vtk.util.numpy_support') @@ -44,12 +44,12 @@ def set_input(vtk_object, input): ---------- >>> poly_mapper = set_input(vtk.vtkPolyDataMapper(), poly_data) """ - if isinstance(input,vtk.vtkPolyData): + if isinstance(input, vtk.vtkPolyData): if vtk.VTK_MAJOR_VERSION <= 5: vtk_object.SetInput(input) else: vtk_object.SetInputData(input) - elif isinstance(input,vtk.vtkAlgorithmOutput): + elif isinstance(input, vtk.vtkAlgorithmOutput): vtk_object.SetInputConnection(input) vtk_object.Update() @@ -71,8 +71,8 @@ def evec_from_lines(lines, use_line_dir=True): directions = np.vstack(lines_dir) else: points = np.vstack(lines) - centered_points = points - np.mean(points,axis=0) - norm = np.sqrt(np.sum(centered_points**2,axis=1, keepdims=True)) + centered_points = points - np.mean(points, axis=0) + norm = np.sqrt(np.sum(centered_points**2, axis=1, keepdims=True)) directions = centered_points/norm U, e_val, e_vec = np.linalg.svd(directions, full_matrices=False) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 5e6ff3630e..2dce71b713 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -4,15 +4,14 @@ from dipy.utils.optpkg import optional_package from dipy import __version__ as dipy_version -from time import sleep -from dipy.viz.utils import set_input -from scipy.misc import imread +from dipy.utils.six import string_types -#import vtk +# import vtk # Allow import, but disable doctests if we don't have vtk vtk, have_vtk, setup_module = optional_package('vtk') colors, have_vtk_colors, _ = optional_package('vtk.util.colors') numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') +_, have_imread, _ = optional_package('Image') if have_vtk: @@ -20,6 +19,9 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() from vtk.util.numpy_support import vtk_to_numpy +if have_imread: + from scipy.misc import imread + def renderer(background=None): """ Create a renderer. @@ -166,7 +168,7 @@ def key_press(obj, event): iren.AddObserver('KeyPressEvent', key_press) iren.SetInteractorStyle(style) iren.Initialize() - #picker.Pick(85, 126, 0, ren) + # picker.Pick(85, 126, 0, ren) window.Render() iren.Start() @@ -332,3 +334,16 @@ def snapshot(ren, fname=None, size=(300, 300)): writer.SetInputConnection(window_to_image_filter.GetOutputPort()) writer.Write() return True + + +def analyze_snapshot(renderer, im): + if isinstance(im, string_types): + im = imread(im) + + bg = renderer.GetBackground() + if bg == (0, 0, 0): + import numpy.testing as npt + npt.assert_equal(im.sum() > 0, True) + else: + raise ValueError('The background of the renderer is not black') + return True From 8b225e705ce48cc4c93af1e55b51470460d5b40b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 13 Mar 2015 14:37:11 -0400 Subject: [PATCH 022/242] RF: renderer parameter is now ren for backwards compatibility --- dipy/viz/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 2dce71b713..5ccb804650 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -336,11 +336,11 @@ def snapshot(ren, fname=None, size=(300, 300)): return True -def analyze_snapshot(renderer, im): +def analyze_snapshot(ren, im): if isinstance(im, string_types): im = imread(im) - bg = renderer.GetBackground() + bg = ren.GetBackground() if bg == (0, 0, 0): import numpy.testing as npt npt.assert_equal(im.sum() > 0, True) From 0696aab839df1e4e8d21a369c7c8b987ec524e26 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 4 Apr 2015 22:20:14 -0400 Subject: [PATCH 023/242] Setting good coordinates for buttons --- dipy/viz/tests/test_fvtk_widgets.py | 18 +++++++++++++++-- dipy/viz/widget.py | 31 +++++++++-------------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index bd395352f4..5f93971fbc 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -57,6 +57,9 @@ def test_button_widget(): ren_win = vtk.vtkRenderWindow() ren_win.AddRenderer(renderer) + + + iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(ren_win) @@ -72,11 +75,22 @@ def callback(obj, event): ren_win.Render() - bds = compute_bounds(renderer, (0.5, 0.5), (200, 100)) - + bds = compute_bounds(renderer, (.5, .5), (200, 50)) button.GetRepresentation().PlaceWidget(bds) button.On() + def win_callback(obj, event): + + bds = compute_bounds(renderer, (.5, .5), (200, 50)) + button.GetRepresentation().PlaceWidget(bds) + button.On() + + #win_callback(None, None) + + ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) + + ren_win.Render() + iren.Start() diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index c0634c2a70..cf0d6f2a06 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -50,8 +50,10 @@ def compute_bounds(renderer, normalized_display_position, size): upperRight = vtk.vtkCoordinate() upperRight.SetCoordinateSystemToNormalizedDisplay() upperRight.SetValue(normalized_display_position[0], normalized_display_position[1]) - bds = [0.0]*6 + bds = [0.0] * 6 bds[0] = upperRight.GetComputedDisplayValue(renderer)[0] - size[0] + print(upperRight.GetComputedDisplayValue(renderer)[0]) + print(upperRight.GetComputedDisplayValue(renderer)[1]) bds[1] = bds[0] + size[0] bds[2] = upperRight.GetComputedDisplayValue(renderer)[1] - size[1] bds[3] = bds[2] + size[1] @@ -64,14 +66,15 @@ def button(iren, callback): image1.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res.png') image1.Update() - image2 = vtk.vtkPNGReader() - image2.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res2.png') - image2.Update() + #image2 = vtk.vtkPNGReader() + #image2.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res2.png') + #image2.Update() #button_rep = vtk.vtkProp3DButtonRepresentation() button_rep = vtk.vtkTexturedButtonRepresentation2D() - button_rep.SetNumberOfStates(1) + button_rep.SetNumberOfStates(2) button_rep.SetButtonTexture(0, image1.GetOutput()) + button_rep.SetButtonTexture(1, image1.GetOutput()) #button_rep.SetButtonTexture(1, image2.GetOutput()) button_rep.SetPlaceFactor(1) @@ -79,28 +82,12 @@ def button(iren, callback): #READ THIS! #http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget - #bds = compute_bounds(ren, (1.5, 1.5), (100, 100)) - #print(bds) - button_rep.PlaceWidget([0., 100, 50, 500, 0, 0]) - - #button_rep.PlaceWidget(bds) - button = vtk.vtkButtonWidget() button.SetInteractor(iren) button.SetRepresentation(button_rep) - button.On() button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) - #ren = iren.GetRenderWindow().GetRenderers().GetFirstRenderer() - #bds = compute_bounds(ren, (.5, .5), (100, 100)) - #button_rep.PlaceWidget(bds) - - #button_rep.SetPlaceFactor(1) - - #button_rep.PlaceWidget((0.75, 0, 0), (250, 450)) - # see state changed #http://vtk.org/gitweb?p=VTK.git;a=blob;f=Interaction/Widgets/Testing/Cxx/TestButtonWidget.cxx #http://vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget - button.SetEnabled(True) - return button \ No newline at end of file + return button From c00a6105ddb05254298c379ce001dcfb2fbef2cc Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 4 Apr 2015 22:21:57 -0400 Subject: [PATCH 024/242] Still debugging buttons --- dipy/viz/widget.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index cf0d6f2a06..194bb4af67 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -57,6 +57,8 @@ def compute_bounds(renderer, normalized_display_position, size): bds[1] = bds[0] + size[0] bds[2] = upperRight.GetComputedDisplayValue(renderer)[1] - size[1] bds[3] = bds[2] + size[1] + + print(bds) return bds From bcb943ae8a0366d4f7f0fe226624f108d4c8d000 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 5 Apr 2015 13:31:19 -0400 Subject: [PATCH 025/242] looking for icons --- dipy/viz/tests/test_fvtk_widgets.py | 23 +++++++++++++---------- dipy/viz/widget.py | 4 ++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 5f93971fbc..bfa2cb6fa5 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -38,6 +38,7 @@ def print_status(obj, event): ren_win.Render() iren.Start() + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_button_widget(): @@ -57,9 +58,6 @@ def test_button_widget(): ren_win = vtk.vtkRenderWindow() ren_win.AddRenderer(renderer) - - - iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(ren_win) @@ -67,7 +65,10 @@ def callback(obj, event): print(obj) print('Pressed') - button = widget.button(iren=iren, callback=callback) + button_png = '/home/eleftherios/Downloads/dipy-running-high-res.png' + # button_png = '/home/eleftherios/Devel/icons/antique-glowing-copper-orbs/antique-copper-orbs/antique-copper-orbs-netvibes-logo.png' + button = widget.button(iren=iren, callback=callback, + fname=button_png) from dipy.viz.widget import compute_bounds @@ -75,18 +76,22 @@ def callback(obj, event): ren_win.Render() - bds = compute_bounds(renderer, (.5, .5), (200, 50)) + button_norm_coords = (.9, 1.2) + button_size = (100, 100) + + bds = compute_bounds(renderer, button_norm_coords, button_size) button.GetRepresentation().PlaceWidget(bds) button.On() def win_callback(obj, event): + # print(obj) + print(event) + print(obj.GetSize()) - bds = compute_bounds(renderer, (.5, .5), (200, 50)) + bds = compute_bounds(renderer, button_norm_coords, button_size) button.GetRepresentation().PlaceWidget(bds) button.On() - #win_callback(None, None) - ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) ren_win.Render() @@ -94,8 +99,6 @@ def win_callback(obj, event): iren.Start() - - if __name__ == '__main__': #test_slider_widget() diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 194bb4af67..f8fa0eab98 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -62,10 +62,10 @@ def compute_bounds(renderer, normalized_display_position, size): return bds -def button(iren, callback): +def button(iren, callback, fname): image1 = vtk.vtkPNGReader() - image1.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res.png') + image1.SetFileName(fname) image1.Update() #image2 = vtk.vtkPNGReader() From 1513c77849bcb227d79ebd43e0188e1bdc289cc8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 5 Apr 2015 21:35:13 -0400 Subject: [PATCH 026/242] NF: button widget has a new method for updating coordinates when window has changed --- dipy/viz/tests/test_fvtk_widgets.py | 38 +++++++++++++++++++++-------- dipy/viz/widget.py | 17 +++++++++---- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index bfa2cb6fa5..9d49e90dec 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -65,10 +65,15 @@ def callback(obj, event): print(obj) print('Pressed') - button_png = '/home/eleftherios/Downloads/dipy-running-high-res.png' + # button_png = '/home/eleftherios/Downloads/dipy-running-high-res.png' + button_png = '/home/eleftherios/Devel/icons/icomoon/PNG/home3.png' # button_png = '/home/eleftherios/Devel/icons/antique-glowing-copper-orbs/antique-copper-orbs/antique-copper-orbs-netvibes-logo.png' - button = widget.button(iren=iren, callback=callback, - fname=button_png) + button = widget.button(iren, callback, + button_png, (.9, 1.2), (50, 50)) + button_png_plus = '/home/eleftherios/Devel/icons/icomoon/PNG/plus.png' + # button_png = '/home/eleftherios/Devel/icons/antique-glowing-copper-orbs/antique-copper-orbs/antique-copper-orbs-netvibes-logo.png' + button_plus = widget.button(iren, callback, + button_png_plus, (.9, .8), (50, 50)) from dipy.viz.widget import compute_bounds @@ -77,20 +82,33 @@ def callback(obj, event): ren_win.Render() button_norm_coords = (.9, 1.2) - button_size = (100, 100) + button_size = (50, 50) + + # bds = compute_bounds(renderer, button_norm_coords, button_size) + # button.GetRepresentation().PlaceWidget(bds) + # button.On() + button.place(renderer) - bds = compute_bounds(renderer, button_norm_coords, button_size) - button.GetRepresentation().PlaceWidget(bds) - button.On() + # bds = compute_bounds(renderer, (.9, .8), button_size) + # button_plus.GetRepresentation().PlaceWidget(bds) + # button_plus.On() + button_plus.place(renderer) def win_callback(obj, event): # print(obj) print(event) print(obj.GetSize()) - bds = compute_bounds(renderer, button_norm_coords, button_size) - button.GetRepresentation().PlaceWidget(bds) - button.On() + button.place(renderer) + # bds = compute_bounds(renderer, button_norm_coords, button_size) + # button.GetRepresentation().PlaceWidget(bds) + # button.On() + + button_plus.place(renderer) + + # bds = compute_bounds(renderer, (.9, .8), button_size) + # button_plus.GetRepresentation().PlaceWidget(bds) + # button_plus.On() ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index f8fa0eab98..cac7ae000e 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -62,15 +62,12 @@ def compute_bounds(renderer, normalized_display_position, size): return bds -def button(iren, callback, fname): +def button(iren, callback, fname, button_norm_coords, button_size): image1 = vtk.vtkPNGReader() image1.SetFileName(fname) image1.Update() - #image2 = vtk.vtkPNGReader() - #image2.SetFileName('/home/eleftherios/Downloads/dipy-running-high-res2.png') - #image2.Update() #button_rep = vtk.vtkProp3DButtonRepresentation() button_rep = vtk.vtkTexturedButtonRepresentation2D() @@ -84,7 +81,15 @@ def button(iren, callback, fname): #READ THIS! #http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget - button = vtk.vtkButtonWidget() + class ButtonWidget(vtk.vtkButtonWidget): + + def place(self, renderer): + + bds = compute_bounds(renderer, button_norm_coords, button_size) + self.GetRepresentation().PlaceWidget(bds) + self.On() + + button = ButtonWidget() # vtk.vtkButtonWidget() button.SetInteractor(iren) button.SetRepresentation(button_rep) button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) @@ -93,3 +98,5 @@ def button(iren, callback, fname): #http://vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget return button + + From 12f2c128daa3253a942f379a2bfe75b1e0f6f506 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 5 Apr 2015 23:01:12 -0400 Subject: [PATCH 027/242] Checking button alignment on resize --- dipy/viz/tests/test_fvtk_widgets.py | 34 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 9d49e90dec..99895b314d 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -57,6 +57,7 @@ def test_button_widget(): ren_win = vtk.vtkRenderWindow() ren_win.AddRenderer(renderer) + ren_win.SetSize(600, 600) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(ren_win) @@ -69,14 +70,24 @@ def callback(obj, event): button_png = '/home/eleftherios/Devel/icons/icomoon/PNG/home3.png' # button_png = '/home/eleftherios/Devel/icons/antique-glowing-copper-orbs/antique-copper-orbs/antique-copper-orbs-netvibes-logo.png' button = widget.button(iren, callback, - button_png, (.9, 1.2), (50, 50)) + button_png, (.8, 1.2), (50, 50)) button_png_plus = '/home/eleftherios/Devel/icons/icomoon/PNG/plus.png' - # button_png = '/home/eleftherios/Devel/icons/antique-glowing-copper-orbs/antique-copper-orbs/antique-copper-orbs-netvibes-logo.png' button_plus = widget.button(iren, callback, - button_png_plus, (.9, .8), (50, 50)) + button_png_plus, (.7, .8), (50, 50)) + button_png_minus = '/home/eleftherios/Devel/icons/icomoon/PNG/minus.png' + button_minus = widget.button(iren, callback, + button_png_minus, (.9, .8), (50, 50)) + from dipy.viz.widget import compute_bounds + def print_status(obj, event): + print(obj) + print(event) + renderer.SetBackground(np.random.rand(3)) + + slider = widget.slider(iren=iren, callback=print_status) + iren.Initialize() ren_win.Render() @@ -84,15 +95,9 @@ def callback(obj, event): button_norm_coords = (.9, 1.2) button_size = (50, 50) - # bds = compute_bounds(renderer, button_norm_coords, button_size) - # button.GetRepresentation().PlaceWidget(bds) - # button.On() button.place(renderer) - - # bds = compute_bounds(renderer, (.9, .8), button_size) - # button_plus.GetRepresentation().PlaceWidget(bds) - # button_plus.On() button_plus.place(renderer) + button_minus.place(renderer) def win_callback(obj, event): # print(obj) @@ -100,15 +105,8 @@ def win_callback(obj, event): print(obj.GetSize()) button.place(renderer) - # bds = compute_bounds(renderer, button_norm_coords, button_size) - # button.GetRepresentation().PlaceWidget(bds) - # button.On() - button_plus.place(renderer) - - # bds = compute_bounds(renderer, (.9, .8), button_size) - # button_plus.GetRepresentation().PlaceWidget(bds) - # button_plus.On() + button_minus.place(renderer) ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) From c61cdeba585c0c29aacd7d7c40925a91b7eda860 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 6 Apr 2015 20:44:01 -0400 Subject: [PATCH 028/242] Looking for better ways to analyze the snapshots --- dipy/viz/tests/test_fvtk_widgets.py | 12 +++++++----- dipy/viz/window.py | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 99895b314d..400ab994f8 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -36,7 +36,8 @@ def print_status(obj, event): iren.Initialize() ren_win.Render() - iren.Start() + # iren.Start() + arr = window.snapshot(renderer, size=(600, 600)) @npt.dec.skipif(not actor.have_vtk) @@ -111,11 +112,12 @@ def win_callback(obj, event): ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) ren_win.Render() + # iren.Start() - iren.Start() - + arr = window.snapshot(renderer, size=(600, 600)) if __name__ == '__main__': - #test_slider_widget() - test_button_widget() + # test_slider_widget() + # test_button_widget() + npt.run_module_suite() \ No newline at end of file diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 5ccb804650..e46be0a00f 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -337,6 +337,15 @@ def snapshot(ren, fname=None, size=(300, 300)): def analyze_snapshot(ren, im): + """ Analyze snapshot from memory or file + + Parameters + ---------- + ren: vtkRenderer + im: str or array + If string then image is read from a file otherwise the image is read + from a numpy array. + """ if isinstance(im, string_types): im = imread(im) From 63975c9ac06648cdcb509862bf0a859535e2e10d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Apr 2015 18:30:04 -0400 Subject: [PATCH 029/242] NF: analyze_snapshot can find specific colors and objects --- dipy/viz/tests/test_fvtk_actors.py | 34 ++++++++++---- dipy/viz/tests/test_fvtk_widgets.py | 4 ++ dipy/viz/window.py | 71 +++++++++++++++++++++++++---- 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 5b80a75bd8..27b273fbb3 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -24,8 +24,9 @@ def test_butcher(): # window.show(renderer) # copy pixels in numpy array directly - arr = window.snapshot(renderer, None) - npt.assert_(window.analyze_snapshot(renderer, arr)) + arr = window.snapshot(renderer) + report = window.analyze_snapshot(renderer, arr, find_objects=True) + npt.assert_equal(report.objects, 1) # The slicer can cut directly a smaller part of the image slicer.SetDisplayExtent(10, 30, 10, 30, 35, 35) @@ -40,7 +41,7 @@ def test_butcher(): # window.show(renderer) window.snapshot(renderer, fname) # imshow(window.snapshot(renderer), origin='lower') - npt.assert_(window.analyze_snapshot(renderer, fname)) + npt.assert_equal(window.analyze_snapshot(renderer, fname).objects, 1) @npt.dec.skipif(not actor.have_vtk) @@ -50,22 +51,35 @@ def test_streamtube_and_line_actors(): renderer = window.renderer() - lines = [np.random.rand(10, 3), np.random.rand(20, 3)] - colors = np.random.rand(2, 3) - c = actor.line(lines, colors) + line1 = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2.]]) + line2 = line1 + np.array([0.5, 0., 0.]) + + lines = [line1, line2] + colors = np.array([[1, 0, 0], [0, 0, 1.]]) + c = actor.line(lines, colors, linewidth=3) window.add(renderer, c) # create streamtubes of the same lines and shift them a bit - c2 = actor.streamtube(lines, colors) + c2 = actor.streamtube(lines, colors, linewidth=.1) c2.SetPosition(2, 0, 0) window.add(renderer, c2) - # window.show(renderer) + window.show(renderer) arr = window.snapshot(renderer) - npt.assert_(window.analyze_snapshot(renderer, arr)) + # npt.assert_(window.analyze_snapshot(renderer, arr)) + report = window.analyze_snapshot(renderer, arr, + colors=[(255, 0, 0), (0, 0, 255)], + find_objects=True) + + + imshow(arr) + imshow(report.labels) + print(report.objects) + print(report.colors_found) if __name__ == "__main__": - npt.run_module_suite() + # npt.run_module_suite() # test_butcher() + test_streamtube_and_line_actors() diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 400ab994f8..1549300441 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -6,6 +6,7 @@ import numpy.testing as npt + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_slider_widget(): @@ -38,6 +39,9 @@ def print_status(obj, event): ren_win.Render() # iren.Start() arr = window.snapshot(renderer, size=(600, 600)) + report = window.analyze_snapshot(renderer, arr) + + @npt.dec.skipif(not actor.have_vtk) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index e46be0a00f..2d3f8d5168 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -1,5 +1,8 @@ from __future__ import division, print_function, absolute_import +import numpy as np +from scipy import ndimage + # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -336,23 +339,71 @@ def snapshot(ren, fname=None, size=(300, 300)): return True -def analyze_snapshot(ren, im): +def analyze_snapshot(ren, im, bg_color=(0, 0, 0), colors=None, + find_objects=False, + strel=None): """ Analyze snapshot from memory or file Parameters ---------- ren: vtkRenderer im: str or array - If string then image is read from a file otherwise the image is read - from a numpy array. + If string then the image is read from a file otherwise the image is + read from a numpy array. The array is expected to be of shape (X, Y, 3) + where the last dimensions are the RGB values. + colors: tuple (3,) or list of tuples (3,) + List of colors to search in the image + find_objects: bool + If True it will calculate the number of objects that are different + from the background and return their position in a new image. + strel: array + Structure element to use for finding the objects. + + Returns + ------- + report : ReportSnapshot + This is an object with attibutes like ``bg_color_check`` or + ``colors_check`` that give information about the result of the analysis + of the current ``im``. + """ if isinstance(im, string_types): im = imread(im) - bg = ren.GetBackground() - if bg == (0, 0, 0): - import numpy.testing as npt - npt.assert_equal(im.sum() > 0, True) - else: - raise ValueError('The background of the renderer is not black') - return True + class ReportSnapshot(object): + objects = None + labels = None + bg_color_check = False + colors_found = False + + report = ReportSnapshot() + + if bg_color is not None: + bg = ren.GetBackground() + if bg == bg_color: + report.bg_color_check = True + else: + report.bg_color_check = False + + if colors is not None: + if isinstance(im, tuple): + colors = [colors] + flags = [False] * len(colors) + for (i, col) in enumerate(colors): + flags[i] = np.sum(im == np.array(col)) > 0 + + report.colors_found = flags + + if find_objects is True: + weights = [0.299, 0.587, 0.144] + gray = np.dot(im[..., :3], weights) + mask_threshold = np.dot(bg_color, weights) + if strel is None: + strel = np.array([[0, 1, 0], + [1, 1, 1], + [0, 1, 0]]) + labels, objects = ndimage.label(gray > mask_threshold, strel) + report.labels = labels + report.objects = objects + + return report From 5fcd1eae01eecac4667249d64f96992394b8898e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Apr 2015 22:42:34 -0400 Subject: [PATCH 030/242] Looking at a possible bug with the tmpdir and snapshot --- dipy/viz/tests/test_fvtk_actors.py | 18 +++++++++++------- dipy/viz/window.py | 26 +++++++++++++++++--------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 27b273fbb3..9c1a93cd91 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -21,11 +21,11 @@ def test_butcher(): slicer = actor.butcher(data, affine) window.add(renderer, slicer) - # window.show(renderer) + window.show(renderer) # copy pixels in numpy array directly arr = window.snapshot(renderer) - report = window.analyze_snapshot(renderer, arr, find_objects=True) + report = window.analyze_snapshot(arr, find_objects=True) npt.assert_equal(report.objects, 1) # The slicer can cut directly a smaller part of the image @@ -37,11 +37,15 @@ def test_butcher(): # save pixels in png file not a numpy array with TemporaryDirectory() as tmpdir: - fname = os.path.join(tmpdir, 'butcher.png') + #fname = os.path.join(tmpdir, 'butcher.png') + fname='butcher.png' + print(fname) + # window.show(renderer) window.snapshot(renderer, fname) + 1/0 # imshow(window.snapshot(renderer), origin='lower') - npt.assert_equal(window.analyze_snapshot(renderer, fname).objects, 1) + npt.assert_equal(window.analyze_snapshot(fname).objects, 1) @npt.dec.skipif(not actor.have_vtk) @@ -67,7 +71,7 @@ def test_streamtube_and_line_actors(): window.show(renderer) arr = window.snapshot(renderer) # npt.assert_(window.analyze_snapshot(renderer, arr)) - report = window.analyze_snapshot(renderer, arr, + report = window.analyze_snapshot(arr, colors=[(255, 0, 0), (0, 0, 255)], find_objects=True) @@ -81,5 +85,5 @@ def test_streamtube_and_line_actors(): if __name__ == "__main__": # npt.run_module_suite() - # test_butcher() - test_streamtube_and_line_actors() + test_butcher() + # test_streamtube_and_line_actors() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 2d3f8d5168..477006db8c 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -339,14 +339,25 @@ def snapshot(ren, fname=None, size=(300, 300)): return True -def analyze_snapshot(ren, im, bg_color=(0, 0, 0), colors=None, +def analyze_renderer(ren): + + class ReportRenderer(object): + bg_color = None + + report = ReportRenderer() + + report.bg_color = ren.GetBackground() + report.collection = ren.GetActors() + + return report + +def analyze_snapshot(im, bg_color=(0, 0, 0), colors=None, find_objects=False, strel=None): """ Analyze snapshot from memory or file Parameters ---------- - ren: vtkRenderer im: str or array If string then the image is read from a file otherwise the image is read from a numpy array. The array is expected to be of shape (X, Y, 3) @@ -378,13 +389,6 @@ class ReportSnapshot(object): report = ReportSnapshot() - if bg_color is not None: - bg = ren.GetBackground() - if bg == bg_color: - report.bg_color_check = True - else: - report.bg_color_check = False - if colors is not None: if isinstance(im, tuple): colors = [colors] @@ -398,6 +402,7 @@ class ReportSnapshot(object): weights = [0.299, 0.587, 0.144] gray = np.dot(im[..., :3], weights) mask_threshold = np.dot(bg_color, weights) + if strel is None: strel = np.array([[0, 1, 0], [1, 1, 1], @@ -407,3 +412,6 @@ class ReportSnapshot(object): report.objects = objects return report + + + From 0eec3ef9fecfab65bc20b89767d0c1646055a38c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Apr 2015 15:35:16 -0400 Subject: [PATCH 031/242] BF: changed default parameter for find_objects --- dipy/viz/tests/test_fvtk_actors.py | 31 ++++++++++------------------- dipy/viz/tests/test_fvtk_widgets.py | 2 -- dipy/viz/window.py | 18 +++++++++-------- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 9c1a93cd91..c7c2fcefe5 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- import os import numpy as np -import scipy as sp -from dipy.viz import actor, window, utils +from dipy.viz import actor, window import numpy.testing as npt from nibabel.tmpdirs import TemporaryDirectory @@ -20,8 +19,7 @@ def test_butcher(): affine = np.eye(4) slicer = actor.butcher(data, affine) window.add(renderer, slicer) - - window.show(renderer) + # window.show(renderer) # copy pixels in numpy array directly arr = window.snapshot(renderer) @@ -37,15 +35,11 @@ def test_butcher(): # save pixels in png file not a numpy array with TemporaryDirectory() as tmpdir: - #fname = os.path.join(tmpdir, 'butcher.png') - fname='butcher.png' - print(fname) - + fname = os.path.join(tmpdir, 'butcher.png') # window.show(renderer) - window.snapshot(renderer, fname) - 1/0 - # imshow(window.snapshot(renderer), origin='lower') - npt.assert_equal(window.analyze_snapshot(fname).objects, 1) + arr = window.snapshot(renderer, fname) + report = window.analyze_snapshot(fname, find_objects=True) + npt.assert_equal(report.objects, 1) @npt.dec.skipif(not actor.have_vtk) @@ -70,20 +64,15 @@ def test_streamtube_and_line_actors(): window.show(renderer) arr = window.snapshot(renderer) - # npt.assert_(window.analyze_snapshot(renderer, arr)) + report = window.analyze_snapshot(arr, colors=[(255, 0, 0), (0, 0, 255)], find_objects=True) - - imshow(arr) - imshow(report.labels) - print(report.objects) - print(report.colors_found) + npt.assert_equal(report.objects, 4) + npt.assert_equal(report.colors_found, [True, True]) if __name__ == "__main__": - # npt.run_module_suite() - test_butcher() - # test_streamtube_and_line_actors() + npt.run_module_suite() diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 1549300441..e7bbb9e612 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -42,8 +42,6 @@ def print_status(obj, event): report = window.analyze_snapshot(renderer, arr) - - @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_button_widget(): diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 477006db8c..27c6b6a4c4 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -324,19 +324,20 @@ def snapshot(ren, fname=None, size=(300, 300)): window_to_image_filter.SetInput(render_window) window_to_image_filter.Update() + vtk_image = window_to_image_filter.GetOutput() + h, w, _ = vtk_image.GetDimensions() + vtk_array = vtk_image.GetPointData().GetScalars() + components = vtk_array.GetNumberOfComponents() + arr = vtk_to_numpy(vtk_array).reshape(h, w, components) + if fname is None: - vtk_image = window_to_image_filter.GetOutput() - h, w, _ = vtk_image.GetDimensions() - vtk_array = vtk_image.GetPointData().GetScalars() - components = vtk_array.GetNumberOfComponents() - arr = vtk_to_numpy(vtk_array).reshape(h, w, components) return arr writer = vtk.vtkPNGWriter() writer.SetFileName(fname) writer.SetInputConnection(window_to_image_filter.GetOutputPort()) writer.Write() - return True + return arr def analyze_renderer(ren): @@ -351,8 +352,9 @@ class ReportRenderer(object): return report + def analyze_snapshot(im, bg_color=(0, 0, 0), colors=None, - find_objects=False, + find_objects=True, strel=None): """ Analyze snapshot from memory or file @@ -367,7 +369,7 @@ def analyze_snapshot(im, bg_color=(0, 0, 0), colors=None, find_objects: bool If True it will calculate the number of objects that are different from the background and return their position in a new image. - strel: array + strel: 2d array Structure element to use for finding the objects. Returns From c9791a4079d81dbf8a3c34a15e511ce034bfe1d7 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Apr 2015 15:47:38 -0400 Subject: [PATCH 032/242] RF: when recording many videos now there are leading zeros --- dipy/viz/window.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 27c6b6a4c4..aee37d2f67 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -265,9 +265,9 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, cam = ren.GetActiveCamera() if verbose: - print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) - print('Camera Focal Point (%.2f,%.2f,%.2f)' % cam.GetFocalPoint()) - print('Camera View Up (%.2f,%.2f,%.2f)' % cam.GetViewUp()) + print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) + print('Camera Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) + print('Camera View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) for i in range(n_frames): ren.GetActiveCamera().Azimuth(ang) @@ -276,12 +276,12 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, renderLarge.SetMagnification(magnification) renderLarge.Update() writer.SetInputConnection(renderLarge.GetOutputPort()) - # filename='/tmp/'+str(3000000+i)+'.png' + if path_numbering: if out_path is None: - filename = str(1000000 + i) + '.png' + filename = str(i).zfill(6) + '.png' else: - filename = out_path + str(1000000 + i) + '.png' + filename = out_path + str(i).zfill(6) + '.png' else: filename = out_path writer.SetFileName(filename) From 75d407bd727acab7c7e6aff63f919e77425150b8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Apr 2015 19:32:07 -0400 Subject: [PATCH 033/242] NF: dialog appears when saving snapshots from show --- dipy/viz/tests/test_fvtk_actors.py | 2 +- dipy/viz/tests/test_fvtk_widgets.py | 8 ++++---- dipy/viz/window.py | 11 ++++++++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index c7c2fcefe5..a3a5eee143 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -19,7 +19,7 @@ def test_butcher(): affine = np.eye(4) slicer = actor.butcher(data, affine) window.add(renderer, slicer) - # window.show(renderer) + window.show(renderer) # copy pixels in numpy array directly arr = window.snapshot(renderer) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index e7bbb9e612..94d51a9eba 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -16,7 +16,7 @@ def test_slider_widget(): # Create 2 lines with 2 different colors lines = [np.random.rand(10, 3), np.random.rand(20, 3)] colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) - c = actor.streamtube(lines, colors) + c = actor.line(lines, colors, linewidth=3) window.add(renderer, c) from dipy.viz.window import vtk @@ -37,7 +37,7 @@ def print_status(obj, event): iren.Initialize() ren_win.Render() - # iren.Start() + iren.Start() arr = window.snapshot(renderer, size=(600, 600)) report = window.analyze_snapshot(renderer, arr) @@ -120,6 +120,6 @@ def win_callback(obj, event): if __name__ == '__main__': - # test_slider_widget() + test_slider_widget() # test_button_widget() - npt.run_module_suite() \ No newline at end of file + # npt.run_module_suite() \ No newline at end of file diff --git a/dipy/viz/window.py b/dipy/viz/window.py index aee37d2f67..0906bc1c7e 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -164,7 +164,16 @@ def key_press(obj, event): renderLarge.Update() writer = vtk.vtkPNGWriter() writer.SetInputConnection(renderLarge.GetOutputPort()) - writer.SetFileName('fvtk.png') + + import Tkinter, tkFileDialog + root = Tkinter.Tk() + root.withdraw() + + file_path = tkFileDialog.asksaveasfilename(initialfile='fvtk.png', + defaultextension='.png', + filetypes=(("PNG file", "*.png"),("All Files", "*.*"))) + print(file_path) + writer.SetFileName(file_path) writer.Write() print('Look for fvtk.png in your current working directory.') From 88e3450637e5999cb72532f8d67528792ac60526 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Apr 2015 21:26:18 -0400 Subject: [PATCH 034/242] RF: made independed save dialog function --- dipy/viz/window.py | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 0906bc1c7e..be63667080 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -87,6 +87,23 @@ def rm_all(ren): clear(ren) +def save_file_dialog(initial_file='dipy.png', default_extension='.png', + filetypes=(("PNG file", "*.png"), ("All Files", "*.*"))): + """ Simple Tk file dialog + """ + + import Tkinter, tkFileDialog + root = Tkinter.Tk() + root.withdraw() + + + filepath = tkFileDialog.asksaveasfilename(initialfile='dipy.png', + defaultextension='.png', + filetypes=filetypes) + + return filepath + + def show(ren, title='Dipy', size=(300, 300), png_magnify=1): """ Show window @@ -162,20 +179,19 @@ def key_press(obj, event): renderLarge.SetInput(ren) renderLarge.SetMagnification(png_magnify) renderLarge.Update() - writer = vtk.vtkPNGWriter() - writer.SetInputConnection(renderLarge.GetOutputPort()) - - import Tkinter, tkFileDialog - root = Tkinter.Tk() - root.withdraw() - - file_path = tkFileDialog.asksaveasfilename(initialfile='fvtk.png', - defaultextension='.png', - filetypes=(("PNG file", "*.png"),("All Files", "*.*"))) - print(file_path) - writer.SetFileName(file_path) - writer.Write() - print('Look for fvtk.png in your current working directory.') + + file_types = (("PNG file", "*.png"), ("All Files", "*.*")) + filepath = save_file_dialog(initial_file='dipy.png', + default_extension='.png', + filetypes=file_types) + if filepath == '': + print('No file was provided in the dialog') + else: + writer = vtk.vtkPNGWriter() + writer.SetInputConnection(renderLarge.GetOutputPort()) + writer.SetFileName(filepath) + writer.Write() + print('File ' + filepath + ' is saved.') iren.AddObserver('KeyPressEvent', key_press) iren.SetInteractorStyle(style) From 3db47cae5e5e8f8fa1f808a8dc35dda1b97b8107 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Apr 2015 14:18:12 -0400 Subject: [PATCH 035/242] NF: Added fetcher to download icons and updated test for widgets --- dipy/data/__init__.py | 4 ++- dipy/data/fetcher.py | 41 ++++++++++++++++++++++++++++- dipy/viz/tests/test_fvtk_widgets.py | 24 ++++++++--------- dipy/viz/window.py | 4 --- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/dipy/data/__init__.py b/dipy/data/__init__.py index 765ffcf99e..1fe18be9c4 100644 --- a/dipy/data/__init__.py +++ b/dipy/data/__init__.py @@ -42,7 +42,9 @@ def loads_compat(bytes): fetch_syn_data, read_syn_data, fetch_stanford_t1, - read_stanford_t1) + read_stanford_t1, + fetch_viz_icons, + read_viz_icons) from ..utils.arrfuncs import as_native_array from dipy.tracking.streamline import relist_streamlines diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 71b8eab434..0ea04e488d 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -13,6 +13,7 @@ from os.path import join as pjoin from hashlib import md5 from shutil import copyfileobj +import tarfile import numpy as np import nibabel as nib @@ -469,7 +470,7 @@ def fetch_syn_data(): url = 'https://dl.dropboxusercontent.com/u/5918983/' t1 = url + 't1.nii.gz' b0 = url + 'b0.nii.gz' - + folder = pjoin(dipy_home, 'syn_test') md5_list = ['701bda02bb769655c7d4a9b1df2b73a6', # t1 @@ -516,3 +517,41 @@ def read_syn_data(): t1 = nib.load(t1_name) b0 = nib.load(b0_name) return t1, b0 + + +def fetch_viz_icons(): + """ Download icons for visualization + """ + url = 'https://dl.dropboxusercontent.com/u/2481924/' + fname = 'icomoon.tar.gz' + icomoon = url + fname + folder = pjoin(dipy_home, 'icons') + + url_list = [icomoon] + md5_list = ['94a07cba06b4136b6687396426f1e380'] + fname_list = [fname] + + if not os.path.exists(folder): + print('Creating new directory %s' % folder) + os.makedirs(folder) + print('Downloading icons ...') + for i in range(len(md5_list)): + _get_file_data(pjoin(folder, fname_list[i]), url_list[i]) + new_path = pjoin(folder, fname_list[i]) + check_md5(new_path, md5_list[i]) + ar = tarfile.open(new_path) + ar.extractall(path=folder) + ar.close() + + print('Done.') + print('Files copied in folder %s' % folder) + else: + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) + + +def read_viz_icons(style='icomoon', fname='infinity.png'): + + folder = pjoin(dipy_home, 'icons', style) + return pjoin(folder, fname) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 94d51a9eba..1c6244ca8b 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -1,9 +1,8 @@ import numpy as np - from dipy.viz import actor from dipy.viz import window from dipy.viz import widget - +from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt @@ -69,21 +68,20 @@ def callback(obj, event): print(obj) print('Pressed') - # button_png = '/home/eleftherios/Downloads/dipy-running-high-res.png' - button_png = '/home/eleftherios/Devel/icons/icomoon/PNG/home3.png' - # button_png = '/home/eleftherios/Devel/icons/antique-glowing-copper-orbs/antique-copper-orbs/antique-copper-orbs-netvibes-logo.png' + fetch_viz_icons() + button_png = read_viz_icons(fname='home3.png') + button = widget.button(iren, callback, button_png, (.8, 1.2), (50, 50)) - button_png_plus = '/home/eleftherios/Devel/icons/icomoon/PNG/plus.png' + + button_png_plus = read_viz_icons(fname='plus.png') button_plus = widget.button(iren, callback, button_png_plus, (.7, .8), (50, 50)) - button_png_minus = '/home/eleftherios/Devel/icons/icomoon/PNG/minus.png' + + button_png_minus = read_viz_icons(fname='minus.png') button_minus = widget.button(iren, callback, button_png_minus, (.9, .8), (50, 50)) - - from dipy.viz.widget import compute_bounds - def print_status(obj, event): print(obj) print(event) @@ -114,12 +112,12 @@ def win_callback(obj, event): ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) ren_win.Render() - # iren.Start() + iren.Start() arr = window.snapshot(renderer, size=(600, 600)) if __name__ == '__main__': - test_slider_widget() - # test_button_widget() + # test_slider_widget() + test_button_widget() # npt.run_module_suite() \ No newline at end of file diff --git a/dipy/viz/window.py b/dipy/viz/window.py index be63667080..330f56425f 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -91,16 +91,12 @@ def save_file_dialog(initial_file='dipy.png', default_extension='.png', filetypes=(("PNG file", "*.png"), ("All Files", "*.*"))): """ Simple Tk file dialog """ - import Tkinter, tkFileDialog root = Tkinter.Tk() root.withdraw() - - filepath = tkFileDialog.asksaveasfilename(initialfile='dipy.png', defaultextension='.png', filetypes=filetypes) - return filepath From 0cb5b0fd3645227fb3384495d4d42d3985cd8eff Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Apr 2015 14:24:31 -0400 Subject: [PATCH 036/242] PEP 8 in fetcher.py --- dipy/data/fetcher.py | 51 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 0ea04e488d..0b2309abef 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -181,9 +181,9 @@ def fetch_isbi2013_2shell(): ubvec = url + '2shells-1500-2500-N64.bvec' folder = pjoin(dipy_home, 'isbi2013') - md5_list = ['42911a70f232321cf246315192d69c42', # data - '90e8cf66e0f4d9737a3b3c0da24df5ea', # bval - '4b7aa2757a1ccab140667b76e8075cb1'] # bvec + md5_list = ['42911a70f232321cf246315192d69c42', # data + '90e8cf66e0f4d9737a3b3c0da24df5ea', # bval + '4b7aa2757a1ccab140667b76e8075cb1'] # bvec url_list = [uraw, ubval, ubvec] fname_list = ['phantom64.nii.gz', 'phantom64.bval', 'phantom64.bvec'] @@ -200,7 +200,9 @@ def fetch_isbi2013_2shell(): print('Done.') print('Files copied in folder %s' % folder) else: - print('Dataset is already in place. If you want to fetch it again, please first remove the folder %s ' % folder) + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) def read_isbi2013_2shell(): @@ -242,9 +244,9 @@ def fetch_sherbrooke_3shell(): ubvec = url + '3shells-1000-2000-3500-N193.bvec' folder = pjoin(dipy_home, 'sherbrooke_3shell') - md5_list = ['0b735e8f16695a37bfbd66aab136eb66', # data - 'e9b9bb56252503ea49d31fb30a0ac637', # bval - '0c83f7e8b917cd677ad58a078658ebb7'] # bvec + md5_list = ['0b735e8f16695a37bfbd66aab136eb66', # data + 'e9b9bb56252503ea49d31fb30a0ac637', # bval + '0c83f7e8b917cd677ad58a078658ebb7'] # bvec url_list = [uraw, ubval, ubvec] fname_list = ['HARDI193.nii.gz', 'HARDI193.bval', 'HARDI193.bvec'] @@ -261,7 +263,9 @@ def fetch_sherbrooke_3shell(): print('Done.') print('Files copied in folder %s' % folder) else: - print('Dataset is already in place. If you want to fetch it again, please first remove the folder %s ' % folder) + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) def read_sherbrooke_3shell(): @@ -329,9 +333,9 @@ def fetch_stanford_hardi(): ubvec = url + 'dwi.bvecs' folder = pjoin(dipy_home, 'stanford_hardi') - md5_list = ['0b18513b46132b4d1051ed3364f2acbc', # data - '4e08ee9e2b1d2ec3fddb68c70ae23c36', # bval - '4c63a586f29afc6a48a5809524a76cb4'] # bvec + md5_list = ['0b18513b46132b4d1051ed3364f2acbc', # data + '4e08ee9e2b1d2ec3fddb68c70ae23c36', # bval + '4c63a586f29afc6a48a5809524a76cb4'] # bvec url_list = [uraw, ubval, ubvec] fname_list = ['HARDI150.nii.gz', 'HARDI150.bval', 'HARDI150.bvec'] @@ -348,7 +352,9 @@ def fetch_stanford_hardi(): print('Done.') print('Files copied in folder %s' % folder) else: - print('Dataset is already in place. If you want to fetch it again, please first remove the folder %s ' % folder) + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) def read_stanford_hardi(): @@ -406,10 +412,10 @@ def fetch_taiwan_ntu_dsi(): ureadme = 'http://dl.dropbox.com/u/2481924/license_taiwan_ntu_dsi.txt' folder = pjoin(dipy_home, 'taiwan_ntu_dsi') - md5_list = ['950408c0980a7154cb188666a885a91f', # data - '602e5cb5fad2e7163e8025011d8a6755', # bval - 'a95eb1be44748c20214dc7aa654f9e6b', # bvec - '7fa1d5e272533e832cc7453eeba23f44'] # license + md5_list = ['950408c0980a7154cb188666a885a91f', # data + '602e5cb5fad2e7163e8025011d8a6755', # bval + 'a95eb1be44748c20214dc7aa654f9e6b', # bvec + '7fa1d5e272533e832cc7453eeba23f44'] # license url_list = [uraw, ubval, ubvec, ureadme] fname_list = ['DSI203.nii.gz', 'DSI203.bval', 'DSI203.bvec', 'DSI203_license.txt'] @@ -430,7 +436,9 @@ def fetch_taiwan_ntu_dsi(): print('http://dsi-studio.labsolver.org') else: - print('Dataset is already in place. If you want to fetch it again, please first remove the folder %s ' % folder) + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) def read_taiwan_ntu_dsi(): @@ -464,6 +472,7 @@ def read_taiwan_ntu_dsi(): img = nib.load(fraw) return img, gtab + def fetch_syn_data(): """ Download t1 and b0 volumes from the same session """ @@ -473,8 +482,8 @@ def fetch_syn_data(): folder = pjoin(dipy_home, 'syn_test') - md5_list = ['701bda02bb769655c7d4a9b1df2b73a6', # t1 - 'e4b741f0c77b6039e67abb2885c97a78'] # b0 + md5_list = ['701bda02bb769655c7d4a9b1df2b73a6', # t1 + 'e4b741f0c77b6039e67abb2885c97a78'] # b0 url_list = [t1, b0] fname_list = ['t1.nii.gz', 'b0.nii.gz'] @@ -491,7 +500,9 @@ def fetch_syn_data(): print('Done.') print('Files copied in folder %s' % folder) else: - print('Dataset is already in place. If you want to fetch it again, please first remove the folder %s ' % folder) + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) def read_syn_data(): From 264300c40774cfb5ed313bd02af98428935df486 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Apr 2015 14:29:58 -0400 Subject: [PATCH 037/242] More PEP 8 in the same file --- dipy/data/fetcher.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 0b2309abef..d8812ae45b 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -161,9 +161,12 @@ def check_md5(filename, stored_md5): """ computed_md5 = _get_file_md5(filename) if stored_md5 != computed_md5: - print ("MD5 checksum of filename", filename, "failed. Expected MD5 was", stored_md5, - "but computed MD5 was", computed_md5, '\n', - "Please check if the data has been downloaded correctly or if the upstream data has changed.") + msg = "MD5 checksum of filename " + filename + " failed.\n" + msg += "Expected MD5 was " + stored_md5 + "\n" + msg += "Current MD5 is " + computed_md5 + "\n" + msg += "Please check if the data has been downloaded " + msg += "correctly or if the upstream data has changed." + print (msg) def _get_file_data(fname, url): From 1f1ab2c451e253a46b89a804f40377576f426fe8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Apr 2015 18:29:18 -0400 Subject: [PATCH 038/242] NF: made new class which separates the window creation and interaction process --- dipy/viz/tests/test_fvtk_widgets.py | 64 +++++++++++++++++++++-- dipy/viz/widget.py | 52 ++++++++++++++++--- dipy/viz/window.py | 80 +++++++++++++++++++++++++++-- 3 files changed, 184 insertions(+), 12 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 1c6244ca8b..d50994e26a 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -32,6 +32,7 @@ def print_status(obj, event): renderer.SetBackground(np.random.rand(3)) slider = widget.slider(iren=iren, callback=print_status) + # text = widget.text(iren, None) iren.Initialize() @@ -112,12 +113,69 @@ def win_callback(obj, event): ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) ren_win.Render() - iren.Start() + # iren.Start() arr = window.snapshot(renderer, size=(600, 600)) + +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_button_widget_show(): + + renderer = window.renderer() + + lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) + stream_actor = actor.streamtube(lines, colors) + + window.add(renderer, stream_actor) + + # renderer.ResetCamera() + + from dipy.viz.window import ShowManager + + show_manager = ShowManager(renderer) + + def button_callback(obj, event): + print('Button Pressed') + + show_manager.initialize() + + """ + fetch_viz_icons() + button_png = read_viz_icons(fname='home3.png') + + button = widget.button(show_manager.iren, button_callback, + button_png, (.8, 1.2), (40, 40)) + + button.place(renderer) + + def win_callback(obj, event): + print('Window modified') + button.place(renderer) + + + show_manager.add_window_callback(win_callback) + + """ + show_manager.render() + + text = widget.text(show_manager.iren, None) + + show_manager.render() + show_manager.start() + + # show(renderer) + + arr = window.snapshot(renderer, size=(600, 600)) + + report = window.analyze_snapshot(arr) + + print(report) + if __name__ == '__main__': # test_slider_widget() - test_button_widget() - # npt.run_module_suite() \ No newline at end of file + # test_button_widget() + # npt.run_module_suite() + test_button_widget_show() \ No newline at end of file diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index cac7ae000e..23e47b5f52 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -57,8 +57,7 @@ def compute_bounds(renderer, normalized_display_position, size): bds[1] = bds[0] + size[0] bds[2] = upperRight.GetComputedDisplayValue(renderer)[1] - size[1] bds[3] = bds[2] + size[1] - - print(bds) + # print(bds) return bds @@ -68,7 +67,6 @@ def button(iren, callback, fname, button_norm_coords, button_size): image1.SetFileName(fname) image1.Update() - #button_rep = vtk.vtkProp3DButtonRepresentation() button_rep = vtk.vtkTexturedButtonRepresentation2D() button_rep.SetNumberOfStates(2) @@ -78,8 +76,7 @@ def button(iren, callback, fname, button_norm_coords, button_size): button_rep.SetPlaceFactor(1) - #READ THIS! - #http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget + # http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget class ButtonWidget(vtk.vtkButtonWidget): @@ -89,7 +86,7 @@ def place(self, renderer): self.GetRepresentation().PlaceWidget(bds) self.On() - button = ButtonWidget() # vtk.vtkButtonWidget() + button = ButtonWidget() button.SetInteractor(iren) button.SetRepresentation(button_rep) button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) @@ -100,3 +97,46 @@ def place(self, renderer): return button +def text(iren, callback, message="LOLz", + coord1=(0.15, 0.15), coord2=(0.7, 0.2), + color=(0, 1, 1), + opacity=1.): + + + widget = vtk.vtkTextWidget() + widget.SetInteractor(iren) + widget.On() + widget.GetTextActor().SetInput("This is a test") + widget.GetTextActor().GetTextProperty().SetColor(0, 1, 0) + widget.GetRepresentation().GetPositionCoordinate().SetValue(.15, .15) + widget.GetRepresentation().GetPosition2Coordinate().SetValue(.7, .2) + widget.SelectableOn() + + # Create the TextActor + # text_actor = vtk.vtkTextActor() + # text_actor.SetInput("This is a test") + #text_actor.GetTextProperty().SetColor(color) + # text_actor.GetTextProperty().SetOpacity(opacity) + + # Create the text representation. Used for positioning the text_actor + # text_representation = vtk.vtkTextRepresentation() + # text_representation.GetPositionCoordinate().SetValue(*coord1) + # text_representation.GetPosition2Coordinate().SetValue(*coord2) + + # Create the TextWidget + # Note that the SelectableOff method MUST be invoked! + # According to the documentation : + # + # SelectableOn/Off indicates whether the interior region of the widget can + # be selected or not. If not, then events (such as left mouse down) allow + # the user to "move" the widget, and no selection is possible. Otherwise + # the SelectRegion() method is invoked. + +# text_widget = vtk.vtkTextWidget() +# text_widget.SetRepresentation(text_representation) +# text_widget.SetInteractor(iren) +# text_widget.SetTextActor(text_actor) +# text_widget.SelectableOn() +# text_widget.On() + + return widget diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 330f56425f..882dc999ba 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -2,6 +2,8 @@ import numpy as np from scipy import ndimage +import Tkinter +import tkFileDialog # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -9,6 +11,7 @@ from dipy import __version__ as dipy_version from dipy.utils.six import string_types + # import vtk # Allow import, but disable doctests if we don't have vtk vtk, have_vtk, setup_module = optional_package('vtk') @@ -17,7 +20,6 @@ _, have_imread, _ = optional_package('Image') if have_vtk: - version = vtk.vtkVersion.GetVTKSourceVersion().split(' ')[-1] major_version = vtk.vtkVersion.GetVTKMajorVersion() from vtk.util.numpy_support import vtk_to_numpy @@ -91,7 +93,6 @@ def save_file_dialog(initial_file='dipy.png', default_extension='.png', filetypes=(("PNG file", "*.png"), ("All Files", "*.*"))): """ Simple Tk file dialog """ - import Tkinter, tkFileDialog root = Tkinter.Tk() root.withdraw() filepath = tkFileDialog.asksaveasfilename(initialfile='dipy.png', @@ -100,7 +101,80 @@ def save_file_dialog(initial_file='dipy.png', default_extension='.png', return filepath -def show(ren, title='Dipy', size=(300, 300), png_magnify=1): +class ShowManager(object): + + def __init__(self, ren, title='Dipy', size=(300, 300), png_magnify=1): + + self.title = title + self.size = size + self.png_magnify = png_magnify + + ren.ResetCamera() + window = vtk.vtkRenderWindow() + window.AddRenderer(ren) + # window.SetAAFrames(6) + window.SetWindowName(title + ' ' + dipy_version) + window.SetSize(size[0], size[1]) + + style = vtk.vtkInteractorStyleTrackballCamera() + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(window) + + def key_press_standard(obj, event): + + key = obj.GetKeySym() + if key == 's' or key == 'S': + print('Saving image...') + renderLarge = vtk.vtkRenderLargeImage() + if major_version <= 5: + renderLarge.SetInput(ren) + else: + renderLarge.SetInput(ren) + renderLarge.SetMagnification(png_magnify) + renderLarge.Update() + + file_types = (("PNG file", "*.png"), ("All Files", "*.*")) + filepath = save_file_dialog(initial_file='dipy.png', + default_extension='.png', + filetypes=file_types) + if filepath == '': + print('No file was provided in the dialog') + else: + writer = vtk.vtkPNGWriter() + writer.SetInputConnection(renderLarge.GetOutputPort()) + writer.SetFileName(filepath) + writer.Write() + print('File ' + filepath + ' is saved.') + + self.window = window + self.ren = ren + self.iren = iren + self.style = style + + self.iren.AddObserver('KeyPressEvent', key_press_standard) + + self.iren.SetInteractorStyle(self.style) + + def initialize(self): + self.iren.Initialize() + # picker.Pick(85, 126, 0, ren) + + def render(self): + self.window.Render() + + def start(self): + self.iren.Start() + # window.RemoveAllObservers() + # ren.SetRenderWindow(None) + self.window.RemoveRenderer(self.ren) + self.ren.SetRenderWindow(None) + + def add_window_callback(self, win_callback): + self.window.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) + self.window.Render() + + +def show(ren, title='Dipy', size=(300, 300), png_magnify=1, widgets=None): """ Show window Notes From b6a44065e432decae494f937a28c5a6b4eb285ee Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Apr 2015 22:22:57 -0400 Subject: [PATCH 039/242] NF: added text widget with simple callback --- dipy/viz/actor.py | 4 +- dipy/viz/tests/test_fvtk_widgets.py | 17 +++++--- dipy/viz/widget.py | 67 ++++++++++++++++------------- 3 files changed, 52 insertions(+), 36 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 5a31c4c795..2da2098ab0 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -111,7 +111,7 @@ def butcher(data, affine): saggital = vtk.vtkImageActor() # set_input(saggital, plane_colors.GetOutput()) saggital.GetMapper().SetInputConnection(plane_colors.GetOutputPort()) - #saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) + # saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) saggital.SetDisplayExtent(x1, x2, y1, y2, z2/2, z2/2) # saggital.SetDisplayExtent(25, 25, 0, 49, 0, 49) saggital.Update() @@ -225,7 +225,7 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, actor.GetProperty().SetDiffuse(0.15) # .3 actor.GetProperty().SetSpecular(0.05) # .3 actor.GetProperty().SetSpecularPower(6) - #actor.GetProperty().SetInterpolationToGouraud() + # actor.GetProperty().SetInterpolationToGouraud() actor.GetProperty().SetInterpolationToPhong() actor.GetProperty().BackfaceCullingOn() actor.GetProperty().SetOpacity(opacity) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index d50994e26a..d2f0d9b598 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -126,7 +126,7 @@ def test_button_widget_show(): lines = [np.random.rand(10, 3), np.random.rand(20, 3)] colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) - stream_actor = actor.streamtube(lines, colors) + stream_actor = actor.line(lines, colors) window.add(renderer, stream_actor) @@ -141,7 +141,6 @@ def button_callback(obj, event): show_manager.initialize() - """ fetch_viz_icons() button_png = read_viz_icons(fname='home3.png') @@ -157,10 +156,16 @@ def win_callback(obj, event): show_manager.add_window_callback(win_callback) - """ show_manager.render() - text = widget.text(show_manager.iren, None) + def text_callback(obj, event): + print(event) + print('Text moved') + print(obj) + print('Rep') + print(obj.GetRepresentation()) + + text = widget.text(show_manager.iren, text_callback, opacity=1., selectable=False, border=True) show_manager.render() show_manager.start() @@ -171,7 +176,9 @@ def win_callback(obj, event): report = window.analyze_snapshot(arr) - print(report) + print(report.objects) + imshow(report.labels) + if __name__ == '__main__': diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 23e47b5f52..f5121fa5cf 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -97,31 +97,27 @@ def place(self, renderer): return button -def text(iren, callback, message="LOLz", - coord1=(0.15, 0.15), coord2=(0.7, 0.2), - color=(0, 1, 1), - opacity=1.): - - - widget = vtk.vtkTextWidget() - widget.SetInteractor(iren) - widget.On() - widget.GetTextActor().SetInput("This is a test") - widget.GetTextActor().GetTextProperty().SetColor(0, 1, 0) - widget.GetRepresentation().GetPositionCoordinate().SetValue(.15, .15) - widget.GetRepresentation().GetPosition2Coordinate().SetValue(.7, .2) - widget.SelectableOn() +def text(iren, callback, message="Accelerating computational anatomy...", + coord1=(.2, .2), coord2=(.7, .2), + color=(.9, .9, .9), + opacity=1., + selectable=True, + border=True): # Create the TextActor - # text_actor = vtk.vtkTextActor() - # text_actor.SetInput("This is a test") - #text_actor.GetTextProperty().SetColor(color) - # text_actor.GetTextProperty().SetOpacity(opacity) + text_actor = vtk.vtkTextActor() + text_actor.SetInput(message) + text_actor.GetTextProperty().SetColor(color) + text_actor.GetTextProperty().SetOpacity(opacity) # Create the text representation. Used for positioning the text_actor - # text_representation = vtk.vtkTextRepresentation() - # text_representation.GetPositionCoordinate().SetValue(*coord1) - # text_representation.GetPosition2Coordinate().SetValue(*coord2) + text_representation = vtk.vtkTextRepresentation() + text_representation.GetPositionCoordinate().SetValue(*coord1) + text_representation.GetPosition2Coordinate().SetValue(*coord2) + if border: + text_representation.SetShowBorderToOn() + else: + text_representation.SetShowBorderToOff() # Create the TextWidget # Note that the SelectableOff method MUST be invoked! @@ -132,11 +128,24 @@ def text(iren, callback, message="LOLz", # the user to "move" the widget, and no selection is possible. Otherwise # the SelectRegion() method is invoked. -# text_widget = vtk.vtkTextWidget() -# text_widget.SetRepresentation(text_representation) -# text_widget.SetInteractor(iren) -# text_widget.SetTextActor(text_actor) -# text_widget.SelectableOn() -# text_widget.On() - - return widget + text_widget = vtk.vtkTextWidget() + text_widget.SetRepresentation(text_representation) + text_widget.SetInteractor(iren) + text_widget.SetTextActor(text_actor) + if selectable: + text_widget.SelectableOn() + else: + text_widget.SelectableOff() + text_widget.On() + + text_widget.AddObserver(vtk.vtkCommand.InteractionEvent, callback) + + # This is a hack for avoiding not plotting the text widget when + # backface culling in On on a different actor + ss = vtk.vtkSphereSource() + mapper = vtk.vtkPolyDataMapper() + mapper.SetInputConnection(ss.GetOutputPort()) + actor = vtk.vtkActor() + actor.GetProperty().BackfaceCullingOff() + + return text_widget From ed848ae3e76fb924a42cbc2b9187e88c93edb044 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Apr 2015 09:24:41 -0400 Subject: [PATCH 040/242] PEP8 in actor.py --- dipy/viz/actor.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 2da2098ab0..c9fdfd11d0 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -155,12 +155,12 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, Notes ----- - Streamtubes can be heavy on GPU when loading many streamlines and therefore, - you may experience slow rendering time depending on system GPU. A solution - to this problem is to reduce the number of points in each streamline. In Dipy - we provide an algorithm that will reduce the number of points on the straighter - parts of the streamline but keep more points on the curvier parts. This can - be used in the following way + Streamtubes can be heavy on GPU when loading many streamlines and + therefore, you may experience slow rendering time depending on system GPU. + A solution to this problem is to reduce the number of points in each + streamline. In Dipy we provide an algorithm that will reduce the number of + points on the straighter parts of the streamline but keep more points on + the curvier parts. This can be used in the following way from dipy.tracking.distances import approx_polygon_track lines = [approx_polygon_track(line, 0.2) for line in lines] @@ -179,7 +179,7 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, next_input = poly_normals.GetOutputPort() # Spline interpolation - if (spline_subdiv is not None) and (spline_subdiv > 0) : + if (spline_subdiv is not None) and (spline_subdiv > 0): spline_filter = set_input(vtk.vtkSplineFilter(), next_input) spline_filter.SetSubdivideToSpecified() spline_filter.SetNumberOfSubdivisions(spline_subdiv) @@ -190,7 +190,7 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, tube_filter = set_input(vtk.vtkTubeFilter(), next_input) tube_filter.SetNumberOfSides(tube_sides) tube_filter.SetRadius(linewidth) - #tube_filter.SetVaryRadiusToVaryRadiusByScalar() + # tube_filter.SetVaryRadiusToVaryRadiusByScalar() tube_filter.CappingOn() tube_filter.Update() next_input = tube_filter.GetOutputPort() @@ -201,7 +201,7 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, poly_mapper.SetScalarModeToUsePointFieldData() poly_mapper.SelectColorArray("Colors") poly_mapper.GlobalImmediateModeRenderingOn() - #poly_mapper.SetColorModeToMapScalars() + # poly_mapper.SetColorModeToMapScalars() poly_mapper.Update() # Color Scale with a lookup table @@ -289,7 +289,7 @@ def line(lines, colors=None, opacity=1, linewidth=1, next_input = poly_data # use spline interpolation - if (spline_subdiv is not None) and (spline_subdiv > 0) : + if (spline_subdiv is not None) and (spline_subdiv > 0): spline_filter = set_input(vtk.vtkSplineFilter(), next_input) spline_filter.SetSubdivideToSpecified() spline_filter.SetNumberOfSubdivisions(spline_subdiv) @@ -300,7 +300,7 @@ def line(lines, colors=None, opacity=1, linewidth=1, poly_mapper.ScalarVisibilityOn() poly_mapper.SetScalarModeToUsePointFieldData() poly_mapper.SelectColorArray("Colors") - #poly_mapper.SetColorModeToMapScalars() + # poly_mapper.SetColorModeToMapScalars() poly_mapper.Update() # Color Scale with a lookup table From c7eabedf67ebdc53dd11be86ce8d094bda248f05 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Apr 2015 09:39:50 -0400 Subject: [PATCH 041/242] More PEP8 same file --- dipy/viz/actor.py | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index c9fdfd11d0..98cd4d2927 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -66,7 +66,7 @@ def butcher(data, affine): image_resliced.Update() # Get back resliced image - #im = image_data #image_resliced.GetOutput() + # im = image_data #image_resliced.GetOutput() # An outline provides context around the data. # outline_data = vtk.vtkOutlineFilter() @@ -345,7 +345,7 @@ def lines_to_vtk_polydata(lines, colors=None): is_colormap : bool, true if the input color array was a colormap """ - #Get the 3d points_array + # Get the 3d points_array points_array = np.vstack(lines) nb_lines = len(lines) @@ -355,7 +355,7 @@ def lines_to_vtk_polydata(lines, colors=None): # Get lines_array in vtk input format lines_array = [] - points_per_line = np.zeros([nb_lines],np.int64) + points_per_line = np.zeros([nb_lines], np.int64) current_position = 0 for i in lines_range: current_len = len(lines[i]) @@ -363,7 +363,7 @@ def lines_to_vtk_polydata(lines, colors=None): end_position = current_position + current_len lines_array += [current_len] - lines_array += range(current_position,end_position) + lines_array += range(current_position, end_position) current_position = end_position lines_array = np.array(lines_array) @@ -379,36 +379,35 @@ def lines_to_vtk_polydata(lines, colors=None): is_colormap = False # Get colors_array (reformat to have colors for each points) # - if/else tested and work in normal simple case - if colors is None: #set automatic rgb colors + if colors is None: # set automatic rgb colors cols_arr = line_colors(lines) colors_mapper = np.repeat(lines_range, points_per_line, axis=0) vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) else: cols_arr = np.asarray(colors) - if cols_arr.dtype == np.object: # colors is a list of colors + if cols_arr.dtype == np.object: # colors is a list of colors vtk_colors = numpy_to_vtk_colors(255 * np.vstack(colors)) else: - if len(cols_arr) == nb_points: # one colors per points / colormap way + if len(cols_arr) == nb_points: vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) is_colormap = True - elif cols_arr.ndim == 1: # the same colors for all points + elif cols_arr.ndim == 1: # the same colors for all points vtk_colors = numpy_to_vtk_colors( - np.tile(255 * cols_arr, (nb_points, 1)) ) + np.tile(255 * cols_arr, (nb_points, 1))) - - elif cols_arr.ndim == 2: # map color to each line + elif cols_arr.ndim == 2: # map color to each line colors_mapper = np.repeat(lines_range, points_per_line, axis=0) vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) - else: # colormap - # get colors for each vertex + else: # colormap + # get colors for each vertex cols_arr = trilinear_interp(cols_arr, points_array) vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) is_colormap = True vtk_colors.SetName("Colors") - #Create the poly_data + # Create the poly_data poly_data = vtk.vtkPolyData() poly_data.SetPoints(vtk_points) poly_data.SetLines(vtk_lines) @@ -416,8 +415,8 @@ def lines_to_vtk_polydata(lines, colors=None): return poly_data, is_colormap -def colormap_lookup_table(scale_range=(0,1), hue_range=(0.8,0), - saturation_range=(1,1), value_range=(0.8,0.8)): +def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), + saturation_range=(1, 1), value_range=(0.8, 0.8)): """ Default Lookup table for the colormap """ vtk_lookup_table = vtk.vtkLookupTable() @@ -446,8 +445,8 @@ def scalar_bar(lookup_table): return scalar_bar -def plot_stats( values, names=None, colors=np.array([0,0,0,255]), - lookup_table=None, scalar_bar=None): +def plot_stats(values, names=None, colors=np.array([0, 0, 0, 255]), + lookup_table=None, scalar_bar=None): """ Plots statstics in a new windows """ @@ -472,10 +471,10 @@ def plot_stats( values, names=None, colors=np.array([0,0,0,255]), graph_line = chart.AddPlot(vtk.vtkChart.LINE) graph_line.SetInput(table, 0, i) graph_line.SetColor(color[0], color[1], color[2], color[3]) - #graph_line.GetPen().SetLineType(vtk.vtkPen.SOLID_LINE) + # graph_line.GetPen().SetLineType(vtk.vtkPen.SOLID_LINE) graph_line.SetWidth(2.0) - if lookup_table is not None : + if lookup_table is not None: graph_line.SetMarkerStyle(vtk.vtkPlotPoints.CIRCLE) graph_line.ScalarVisibilityOn() graph_line.SetLookupTable(lookup_table) From 3789fd60fcb2cec9847add2d7a87b64b0b7143ad Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Apr 2015 13:33:08 -0400 Subject: [PATCH 042/242] Removed vtk 2d charts from new actor.py file --- dipy/viz/actor.py | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 98cd4d2927..679ca0d5bd 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -443,50 +443,3 @@ def scalar_bar(lookup_table): scalar_bar.SetNumberOfLabels(6) return scalar_bar - - -def plot_stats(values, names=None, colors=np.array([0, 0, 0, 255]), - lookup_table=None, scalar_bar=None): - """ Plots statstics in a new windows - """ - - nb_lines = len(values) - if colors.ndim == 1: - colors = np.repeat(colors.reshape((1, -1)), nb_lines, axis=0) - - chart = vtk.vtkChartXY() - chart.SetShowLegend(True) - - table = vtk.vtkTable() - table.SetNumberOfRows(values.shape[1]) - - for i in range(nb_lines): - value = values[i] - vtk_array = numpy_support.numpy_to_vtk(value, deep=1) - vtk_array.SetName(names[i]) - table.AddColumn(vtk_array) - - color = colors[i] * 255 - if i > 0: - graph_line = chart.AddPlot(vtk.vtkChart.LINE) - graph_line.SetInput(table, 0, i) - graph_line.SetColor(color[0], color[1], color[2], color[3]) - # graph_line.GetPen().SetLineType(vtk.vtkPen.SOLID_LINE) - graph_line.SetWidth(2.0) - - if lookup_table is not None: - graph_line.SetMarkerStyle(vtk.vtkPlotPoints.CIRCLE) - graph_line.ScalarVisibilityOn() - graph_line.SetLookupTable(lookup_table) - graph_line.SelectColorArray(i) - - # render plot - view = vtk.vtkContextView() - view.GetRenderer().SetBackground(colors[0][0], colors[0][1], colors[0][2]) - view.GetRenderWindow().SetSize(400, 300) - view.GetScene().AddItem(chart) - - if scalar_bar is not None: - view.GetRenderer().AddActor2D(scalar_bar) - - return view From 303971844227788496d384399d49cc313eaf0e4b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Apr 2015 17:15:12 -0400 Subject: [PATCH 043/242] TEST: new bundle maps test --- dipy/viz/actor.py | 5 ++-- dipy/viz/tests/test_fvtk_actors.py | 42 +++++++++++++++++++++++++++-- dipy/viz/tests/test_fvtk_widgets.py | 4 +-- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 679ca0d5bd..a6e2ec9a98 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -431,14 +431,15 @@ def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), return vtk_lookup_table -def scalar_bar(lookup_table): +def scalar_bar(lookup_table, title=" "): """ Default Scalar bar actor for the colormap - Deepcopy the lookup_table because sometime vtkPolyDataMapper delete it + Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it """ lookup_table_copy = vtk.vtkLookupTable() lookup_table_copy.DeepCopy(lookup_table) scalar_bar = vtk.vtkScalarBarActor() + scalar_bar.SetTitle(title) scalar_bar.SetLookupTable(lookup_table_copy) scalar_bar.SetNumberOfLabels(6) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index a3a5eee143..84d2f083a3 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -6,6 +6,8 @@ import numpy.testing as npt from nibabel.tmpdirs import TemporaryDirectory +from dipy.tracking.streamline import center_streamlines, transform_streamlines +from dipy.align.tests.test_streamlinear import fornix_streamlines @npt.dec.skipif(not actor.have_vtk) @@ -62,7 +64,6 @@ def test_streamtube_and_line_actors(): c2.SetPosition(2, 0, 0) window.add(renderer, c2) - window.show(renderer) arr = window.snapshot(renderer) report = window.analyze_snapshot(arr, @@ -73,6 +74,43 @@ def test_streamtube_and_line_actors(): npt.assert_equal(report.colors_found, [True, True]) +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +@npt.dec.skipif(not window.have_imread) +def test_bundle_maps(): + + renderer = window.renderer() + bundle = fornix_streamlines() + bundle, shift = center_streamlines(bundle) + + mat = np.array([[1, 0, 0, 100], + [0, 1, 0, 100], + [0, 0, 1, 100], + [0, 0, 0, 1.]]) + + bundle = transform_streamlines(bundle, mat) + + # metric = np.random.rand(*(200, 200, 200)) + metric = 100 * np.ones((200, 200, 200)) + + # add lower values + metric[100, :, :] = 100 * 0.5 + + # create a nice orange-red colormap + lut = actor.colormap_lookup_table(scale_range=(0., 100.), + hue_range=(0., 0.1), + saturation_range=(1, 1), + value_range=(1., 1)) + + line = actor.streamtube(bundle, metric, linewidth=0.1, lookup_colormap=lut) + window.add(renderer, line) + window.add(renderer, actor.scalar_bar(lut, ' ')) + + report = window.analyze_renderer(renderer) + + if __name__ == "__main__": - npt.run_module_suite() + #npt.run_module_suite() + test_bundle_maps() + # test_streamtube_and_line_actors() diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index d2f0d9b598..3f31d7cbce 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -113,7 +113,7 @@ def win_callback(obj, event): ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) ren_win.Render() - # iren.Start() + iren.Start() arr = window.snapshot(renderer, size=(600, 600)) @@ -153,7 +153,6 @@ def win_callback(obj, event): print('Window modified') button.place(renderer) - show_manager.add_window_callback(win_callback) show_manager.render() @@ -177,7 +176,6 @@ def text_callback(obj, event): report = window.analyze_snapshot(arr) print(report.objects) - imshow(report.labels) if __name__ == '__main__': From 935a3d090d45c640673c8b66218c7f81af813d87 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Apr 2015 18:12:48 -0400 Subject: [PATCH 044/242] NF: receive class names in analyze_renderer --- dipy/viz/actor.py | 3 +-- dipy/viz/tests/test_fvtk_actors.py | 6 ++++-- dipy/viz/window.py | 7 +++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index a6e2ec9a98..dfd2eb7f2e 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -1,5 +1,4 @@ - -#from __future__ import division, print_function, absolute_import +# from __future__ import division, print_function, absolute_import import numpy as np diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 84d2f083a3..120e9140eb 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -102,15 +102,17 @@ def test_bundle_maps(): saturation_range=(1, 1), value_range=(1., 1)) - line = actor.streamtube(bundle, metric, linewidth=0.1, lookup_colormap=lut) + line = actor.line(bundle, metric, linewidth=0.1, lookup_colormap=lut) window.add(renderer, line) window.add(renderer, actor.scalar_bar(lut, ' ')) report = window.analyze_renderer(renderer) + npt.assert_almost_equal(report.actors, 1) + # window.show(renderer) if __name__ == "__main__": - #npt.run_module_suite() + # npt.run_module_suite() test_bundle_maps() # test_streamtube_and_line_actors() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 882dc999ba..f9286f1f8d 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -444,6 +444,13 @@ class ReportRenderer(object): report.bg_color = ren.GetBackground() report.collection = ren.GetActors() + report.actors = report.collection.GetNumberOfItems() + + report.collection.InitTraversal() + report.actors_classnames = [] + for i in range(report.actors): + class_name = report.collection.GetNextActor().GetClassName() + report.actors_classnames.append(class_name) return report From b7b4d9920159d79e5cbca231ff9dcb346c5852c0 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Apr 2015 18:57:35 -0400 Subject: [PATCH 045/242] RF: pep 8 in viz.utils --- dipy/viz/utils.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 526bd6cc85..ebd39283cf 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -134,9 +134,9 @@ def trilinear_interp(input_array, indices): assert (input_array.ndim > 2 )," array need to be at least 3dimensions" assert (input_array.ndim < 5 )," dont support array with more than 4 dims" - x_indices = indices[:,0] - y_indices = indices[:,1] - z_indices = indices[:,2] + x_indices = indices[:, 0] + y_indices = indices[:, 1] + z_indices = indices[:, 2] x0 = x_indices.astype(np.integer) y0 = y_indices.astype(np.integer) @@ -145,28 +145,28 @@ def trilinear_interp(input_array, indices): y1 = y0 + 1 z1 = z0 + 1 - #Check if xyz1 is beyond array boundary: - x1[np.where(x1==input_array.shape[0])] = x0.max() - y1[np.where(y1==input_array.shape[1])] = y0.max() - z1[np.where(z1==input_array.shape[2])] = z0.max() + # Check if xyz1 is beyond array boundary: + x1[np.where(x1 == input_array.shape[0])] = x0.max() + y1[np.where(y1 == input_array.shape[1])] = y0.max() + z1[np.where(z1 == input_array.shape[2])] = z0.max() if input_array.ndim == 3: x = x_indices - x0 y = y_indices - y0 z = z_indices - z0 elif input_array.ndim == 4: - x = np.expand_dims(x_indices - x0, axis = 1) - y = np.expand_dims(y_indices - y0, axis = 1) - z = np.expand_dims(z_indices - z0, axis = 1) - - output = (input_array[x0,y0,z0]*(1-x)*(1-y)*(1-z) + - input_array[x1,y0,z0]*x*(1-y)*(1-z) + - input_array[x0,y1,z0]*(1-x)*y*(1-z) + - input_array[x0,y0,z1]*(1-x)*(1-y)*z + - input_array[x1,y0,z1]*x*(1-y)*z + - input_array[x0,y1,z1]*(1-x)*y*z + - input_array[x1,y1,z0]*x*y*(1-z) + - input_array[x1,y1,z1]*x*y*z) + x = np.expand_dims(x_indices - x0, axis=1) + y = np.expand_dims(y_indices - y0, axis=1) + z = np.expand_dims(z_indices - z0, axis=1) + + output = (input_array[x0, y0, z0] * (1 - x) * (1 - y) * (1 - z) + + input_array[x1, y0, z0] * x * (1 - y) * (1 - z) + + input_array[x0, y1, z0] * (1 - x) * y * (1-z) + + input_array[x0, y0, z1] * (1 - x) * (1 - y) * z + + input_array[x1, y0, z1] * x * (1 - y) * z + + input_array[x0, y1, z1] * (1 - x) * y * z + + input_array[x1, y1, z0] * x * y * (1 - z) + + input_array[x1, y1, z1] * x * y * z) return output From d9f07360d7bf7df2a536b09156282d7105dfc65a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Apr 2015 13:29:45 -0400 Subject: [PATCH 046/242] RF: raised ValueError --- dipy/viz/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index ebd39283cf..0edfc9f929 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -131,8 +131,8 @@ def trilinear_interp(input_array, indices): """ Evaluate the input_array data at the given indices """ - assert (input_array.ndim > 2 )," array need to be at least 3dimensions" - assert (input_array.ndim < 5 )," dont support array with more than 4 dims" + if input_array.ndim <= 2 or input_array.ndim >= 5: + raise ValueError("Input array can only be 3d or 4d") x_indices = indices[:, 0] y_indices = indices[:, 1] @@ -154,6 +154,7 @@ def trilinear_interp(input_array, indices): x = x_indices - x0 y = y_indices - y0 z = z_indices - z0 + elif input_array.ndim == 4: x = np.expand_dims(x_indices - x0, axis=1) y = np.expand_dims(y_indices - y0, axis=1) From 41e115acd02a0b4359e4b9ca8ad70c814af52b93 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 30 Apr 2015 18:13:00 -0400 Subject: [PATCH 047/242] DOC: started section for visualization examples --- doc/examples/interact_data.py | 99 ------------------- doc/examples/introduction_to_visualization.py | 32 ++++++ doc/examples/valid_examples.txt | 1 + doc/examples_index.rst | 6 ++ 4 files changed, 39 insertions(+), 99 deletions(-) delete mode 100644 doc/examples/interact_data.py create mode 100644 doc/examples/introduction_to_visualization.py diff --git a/doc/examples/interact_data.py b/doc/examples/interact_data.py deleted file mode 100644 index c0edb2e0f4..0000000000 --- a/doc/examples/interact_data.py +++ /dev/null @@ -1,99 +0,0 @@ -import numpy as np -from dipy.viz import actor, window, widget - - -# Change with Stanford data -dname = '/home/eleftherios/Data/Cunnane_Elef/08-111-609-AC15/work/' -import nibabel as nib -from nibabel import trackvis as tv - -world_coords = False -streamline_opacity = .5 -slicer_opacity = .5 -depth_peeling = False - - -img = nib.load(dname + 't1_brain_warp.nii.gz') -data = img.get_data() -affine = img.get_affine() - - -img_fa = nib.load(dname + 'results/metrics/fa.nii') -fa = img_fa.get_data() -affine_fa = img_fa.get_affine() - - -streams, hdr = tv.read(dname + 'results/bundles/cst.right.trk', - points_space="rasmm") -streamlines = [s[0] for s in streams] - -streams, hdr = tv.read(dname + 'results/bundles/af.left.trk', - points_space="rasmm") -streamlines += [s[0] for s in streams] - -streams, hdr = tv.read(dname + 'results/bundles/cc_1.trk', - points_space="rasmm") -streamlines += [s[0] for s in streams] - -if not world_coords: - from dipy.tracking.streamline import transform_streamlines - streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) - -renderer = window.renderer() - -stream_actor = actor.streamtube(streamlines, fa) - -if not world_coords: - slicer = actor.butcher(data, affine=np.eye(4)) -else: - slicer = actor.butcher(data, affine) - -slicer.GetProperty().SetOpacity(slicer_opacity) -stream_actor.GetProperty().SetOpacity(streamline_opacity) - -window.add(renderer, stream_actor) -window.add(renderer, slicer) - - -def change_slice(obj, event): - global slicer - z = int(np.round(obj.GetSliderRepresentation().GetValue())) - - print(obj) - print(event) - print(z) - slicer.SetDisplayExtent(0, 255, 0, 255, z, z) - slicer.Update() - -import vtk - -ren_win = vtk.vtkRenderWindow() -ren_win.AddRenderer(renderer) - -if depth_peeling: - # http://www.vtk.org/Wiki/VTK/Depth_Peeling - ren_win.SetAlphaBitPlanes(1) - ren_win.SetMultiSamples(0) - renderer.SetUseDepthPeeling(1) - renderer.SetMaximumNumberOfPeels(10) - renderer.SetOcclusionRatio(0.1) - - -iren = vtk.vtkRenderWindowInteractor() -iren.SetRenderWindow(ren_win) - -slider = widget.slider(iren=iren, callback=change_slice) - -iren.Initialize() - -ren_win.Render() - -if depth_peeling: - dp_bool = str(bool(renderer.GetLastRenderingUsedDepthPeeling())) - print('Depth peeling used? ' + dp_bool) - -iren.Start() - - -# ren_win.RemoveRenderer(renderer) -# renderer.SetRenderWindow(None) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py new file mode 100644 index 0000000000..411cbe36f5 --- /dev/null +++ b/doc/examples/introduction_to_visualization.py @@ -0,0 +1,32 @@ +""" +========================================= +Introduction to interactive visualization +========================================= + +In DIPY we created a thin interface to access many of the capabilities +available in the Visualization Toolkit framework (VTK) but tailored to the +needs of structural and diffusion imaging. Initially the 3D visualization +module was named ``fvtk``, meaning functions using vtk. This is still available +for backwards compatibility but now there is a more comprehensive way to access +the main functions using the following import. +""" + +from dipy.viz import window, actor, widgets + +""" +The main objects/functions which are used for drawing actors (e.g. slices, +streamlines) in a window or in a file are available in window. And the actors +are available in actor. There are also some objects which allow to add buttons +and slider and these interact both with windows and actors and those are in +widjets. +""" + + + + + + + + + + diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index 1b35e08f38..2790377aea 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -36,3 +36,4 @@ bundle_registration.py tracking_tissue_classifier.py piesno.py + introduction_to_visualization.py \ No newline at end of file diff --git a/doc/examples_index.rst b/doc/examples_index.rst index bcace9f612..8ebd83228b 100644 --- a/doc/examples_index.rst +++ b/doc/examples_index.rst @@ -189,6 +189,12 @@ File Formats - :ref:`example_streamline_formats` +------------- +Visualization +------------- + +- :ref:`example_introduction_to_visualization` + .. In order to build the examples, you'll need (on Debian) sudo apt-get install python-tables python-matplotib python-vtk From 11ed9411e2b746d7ff130f3cb4a4147b58394100 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 30 Apr 2015 18:24:28 -0400 Subject: [PATCH 048/242] RF: removed show from tests --- dipy/viz/tests/test_fvtk_actors.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 120e9140eb..cd5cde7b92 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import os import numpy as np @@ -21,7 +20,7 @@ def test_butcher(): affine = np.eye(4) slicer = actor.butcher(data, affine) window.add(renderer, slicer) - window.show(renderer) + # window.show(renderer) # copy pixels in numpy array directly arr = window.snapshot(renderer) @@ -113,6 +112,6 @@ def test_bundle_maps(): if __name__ == "__main__": - # npt.run_module_suite() - test_bundle_maps() + npt.run_module_suite() + # test_bundle_maps() # test_streamtube_and_line_actors() From 5cf8a645c3a324b527a41c38ba3a0cf8c3aadfc9 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 30 Apr 2015 18:59:31 -0400 Subject: [PATCH 049/242] RF: butcher is now slice --- dipy/viz/actor.py | 2 +- dipy/viz/tests/test_fvtk_actors.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index dfd2eb7f2e..ae1951698a 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,7 +21,7 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() -def butcher(data, affine): +def slice(data, affine): vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) vol = vol.astype('uint8') diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index cd5cde7b92..20577eebf4 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -12,13 +12,13 @@ @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) @npt.dec.skipif(not window.have_imread) -def test_butcher(): +def test_slice(): renderer = window.renderer() data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) - slicer = actor.butcher(data, affine) + slicer = actor.slice(data, affine) window.add(renderer, slicer) # window.show(renderer) @@ -36,7 +36,7 @@ def test_butcher(): # save pixels in png file not a numpy array with TemporaryDirectory() as tmpdir: - fname = os.path.join(tmpdir, 'butcher.png') + fname = os.path.join(tmpdir, 'slice.png') # window.show(renderer) arr = window.snapshot(renderer, fname) report = window.analyze_snapshot(fname, find_objects=True) From 3fe19514d0cc435d1c12646a3b933260823c66fd Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 30 Apr 2015 19:08:35 -0400 Subject: [PATCH 050/242] Adding renderer class --- dipy/viz/window.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index f9286f1f8d..788d033653 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -28,6 +28,33 @@ from scipy.misc import imread +class Renderer(vtk.vtkRenderer): + + def background(self, color): + self.SetBackground(color) + + def add(self, actor): + if isinstance(actor, vtk.vtkVolume): + self.AddVolume(actor) + else: + self.AddActor(actor) + + def rm(self, actor): + """ Remove a specific actor + """ + self.RemoveActor(actor) + + def clear(self): + """ Remove all actors from the renderer + """ + self.RemoveAllViewProps() + + def rm_all(self): + """ Remove all actors from the renderer + """ + self.RemoveAllViewProps() + + def renderer(background=None): """ Create a renderer. From e3827a341a244f6cce853ff7037b7e3d9085166b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 3 May 2015 19:53:58 -0400 Subject: [PATCH 051/242] RF: removing renderer and actor manipulation functions in window --- dipy/viz/fvtk.py | 48 +--------------------------------------------- dipy/viz/window.py | 24 ++++++++++++++--------- 2 files changed, 16 insertions(+), 56 deletions(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 53b5e0a4c9..efd781f09a 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -64,53 +64,7 @@ # Create a cell picker. picker = vtk.vtkCellPicker() - -def ren(): - '''Create a renderer. - - Returns - ------- - v : vtkRenderer() object - Renderer. - - Examples - -------- - >>> from dipy.viz import fvtk - >>> import numpy as np - >>> r=fvtk.ren() - >>> lines=[np.random.rand(10,3)] - >>> c=fvtk.line(lines, fvtk.colors.red) - >>> fvtk.add(r,c) - >>> #fvtk.show(r) - ''' - return vtk.vtkRenderer() - - -def add(ren, a): - ''' Add a specific actor - ''' - if isinstance(a, vtk.vtkVolume): - ren.AddVolume(a) - else: - ren.AddActor(a) - - -def rm(ren, a): - ''' Remove a specific actor - ''' - ren.RemoveActor(a) - - -def clear(ren): - ''' Remove all actors from the renderer - ''' - ren.RemoveAllViewProps() - - -def rm_all(ren): - ''' Remove all actors from the renderer - ''' - clear(ren) + from dipy.viz.window import ren, renderer, add, clear, rm, rm_all def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 788d033653..b0998fc1bb 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -29,6 +29,15 @@ class Renderer(vtk.vtkRenderer): + """ The key rendering preparation object + + This is an important object that is responsible for preparing objects + e.g. actors and volumes for rendering. This is a more pythonic version + of ``vtkRenderer`` proving simple methods for adding and removing actors + but also it provides access to all the functionality + available in ``vtkRenderer``. + + """ def background(self, color): self.SetBackground(color) @@ -79,41 +88,38 @@ def renderer(background=None): >>> fvtk.add(r,c) >>> #fvtk.show(r) """ - ren = vtk.vtkRenderer() + ren = Renderer() if background is not None: ren.SetBackground(background) return ren if have_vtk: - ren = renderer() + ren = renderer def add(ren, a): """ Add a specific actor """ - if isinstance(a, vtk.vtkVolume): - ren.AddVolume(a) - else: - ren.AddActor(a) + ren.add(a) def rm(ren, a): """ Remove a specific actor """ - ren.RemoveActor(a) + ren.rm(a) def clear(ren): """ Remove all actors from the renderer """ - ren.RemoveAllViewProps() + ren.clear() def rm_all(ren): """ Remove all actors from the renderer """ - clear(ren) + ren.rm_all() def save_file_dialog(initial_file='dipy.png', default_extension='.png', From 82f4273e98c557bb843dc3bc75f047dac3946b9d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 3 May 2015 20:14:11 -0400 Subject: [PATCH 052/242] RF: removed show and record from fvtk.py and moved it to window.py --- dipy/viz/fvtk.py | 193 +---------------------------------------------- 1 file changed, 2 insertions(+), 191 deletions(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index efd781f09a..0879767a4e 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -64,7 +64,8 @@ # Create a cell picker. picker = vtk.vtkCellPicker() - from dipy.viz.window import ren, renderer, add, clear, rm, rm_all + from dipy.viz.window import (ren, renderer, add, clear, rm, rm_all, + show, record, snapshot) def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): @@ -1613,195 +1614,5 @@ def camera(ren, pos=None, focal=None, viewup=None, verbose=True): return cam -def show(ren, title='Dipy', size=(300, 300), png_magnify=1): - """ Show window - - Notes - ----- - To save a screenshot press's' and check your current directory - for ``fvtk.png``. - - Parameters - ------------ - ren : vtkRenderer() object - As returned from function ``ren()``. - title : string - A string for the window title bar. - size : (int, int) - ``(width, height)`` of the window - png_magnify : int - Number of times to magnify the screenshot. - - Notes - ----- - If you want to: - - * navigate in the the 3d world use the left - middle - right mouse buttons - * reset the screen press 'r' - * save a screenshot press 's' - * quit press 'q' - - See also - --------- - dipy.viz.fvtk.record - - Examples - ---------- - >>> import numpy as np - >>> from dipy.viz import fvtk - >>> r=fvtk.ren() - >>> lines=[np.random.rand(10,3),np.random.rand(20,3)] - >>> colors=np.array([[0.2,0.2,0.2],[0.8,0.8,0.8]]) - >>> c=fvtk.line(lines,colors) - >>> fvtk.add(r,c) - >>> l=fvtk.label(r) - >>> fvtk.add(r,l) - >>> #fvtk.show(r) - - See also - ---------- - dipy.viz.fvtk.record - - """ - - ren.ResetCamera() - window = vtk.vtkRenderWindow() - window.AddRenderer(ren) - # window.SetAAFrames(6) - window.SetWindowName(title) - window.SetSize(size[0], size[1]) - style = vtk.vtkInteractorStyleTrackballCamera() - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(window) - iren.SetPicker(picker) - - def key_press(obj, event): - - key = obj.GetKeySym() - if key == 's' or key == 'S': - print('Saving image...') - renderLarge = vtk.vtkRenderLargeImage() - if major_version <= 5: - renderLarge.SetInput(ren) - else: - renderLarge.SetInputData(ren) - renderLarge.SetMagnification(png_magnify) - renderLarge.Update() - writer = vtk.vtkPNGWriter() - writer.SetInputConnection(renderLarge.GetOutputPort()) - writer.SetFileName('fvtk.png') - writer.Write() - print('Look for fvtk.png in your current working directory.') - - iren.AddObserver('KeyPressEvent', key_press) - iren.SetInteractorStyle(style) - iren.Initialize() - picker.Pick(85, 126, 0, ren) - window.Render() - iren.Start() - - # window.RemoveAllObservers() - # ren.SetRenderWindow(None) - window.RemoveRenderer(ren) - ren.SetRenderWindow(None) - - -def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, - out_path=None, path_numbering=False, n_frames=1, az_ang=10, - magnification=1, size=(300, 300), verbose=False): - ''' This will record a video of your scene - - Records a video as a series of ``.png`` files of your scene by rotating the - azimuth angle az_angle in every frame. - - Parameters - ----------- - ren : vtkRenderer() object - as returned from function ren() - cam_pos : None or sequence (3,), optional - camera position - cam_focal : None or sequence (3,), optional - camera focal point - cam_view : None or sequence (3,), optional - camera view up - out_path : str, optional - output directory for the frames - path_numbering : bool - when recording it changes out_path ot out_path + str(frame number) - n_frames : int, optional - number of frames to save, default 1 - az_ang : float, optional - azimuthal angle of camera rotation. - magnification : int, optional - how much to magnify the saved frame - - Examples - --------- - >>> from dipy.viz import fvtk - >>> r=fvtk.ren() - >>> a=fvtk.axes() - >>> fvtk.add(r,a) - >>> #uncomment below to record - >>> #fvtk.record(r) - >>> #check for new images in current directory - ''' - if ren is None: - ren = vtk.vtkRenderer() - - renWin = vtk.vtkRenderWindow() - renWin.AddRenderer(ren) - renWin.SetSize(size[0], size[1]) - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(renWin) - - # ren.GetActiveCamera().Azimuth(180) - - ren.ResetCamera() - - renderLarge = vtk.vtkRenderLargeImage() - renderLarge.SetInput(ren) - renderLarge.SetMagnification(magnification) - renderLarge.Update() - - writer = vtk.vtkPNGWriter() - ang = 0 - - if cam_pos is not None: - cx, cy, cz = cam_pos - ren.GetActiveCamera().SetPosition(cx, cy, cz) - if cam_focal is not None: - fx, fy, fz = cam_focal - ren.GetActiveCamera().SetFocalPoint(fx, fy, fz) - if cam_view is not None: - ux, uy, uz = cam_view - ren.GetActiveCamera().SetViewUp(ux, uy, uz) - - cam = ren.GetActiveCamera() - if verbose: - print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) - print('Camera Focal Point (%.2f,%.2f,%.2f)' % cam.GetFocalPoint()) - print('Camera View Up (%.2f,%.2f,%.2f)' % cam.GetViewUp()) - - for i in range(n_frames): - ren.GetActiveCamera().Azimuth(ang) - renderLarge = vtk.vtkRenderLargeImage() - renderLarge.SetInput(ren) - renderLarge.SetMagnification(magnification) - renderLarge.Update() - writer.SetInputConnection(renderLarge.GetOutputPort()) - # filename='/tmp/'+str(3000000+i)+'.png' - if path_numbering: - if out_path is None: - filename = str(1000000 + i) + '.png' - else: - filename = out_path + str(1000000 + i) + '.png' - else: - filename = out_path - writer.SetFileName(filename) - writer.Write() - - ang = +az_ang - - if __name__ == "__main__": pass From 1feefc38fb84a5237a8945f45bb4aafd9d9bfa30 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 3 May 2015 20:20:33 -0400 Subject: [PATCH 053/242] RF: removed line and streamutbe from fvtk.py --- dipy/viz/fvtk.py | 324 +---------------------------------------------- 1 file changed, 1 insertion(+), 323 deletions(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 0879767a4e..39c80ecc54 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -66,6 +66,7 @@ from dipy.viz.window import (ren, renderer, add, clear, rm, rm_all, show, record, snapshot) + from dipy.viz.actor import line, streamtube def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): @@ -128,329 +129,6 @@ def axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), return ass -def _lookup(colors): - ''' Internal function - Creates a lookup table with given colors. - - Parameters - ------------ - colors : array, shape (N,3) - Colormap where every triplet is encoding red, green and blue e.g. - - :: - r1,g1,b1 - r2,g2,b2 - ... - rN,gN,bN - - where - - :: - 0= 2: - raise ValueError('Incorrect shape of array in colors') - - if colors.ndim == 1: - N = 1 - - if colors.ndim == 2: - - N = colors.shape[0] - - lut = vtk.vtkLookupTable() - lut.SetNumberOfColors(N) - lut.Build() - - if colors.ndim == 2: - scalar = 0 - for (r, g, b) in colors: - - lut.SetTableValue(scalar, r, g, b, 1.0) - scalar += 1 - if colors.ndim == 1: - - lut.SetTableValue(0, colors[0], colors[1], colors[2], 1.0) - - return lut - - -def streamtube(lines, colors, opacity=1, linewidth=0.15, tube_sides=8, - lod=True, lod_points=10 ** 4, lod_points_size=5): - """ Uses streamtubes to visualize polylines - - Parameters - ---------- - lines : list - list of N curves represented as 2D ndarrays - colors : array (N, 3) or tuple (3,) - opacity : float - linewidth : float - tube_sides : int - lod : bool - use vtkLODActor rather than vtkActor - lod_points : int - number of points to be used when LOD is in effect - lod_points_size : int - size of points when lod is in effect - - Examples - -------- - >>> from dipy.viz import fvtk - >>> r=fvtk.ren() - >>> lines=[np.random.rand(10, 3), np.random.rand(20, 3)] - >>> colors=np.random.rand(2, 3) - >>> c=fvtk.streamtube(lines, colors) - >>> fvtk.add(r,c) - >>> #fvtk.show(r) - - Notes - ----- - Streamtubes can be heavy on GPU when loading many streamlines and therefore, - you may experience slow rendering time depending on system GPU. A solution - to this problem is to reduce the number of points in each streamline. In Dipy - we provide an algorithm that will reduce the number of points on the straighter - parts of the streamline but keep more points on the curvier parts. This can - be used in the following way - - from dipy.tracking.distances import approx_polygon_track - lines = [approx_polygon_track(line, 0.2) for line in lines] - """ - - points = vtk.vtkPoints() - - colors = np.asarray(colors) - if colors.ndim == 1: - colors = np.tile(colors, (len(lines), 1)) - - # Create the polyline. - streamlines = vtk.vtkCellArray() - - cols = vtk.vtkUnsignedCharArray() - cols.SetName("Cols") - cols.SetNumberOfComponents(3) - - len_lines = len(lines) - prior_line_shape = 0 - for i in range(len_lines): - line = lines[i] - streamlines.InsertNextCell(line.shape[0]) - for j in range(line.shape[0]): - points.InsertNextPoint(*line[j]) - streamlines.InsertCellPoint(j + prior_line_shape) - color = (255 * colors[i]).astype('ubyte') - cols.InsertNextTuple3(*color) - prior_line_shape += line.shape[0] - - profileData = vtk.vtkPolyData() - profileData.SetPoints(points) - profileData.SetLines(streamlines) - profileData.GetPointData().AddArray(cols) - - # Add thickness to the resulting line. - profileTubes = vtk.vtkTubeFilter() - profileTubes.SetNumberOfSides(tube_sides) - - if major_version <= 5: - profileTubes.SetInput(profileData) - else: - profileTubes.SetInputData(profileData) - - #profileTubes.SetInput(profileData) - profileTubes.SetRadius(linewidth) - - profileMapper = vtk.vtkPolyDataMapper() - profileMapper.SetInputConnection(profileTubes.GetOutputPort()) - profileMapper.ScalarVisibilityOn() - profileMapper.SetScalarModeToUsePointFieldData() - profileMapper.SelectColorArray("Cols") - profileMapper.GlobalImmediateModeRenderingOn() - - if lod: - profile = vtk.vtkLODActor() - profile.SetNumberOfCloudPoints(lod_points) - profile.GetProperty().SetPointSize(lod_points_size) - else: - profile = vtk.vtkActor() - profile.SetMapper(profileMapper) - - profile.GetProperty().SetAmbient(0) # .3 - profile.GetProperty().SetSpecular(0) # .3 - profile.GetProperty().SetSpecularPower(10) - profile.GetProperty().SetInterpolationToGouraud() - profile.GetProperty().BackfaceCullingOn() - profile.GetProperty().SetOpacity(opacity) - - return profile - - -def line(lines, colors, opacity=1, linewidth=1): - ''' Create an actor for one or more lines. - - Parameters - ------------ - lines : list of arrays representing lines as 3d points for example - lines=[np.random.rand(10,3),np.random.rand(20,3)] - represents 2 lines the first with 10 points and the second with 20 points in x,y,z coordinates. - colors : array, shape (N,3) - Colormap where every triplet is encoding red, green and blue e.g. - - :: - r1,g1,b1 - r2,g2,b2 - ... - rN,gN,bN - - where - - :: - 0=>> from dipy.viz import fvtk - >>> r=fvtk.ren() - >>> lines=[np.random.rand(10,3), np.random.rand(20,3)] - >>> colors=np.random.rand(2,3) - >>> c=fvtk.line(lines, colors) - >>> fvtk.add(r,c) - >>> #fvtk.show(r) - ''' - if not isinstance(lines, types.ListType): - lines = [lines] - - points = vtk.vtkPoints() - lines_ = vtk.vtkCellArray() - linescalars = vtk.vtkFloatArray() - - # lookuptable=vtk.vtkLookupTable() - lookuptable = _lookup(colors) - - scalarmin = 0 - colors = np.asarray(colors) - if colors.ndim == 2: - scalarmax = colors.shape[0] - 1 - if colors.ndim == 1: - scalarmax = 0 - - curPointID = 0 - - m = (0.0, 0.0, 0.0) - n = (1.0, 0.0, 0.0) - - scalar = 0 - # many colors - if colors.ndim == 2: - for Line in lines: - - inw = True - mit = iter(Line) - nit = iter(Line) - next(nit) - - while(inw): - - try: - m = next(mit) - n = next(nit) - - # scalar=sp.rand(1) - - linescalars.SetNumberOfComponents(1) - points.InsertNextPoint(m) - linescalars.InsertNextTuple1(scalar) - - points.InsertNextPoint(n) - linescalars.InsertNextTuple1(scalar) - - lines_.InsertNextCell(2) - lines_.InsertCellPoint(curPointID) - lines_.InsertCellPoint(curPointID + 1) - - curPointID += 2 - except StopIteration: - break - - scalar += 1 - # one color only - if colors.ndim == 1: - for Line in lines: - - inw = True - mit = iter(Line) - nit = iter(Line) - next(nit) - - while(inw): - - try: - m = next(mit) - n = next(nit) - - # scalar=sp.rand(1) - - linescalars.SetNumberOfComponents(1) - points.InsertNextPoint(m) - linescalars.InsertNextTuple1(scalar) - - points.InsertNextPoint(n) - linescalars.InsertNextTuple1(scalar) - - lines_.InsertNextCell(2) - lines_.InsertCellPoint(curPointID) - lines_.InsertCellPoint(curPointID + 1) - - curPointID += 2 - except StopIteration: - break - - polydata = vtk.vtkPolyData() - polydata.SetPoints(points) - polydata.SetLines(lines_) - polydata.GetPointData().SetScalars(linescalars) - - mapper = vtk.vtkPolyDataMapper() - if major_version <= 5: - mapper.SetInput(polydata) - else: - mapper.SetInputData(polydata) - - mapper.SetLookupTable(lookuptable) - - mapper.SetColorModeToMapScalars() - mapper.SetScalarRange(scalarmin, scalarmax) - mapper.SetScalarModeToUsePointData() - - actor = vtk.vtkActor() - actor.SetMapper(mapper) - actor.GetProperty().SetLineWidth(linewidth) - actor.GetProperty().SetOpacity(opacity) - - return actor - - def dots(points, color=(1, 0, 0), opacity=1, dot_size=5): """ Create one or more 3d points From 5e8e727a11e107d2724bef14deffea0dd2f975e8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 3 May 2015 21:43:54 -0400 Subject: [PATCH 054/242] TEST: value error corrected --- dipy/viz/tests/test_fvtk_widgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 3f31d7cbce..a698ba7cc9 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -39,7 +39,7 @@ def print_status(obj, event): ren_win.Render() iren.Start() arr = window.snapshot(renderer, size=(600, 600)) - report = window.analyze_snapshot(renderer, arr) + report = window.analyze_snapshot(arr) @npt.dec.skipif(not actor.have_vtk) @@ -182,5 +182,5 @@ def text_callback(obj, event): # test_slider_widget() # test_button_widget() - # npt.run_module_suite() - test_button_widget_show() \ No newline at end of file + npt.run_module_suite() + # test_button_widget_show() \ No newline at end of file From 6933e378801978a9c498d40f58e36ad4af1f94ed Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 5 May 2015 19:30:18 -0400 Subject: [PATCH 055/242] TEST: new test more focused on functions available on window --- dipy/viz/tests/test_fvtk_window.py | 143 +++++++++++++++++++++++++++++ dipy/viz/window.py | 14 +-- 2 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 dipy/viz/tests/test_fvtk_window.py diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py new file mode 100644 index 0000000000..1ac25d395c --- /dev/null +++ b/dipy/viz/tests/test_fvtk_window.py @@ -0,0 +1,143 @@ +import numpy as np +from dipy.viz import actor +from dipy.viz import window +from dipy.viz import widget +from dipy.data import fetch_viz_icons, read_viz_icons +import numpy.testing as npt + + +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_window_module(): + + ren = window.Renderer() + + ren.background((1, 0.5, 0)) + + window.show(ren) + + arr = window.snapshot(ren) + + report = window.analyze_snapshot(arr, + colors=[(255, 128, 0), (0, 127, 0)]) + + npt.assert_equal(report.objects, 1) + npt.assert_equal(report.colors_found, [True, False]) + + +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_slider_widget(): + + renderer = window.renderer() + + # Create 2 lines with 2 different colors + lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) + c = actor.line(lines, colors, linewidth=3) + window.add(renderer, c) + + from dipy.viz.window import vtk + + ren_win = vtk.vtkRenderWindow() + ren_win.AddRenderer(renderer) + + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(ren_win) + + def print_status(obj, event): + print(obj) + print(event) + renderer.SetBackground(np.random.rand(3)) + + slider = widget.slider(iren=iren, callback=print_status) + # text = widget.text(iren, None) + + iren.Initialize() + + ren_win.Render() + iren.Start() + arr = window.snapshot(renderer, size=(600, 600)) + report = window.analyze_snapshot(arr) + + +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_button_widget(): + + from dipy.viz.window import vtk + + renderer = window.renderer() + + lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) + stream_actor = actor.streamtube(lines, colors) + + window.add(renderer, stream_actor) + + renderer.ResetCamera() + + ren_win = vtk.vtkRenderWindow() + ren_win.AddRenderer(renderer) + ren_win.SetSize(600, 600) + + iren = vtk.vtkRenderWindowInteractor() + iren.SetRenderWindow(ren_win) + + def callback(obj, event): + print(obj) + print('Pressed') + + fetch_viz_icons() + button_png = read_viz_icons(fname='home3.png') + + button = widget.button(iren, callback, + button_png, (.8, 1.2), (50, 50)) + + button_png_plus = read_viz_icons(fname='plus.png') + button_plus = widget.button(iren, callback, + button_png_plus, (.7, .8), (50, 50)) + + button_png_minus = read_viz_icons(fname='minus.png') + button_minus = widget.button(iren, callback, + button_png_minus, (.9, .8), (50, 50)) + + def print_status(obj, event): + print(obj) + print(event) + renderer.SetBackground(np.random.rand(3)) + + slider = widget.slider(iren=iren, callback=print_status) + + iren.Initialize() + + ren_win.Render() + + button_norm_coords = (.9, 1.2) + button_size = (50, 50) + + button.place(renderer) + button_plus.place(renderer) + button_minus.place(renderer) + + def win_callback(obj, event): + # print(obj) + print(event) + print(obj.GetSize()) + + button.place(renderer) + button_plus.place(renderer) + button_minus.place(renderer) + + ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) + + ren_win.Render() + iren.Start() + + arr = window.snapshot(renderer, size=(600, 600)) + + +if __name__ == '__main__': + + test_window_module() + # npt.run_module_suite() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index b0998fc1bb..2e4e7fb7bf 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -425,15 +425,16 @@ def snapshot(ren, fname=None, size=(300, 300)): ----------- ren : vtkRenderer as returned from function renderer() - fname : str or None - If None return numpy array otherwise save png file. + fname : str + Save PNG file. size : (int, int) ``(width, height)`` of the window Returns ------- - arr : ndarray or bool - If fname is None returns array or True otherwise. + arr : array + Color array of size (width, height, 3) where the last dimension + holds the RGB values. """ width, height = size @@ -527,11 +528,12 @@ class ReportSnapshot(object): report = ReportSnapshot() if colors is not None: - if isinstance(im, tuple): + if isinstance(colors, tuple): colors = [colors] flags = [False] * len(colors) for (i, col) in enumerate(colors): - flags[i] = np.sum(im == np.array(col)) > 0 + # find if the current color exist in the array + flags[i] = np.any(np.all(im == col, axis = -1)) report.colors_found = flags From 3c478c185cd05d7927a743341c9ead11b599d713 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 5 May 2015 21:46:49 -0400 Subject: [PATCH 056/242] BF: corrected problem with axes at VTK 6 --- dipy/viz/fvtk.py | 4 +- dipy/viz/tests/test_fvtk_window.py | 121 ++++------------------------- 2 files changed, 15 insertions(+), 110 deletions(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 39c80ecc54..ad6621c350 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -80,7 +80,7 @@ def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): if major_version <= 5: arrowm.SetInput(arrow.GetOutput()) else: - arrowm.SetInputData(arrow.GetOutput()) + arrowm.SetInputConnection(arrow.GetOutputPort()) arrowa = vtk.vtkActor() arrowa.SetMapper(arrowm) @@ -95,7 +95,7 @@ def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): def axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), opacity=1): """ Create an actor with the coordinate's system axes where - red = x, green = y, blue =z. + red = x, green = y, blue = z. Parameters ---------- diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 1ac25d395c..a2e3f32202 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -1,20 +1,18 @@ import numpy as np -from dipy.viz import actor -from dipy.viz import window -from dipy.viz import widget +from dipy.viz import actor, window, fvtk from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) -def test_window_module(): +def test_renderer(): ren = window.Renderer() ren.background((1, 0.5, 0)) - window.show(ren) + # window.show(ren) arr = window.snapshot(ren) @@ -24,120 +22,27 @@ def test_window_module(): npt.assert_equal(report.objects, 1) npt.assert_equal(report.colors_found, [True, False]) + axes = fvtk.axes() -@npt.dec.skipif(not actor.have_vtk) -@npt.dec.skipif(not actor.have_vtk_colors) -def test_slider_widget(): - - renderer = window.renderer() - - # Create 2 lines with 2 different colors - lines = [np.random.rand(10, 3), np.random.rand(20, 3)] - colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) - c = actor.line(lines, colors, linewidth=3) - window.add(renderer, c) - - from dipy.viz.window import vtk - - ren_win = vtk.vtkRenderWindow() - ren_win.AddRenderer(renderer) - - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(ren_win) - - def print_status(obj, event): - print(obj) - print(event) - renderer.SetBackground(np.random.rand(3)) - - slider = widget.slider(iren=iren, callback=print_status) - # text = widget.text(iren, None) - - iren.Initialize() - - ren_win.Render() - iren.Start() - arr = window.snapshot(renderer, size=(600, 600)) - report = window.analyze_snapshot(arr) - - -@npt.dec.skipif(not actor.have_vtk) -@npt.dec.skipif(not actor.have_vtk_colors) -def test_button_widget(): - - from dipy.viz.window import vtk - - renderer = window.renderer() + ren.add(axes) - lines = [np.random.rand(10, 3), np.random.rand(20, 3)] - colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) - stream_actor = actor.streamtube(lines, colors) - - window.add(renderer, stream_actor) - - renderer.ResetCamera() - - ren_win = vtk.vtkRenderWindow() - ren_win.AddRenderer(renderer) - ren_win.SetSize(600, 600) - - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(ren_win) - - def callback(obj, event): - print(obj) - print('Pressed') - - fetch_viz_icons() - button_png = read_viz_icons(fname='home3.png') - - button = widget.button(iren, callback, - button_png, (.8, 1.2), (50, 50)) - - button_png_plus = read_viz_icons(fname='plus.png') - button_plus = widget.button(iren, callback, - button_png_plus, (.7, .8), (50, 50)) - - button_png_minus = read_viz_icons(fname='minus.png') - button_minus = widget.button(iren, callback, - button_png_minus, (.9, .8), (50, 50)) - - def print_status(obj, event): - print(obj) - print(event) - renderer.SetBackground(np.random.rand(3)) - - slider = widget.slider(iren=iren, callback=print_status) - - iren.Initialize() - - ren_win.Render() + window.show(ren) - button_norm_coords = (.9, 1.2) - button_size = (50, 50) + ren.rm(axes) - button.place(renderer) - button_plus.place(renderer) - button_minus.place(renderer) + window.show(ren) - def win_callback(obj, event): - # print(obj) - print(event) - print(obj.GetSize()) + window.add(ren, axes) - button.place(renderer) - button_plus.place(renderer) - button_minus.place(renderer) + window.show(ren) - ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) + ren.rm_all() - ren_win.Render() - iren.Start() + window.show(ren) - arr = window.snapshot(renderer, size=(600, 600)) if __name__ == '__main__': - test_window_module() + test_renderer() # npt.run_module_suite() From 7ccaa2dc15065303d8f5c070115215cd04e2751e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 6 May 2015 12:02:25 -0400 Subject: [PATCH 057/242] TEST: improving converage for test_fvtk_window --- dipy/viz/tests/test_fvtk_window.py | 39 +++++++++++++++++++----------- dipy/viz/window.py | 11 ++++----- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index a2e3f32202..1bba3c2eb5 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -10,35 +10,46 @@ def test_renderer(): ren = window.Renderer() - ren.background((1, 0.5, 0)) + bg_float = (1, 0.5, 0) - # window.show(ren) + bg_color = tuple((np.round(255 * np.array(bg_float))).astype('uint8')) - arr = window.snapshot(ren) + ren.background(bg_float) + # window.show(ren) + arr = window.snapshot(ren) report = window.analyze_snapshot(arr, - colors=[(255, 128, 0), (0, 127, 0)]) - - npt.assert_equal(report.objects, 1) + bg_color=bg_color, + colors=[bg_color, (0, 127, 0)]) + npt.assert_equal(report.objects, 0) npt.assert_equal(report.colors_found, [True, False]) axes = fvtk.axes() - ren.add(axes) - - window.show(ren) + arr = window.snapshot(ren) + report = window.analyze_snapshot(arr, bg_color) + npt.assert_equal(report.objects, 1) ren.rm(axes) - - window.show(ren) + arr = window.snapshot(ren) + report = window.analyze_snapshot(arr, bg_color) + npt.assert_equal(report.objects, 0) window.add(ren, axes) - - window.show(ren) + arr = window.snapshot(ren) + report = window.analyze_snapshot(arr, bg_color) + npt.assert_equal(report.objects, 1) ren.rm_all() + arr = window.snapshot(ren) + report = window.analyze_snapshot(arr, bg_color) + npt.assert_equal(report.objects, 0) + + ren2 = window.renderer(bg_float) + ren2.background((0, 0, 0.)) - window.show(ren) + report = window.analyze_renderer(ren2) + npt.assert_equal(report.bg_color, (0, 0, 0)) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 2e4e7fb7bf..ac3b6134c0 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -511,9 +511,8 @@ def analyze_snapshot(im, bg_color=(0, 0, 0), colors=None, Returns ------- report : ReportSnapshot - This is an object with attibutes like ``bg_color_check`` or - ``colors_check`` that give information about the result of the analysis - of the current ``im``. + This is an object with attibutes like ``colors_found`` that give + information about what was found in the current snapshot array ``im``. """ if isinstance(im, string_types): @@ -522,7 +521,6 @@ def analyze_snapshot(im, bg_color=(0, 0, 0), colors=None, class ReportSnapshot(object): objects = None labels = None - bg_color_check = False colors_found = False report = ReportSnapshot() @@ -540,13 +538,14 @@ class ReportSnapshot(object): if find_objects is True: weights = [0.299, 0.587, 0.144] gray = np.dot(im[..., :3], weights) - mask_threshold = np.dot(bg_color, weights) + background = np.dot(bg_color, weights) if strel is None: strel = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]]) - labels, objects = ndimage.label(gray > mask_threshold, strel) + + labels, objects = ndimage.label(gray != background, strel) report.labels = labels report.objects = objects From bd99723d940267167caafc1d895cb879e885904b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 6 May 2015 21:36:57 -0400 Subject: [PATCH 058/242] RF: show is now using ShowManager --- dipy/viz/tests/test_fvtk_window.py | 12 ++++++ dipy/viz/window.py | 60 +++++------------------------- 2 files changed, 21 insertions(+), 51 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 1bba3c2eb5..4fa9c69ccf 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -26,6 +26,9 @@ def test_renderer(): axes = fvtk.axes() ren.add(axes) + + # window.show(ren) + arr = window.snapshot(ren) report = window.analyze_snapshot(arr, bg_color) npt.assert_equal(report.objects, 1) @@ -51,6 +54,15 @@ def test_renderer(): report = window.analyze_renderer(ren2) npt.assert_equal(report.bg_color, (0, 0, 0)) + ren2.add(axes) + + report = window.analyze_renderer(ren2) + npt.assert_equal(report.actors, 3) + + window.rm(ren2, axes) + report = window.analyze_renderer(ren2) + npt.assert_equal(report.actors, 0) + if __name__ == '__main__': diff --git a/dipy/viz/window.py b/dipy/viz/window.py index ac3b6134c0..34def24464 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -146,7 +146,10 @@ def __init__(self, ren, title='Dipy', size=(300, 300), png_magnify=1): window = vtk.vtkRenderWindow() window.AddRenderer(ren) # window.SetAAFrames(6) - window.SetWindowName(title + ' ' + dipy_version) + if title == 'Dipy': + window.SetWindowName(title + ' ' + dipy_version) + else: + window.SetWindowName(title) window.SetSize(size[0], size[1]) style = vtk.vtkInteractorStyleTrackballCamera() @@ -207,7 +210,7 @@ def add_window_callback(self, win_callback): self.window.Render() -def show(ren, title='Dipy', size=(300, 300), png_magnify=1, widgets=None): +def show(ren, title='Dipy', size=(300, 300), png_magnify=1): """ Show window Notes @@ -258,55 +261,10 @@ def show(ren, title='Dipy', size=(300, 300), png_magnify=1, widgets=None): """ - ren.ResetCamera() - window = vtk.vtkRenderWindow() - window.AddRenderer(ren) - # window.SetAAFrames(6) - - window.SetWindowName(title + ' ' + dipy_version) - window.SetSize(size[0], size[1]) - style = vtk.vtkInteractorStyleTrackballCamera() - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(window) - # iren.SetPicker(picker) - - def key_press(obj, event): - - key = obj.GetKeySym() - if key == 's' or key == 'S': - print('Saving image...') - renderLarge = vtk.vtkRenderLargeImage() - if major_version <= 5: - renderLarge.SetInput(ren) - else: - renderLarge.SetInput(ren) - renderLarge.SetMagnification(png_magnify) - renderLarge.Update() - - file_types = (("PNG file", "*.png"), ("All Files", "*.*")) - filepath = save_file_dialog(initial_file='dipy.png', - default_extension='.png', - filetypes=file_types) - if filepath == '': - print('No file was provided in the dialog') - else: - writer = vtk.vtkPNGWriter() - writer.SetInputConnection(renderLarge.GetOutputPort()) - writer.SetFileName(filepath) - writer.Write() - print('File ' + filepath + ' is saved.') - - iren.AddObserver('KeyPressEvent', key_press) - iren.SetInteractorStyle(style) - iren.Initialize() - # picker.Pick(85, 126, 0, ren) - window.Render() - iren.Start() - - # window.RemoveAllObservers() - # ren.SetRenderWindow(None) - window.RemoveRenderer(ren) - ren.SetRenderWindow(None) + show_manager = ShowManager(ren, title, size, png_magnify) + show_manager.initialize() + show_manager.render() + show_manager.start() def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, From 28fb6a08081044cf121a6def2da79be50be34efd Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 7 May 2015 12:02:57 -0400 Subject: [PATCH 059/242] Working to understand better the relationship of different widgets with the normalized coordinate system --- dipy/viz/tests/test_fvtk_widgets.py | 66 ++++++++++++----------------- dipy/viz/widget.py | 1 + 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index a698ba7cc9..cf7b97b2ff 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -1,7 +1,5 @@ import numpy as np -from dipy.viz import actor -from dipy.viz import window -from dipy.viz import widget +from dipy.viz import actor, window, widget from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt @@ -10,34 +8,30 @@ @npt.dec.skipif(not actor.have_vtk_colors) def test_slider_widget(): - renderer = window.renderer() + renderer = window.Renderer() # Create 2 lines with 2 different colors lines = [np.random.rand(10, 3), np.random.rand(20, 3)] colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) c = actor.line(lines, colors, linewidth=3) - window.add(renderer, c) - - from dipy.viz.window import vtk - ren_win = vtk.vtkRenderWindow() - ren_win.AddRenderer(renderer) + renderer.add(c) - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(ren_win) + show_manager = window.ShowManager(renderer) + show_manager.initialize() - def print_status(obj, event): + def slider_callback(obj, event): print(obj) print(event) renderer.SetBackground(np.random.rand(3)) - slider = widget.slider(iren=iren, callback=print_status) - # text = widget.text(iren, None) + slider = widget.slider(iren=show_manager.iren, + callback=slider_callback) + # text = widget.text(slider.iren, None) - iren.Initialize() + show_manager.render() + show_manager.start() - ren_win.Render() - iren.Start() arr = window.snapshot(renderer, size=(600, 600)) report = window.analyze_snapshot(arr) @@ -48,22 +42,16 @@ def test_button_widget(): from dipy.viz.window import vtk - renderer = window.renderer() + renderer = window.Renderer() lines = [np.random.rand(10, 3), np.random.rand(20, 3)] - colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) + colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) stream_actor = actor.streamtube(lines, colors) - window.add(renderer, stream_actor) - - renderer.ResetCamera() + renderer.add(stream_actor) - ren_win = vtk.vtkRenderWindow() - ren_win.AddRenderer(renderer) - ren_win.SetSize(600, 600) + show_manager= window.ShowManager(renderer, size=(600, 600)) - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(ren_win) def callback(obj, event): print(obj) @@ -72,15 +60,15 @@ def callback(obj, event): fetch_viz_icons() button_png = read_viz_icons(fname='home3.png') - button = widget.button(iren, callback, + button = widget.button(show_manager.iren, callback, button_png, (.8, 1.2), (50, 50)) button_png_plus = read_viz_icons(fname='plus.png') - button_plus = widget.button(iren, callback, + button_plus = widget.button(show_manager.iren, callback, button_png_plus, (.7, .8), (50, 50)) button_png_minus = read_viz_icons(fname='minus.png') - button_minus = widget.button(iren, callback, + button_minus = widget.button(show_manager.iren, callback, button_png_minus, (.9, .8), (50, 50)) def print_status(obj, event): @@ -88,11 +76,10 @@ def print_status(obj, event): print(event) renderer.SetBackground(np.random.rand(3)) - slider = widget.slider(iren=iren, callback=print_status) + slider = widget.slider(iren=show_manager.iren, callback=print_status) - iren.Initialize() - - ren_win.Render() + show_manager.initialize() + show_manager.render() button_norm_coords = (.9, 1.2) button_size = (50, 50) @@ -110,10 +97,11 @@ def win_callback(obj, event): button_plus.place(renderer) button_minus.place(renderer) - ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) + # ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) + show_manager.add_window_callback(win_callback) - ren_win.Render() - iren.Start() + show_manager.render() + show_manager.start() arr = window.snapshot(renderer, size=(600, 600)) @@ -181,6 +169,6 @@ def text_callback(obj, event): if __name__ == '__main__': # test_slider_widget() - # test_button_widget() - npt.run_module_suite() + test_button_widget() + # npt.run_module_suite() # test_button_widget_show() \ No newline at end of file diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index f5121fa5cf..ad7f8252f5 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -27,6 +27,7 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() slider_rep.GetPoint1Coordinate().SetValue(*coord1) slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPoint2Coordinate().SetValue(*coord2) slider_rep.SetSliderLength(length) slider_rep.SetSliderWidth(length) From 7f82d0bea57be079bc769def8536c6ee284276ba Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 7 May 2015 21:50:05 -0400 Subject: [PATCH 060/242] Added todo for aligning the slider with the button --- dipy/viz/tests/test_fvtk_widgets.py | 12 ++++++++---- dipy/viz/widget.py | 19 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index cf7b97b2ff..0e2d65b54d 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -61,22 +61,23 @@ def callback(obj, event): button_png = read_viz_icons(fname='home3.png') button = widget.button(show_manager.iren, callback, - button_png, (.8, 1.2), (50, 50)) + button_png, (1., 1.), (80, 50)) button_png_plus = read_viz_icons(fname='plus.png') button_plus = widget.button(show_manager.iren, callback, - button_png_plus, (.7, .8), (50, 50)) + button_png_plus, (1., .8), (120, 50)) button_png_minus = read_viz_icons(fname='minus.png') button_minus = widget.button(show_manager.iren, callback, - button_png_minus, (.9, .8), (50, 50)) + button_png_minus, (1., .8), (50, 50)) def print_status(obj, event): print(obj) print(event) renderer.SetBackground(np.random.rand(3)) - slider = widget.slider(iren=show_manager.iren, callback=print_status) + slider = widget.slider(iren=show_manager.iren, callback=print_status, + coord1=(0.9, 0.5), coord2=(1., 0.5)) show_manager.initialize() show_manager.render() @@ -96,6 +97,9 @@ def win_callback(obj, event): button.place(renderer) button_plus.place(renderer) button_minus.place(renderer) + # TODO + # GET SLICER REPRESENTATION HERE AND SET THE COORDINATES TO ALIGN + # WITH BUTTONS # ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) show_manager.add_window_callback(win_callback) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index ad7f8252f5..4598bf3b18 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -24,11 +24,14 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, slider_rep.SetMaximumValue(max_value) slider_rep.SetValue(value) slider_rep.SetTitleText(label) + slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() slider_rep.GetPoint1Coordinate().SetValue(*coord1) + #1/0 + #test = slider_rep.GetPoint1Coordinate().GetDisplayValue() slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPoint2Coordinate().SetValue(*coord2) + slider_rep.SetSliderLength(length) slider_rep.SetSliderWidth(length) slider_rep.SetEndCapLength(cap_length) @@ -44,17 +47,20 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, slider.KeyPressActivationOff() slider.AddObserver("InteractionEvent", callback) slider.SetEnabled(True) + return slider -def compute_bounds(renderer, normalized_display_position, size): +def button_display_coordinates(renderer, normalized_display_position, size): upperRight = vtk.vtkCoordinate() upperRight.SetCoordinateSystemToNormalizedDisplay() upperRight.SetValue(normalized_display_position[0], normalized_display_position[1]) bds = [0.0] * 6 + #1/0 bds[0] = upperRight.GetComputedDisplayValue(renderer)[0] - size[0] - print(upperRight.GetComputedDisplayValue(renderer)[0]) - print(upperRight.GetComputedDisplayValue(renderer)[1]) + print(upperRight.GetComputedDisplayValue(renderer)[0], + upperRight.GetComputedDisplayValue(renderer)[1]) + print(renderer.GetSize()) bds[1] = bds[0] + size[0] bds[2] = upperRight.GetComputedDisplayValue(renderer)[1] - size[1] bds[3] = bds[2] + size[1] @@ -75,15 +81,14 @@ def button(iren, callback, fname, button_norm_coords, button_size): button_rep.SetButtonTexture(1, image1.GetOutput()) #button_rep.SetButtonTexture(1, image2.GetOutput()) - button_rep.SetPlaceFactor(1) - # http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget class ButtonWidget(vtk.vtkButtonWidget): def place(self, renderer): - bds = compute_bounds(renderer, button_norm_coords, button_size) + bds = button_display_coordinates(renderer, button_norm_coords, button_size) + self.GetRepresentation().SetPlaceFactor(1) self.GetRepresentation().PlaceWidget(bds) self.On() From 40fee35bb1bfb2d2c9814f04f1c0412bc0701c2d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 8 May 2015 12:31:14 -0400 Subject: [PATCH 061/242] NF: adding a place method in SliderWidget --- dipy/viz/tests/test_fvtk_widgets.py | 5 ++--- dipy/viz/widget.py | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 0e2d65b54d..8047d6cb28 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -52,7 +52,6 @@ def test_button_widget(): show_manager= window.ShowManager(renderer, size=(600, 600)) - def callback(obj, event): print(obj) print('Pressed') @@ -98,9 +97,9 @@ def win_callback(obj, event): button_plus.place(renderer) button_minus.place(renderer) # TODO - # GET SLICER REPRESENTATION HERE AND SET THE COORDINATES TO ALIGN + # GET SLIDER REPRESENTATION HERE AND SET THE COORDINATES TO ALIGN # WITH BUTTONS - + slider.place # ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) show_manager.add_window_callback(win_callback) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 4598bf3b18..821cb6c336 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -40,7 +40,20 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, slider_rep.SetLabelFormat(label_format) - slider = vtk.vtkSliderWidget() + class SliderWidget(vtk.vtkSliderWidget): + + def place(self, coord1=None, coord2=None): + + slider_rep = slider.GetRepresentation() + if coord1 is not None: + slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPoint1Coordinate().SetValue(*coord1) + + if coord1 is not None: + slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPoint2Coordinate().SetValue(*coord2) + + slider = SliderWidget() slider.SetInteractor(iren) slider.SetRepresentation(slider_rep) slider.SetAnimationModeToAnimate() From eda6f8c9059a5d759d0236262c63c66b65635863 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 8 May 2015 22:05:01 -0400 Subject: [PATCH 062/242] Progress with slider still some work needed plus some refactoring with the text widget --- dipy/viz/tests/test_fvtk_widgets.py | 61 ++++++++++++++++------------- dipy/viz/widget.py | 46 +++++++++++++--------- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 8047d6cb28..f77fb7c9bb 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -17,7 +17,7 @@ def test_slider_widget(): renderer.add(c) - show_manager = window.ShowManager(renderer) + show_manager = window.ShowManager(renderer, size=(400, 400)) show_manager.initialize() def slider_callback(obj, event): @@ -26,6 +26,9 @@ def slider_callback(obj, event): renderer.SetBackground(np.random.rand(3)) slider = widget.slider(iren=show_manager.iren, + ren=show_manager.ren, + right_normalized_pos=(.98, 0.5), + size=(120, 0), callback=slider_callback) # text = widget.text(slider.iren, None) @@ -38,7 +41,7 @@ def slider_callback(obj, event): @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) -def test_button_widget(): +def test_button_and_slider_widgets(): from dipy.viz.window import vtk @@ -50,43 +53,43 @@ def test_button_widget(): renderer.add(stream_actor) - show_manager= window.ShowManager(renderer, size=(600, 600)) + show_manager= window.ShowManager(renderer, size=(800, 800)) def callback(obj, event): print(obj) print('Pressed') fetch_viz_icons() - button_png = read_viz_icons(fname='home3.png') + button_png = read_viz_icons(fname='camera.png') button = widget.button(show_manager.iren, callback, - button_png, (1., 1.), (80, 50)) + button_png, (.98, 1.), (80, 50)) button_png_plus = read_viz_icons(fname='plus.png') button_plus = widget.button(show_manager.iren, callback, - button_png_plus, (1., .8), (120, 50)) + button_png_plus, (.98, .9), (120, 50)) button_png_minus = read_viz_icons(fname='minus.png') button_minus = widget.button(show_manager.iren, callback, - button_png_minus, (1., .8), (50, 50)) + button_png_minus, (.98, .9), (50, 50)) def print_status(obj, event): - print(obj) - print(event) + # print(obj) + # print(event) renderer.SetBackground(np.random.rand(3)) - slider = widget.slider(iren=show_manager.iren, callback=print_status, - coord1=(0.9, 0.5), coord2=(1., 0.5)) + slider = widget.slider(show_manager.iren, show_manager.ren, + callback=print_status, + right_normalized_pos=(.98, 0.7), + size=(120, 0)) show_manager.initialize() show_manager.render() - button_norm_coords = (.9, 1.2) - button_size = (50, 50) - button.place(renderer) button_plus.place(renderer) button_minus.place(renderer) + slider.place(renderer) def win_callback(obj, event): # print(obj) @@ -96,22 +99,21 @@ def win_callback(obj, event): button.place(renderer) button_plus.place(renderer) button_minus.place(renderer) - # TODO - # GET SLIDER REPRESENTATION HERE AND SET THE COORDINATES TO ALIGN - # WITH BUTTONS - slider.place + slider.place(renderer) + # ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) show_manager.add_window_callback(win_callback) - show_manager.render() + # show_manager.render() + show_manager.start() - arr = window.snapshot(renderer, size=(600, 600)) + arr = window.snapshot(renderer, size=(800, 800)) @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) -def test_button_widget_show(): +def test_text_widget(): renderer = window.renderer() @@ -123,9 +125,7 @@ def test_button_widget_show(): # renderer.ResetCamera() - from dipy.viz.window import ShowManager - - show_manager = ShowManager(renderer) + show_manager = window.ShowManager(renderer) def button_callback(obj, event): print('Button Pressed') @@ -155,7 +155,11 @@ def text_callback(obj, event): print('Rep') print(obj.GetRepresentation()) - text = widget.text(show_manager.iren, text_callback, opacity=1., selectable=False, border=True) + text = widget.text(show_manager.iren, text_callback, + message="Accelerating anatomy...", + coord1=(.4, .2), coord2=(.5, .2), + opacity=1., + selectable=False, border=True) show_manager.render() show_manager.start() @@ -172,6 +176,7 @@ def text_callback(obj, event): if __name__ == '__main__': # test_slider_widget() - test_button_widget() - # npt.run_module_suite() - # test_button_widget_show() \ No newline at end of file + # test_button_and_slider_widgets() + test_text_widget() + # test_button_widget_show() + # npt.run_module_suite() \ No newline at end of file diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 821cb6c336..1630ae959a 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -9,12 +9,10 @@ colors, have_vtk_colors, _ = optional_package('vtk.util.colors') numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') -def slider(iren, callback, min_value=0, max_value=255, value=125, +def slider(iren, ren, callback, min_value=0, max_value=255, value=125, label="Slider", - coord1=(0.8, 0.5), coord2=(0.9, 0.5), - length=0.04, width=0.02, - cap_length=0.01, cap_width=0.01, - tube_width=0.005, + right_normalized_pos=(0.9, 0.5), + size=(50, 0), label_format="%0.0lf"): """ Create a 2D slider with normalized window coordinates """ @@ -25,15 +23,21 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, slider_rep.SetValue(value) slider_rep.SetTitleText(label) - slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPoint1Coordinate().SetValue(*coord1) - #1/0 - #test = slider_rep.GetPoint1Coordinate().GetDisplayValue() slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPoint2Coordinate().SetValue(*coord2) + slider_rep.GetPoint2Coordinate().SetValue(*right_normalized_pos) + + coord2_display = slider_rep.GetPoint2Coordinate().GetComputedDisplayValue(ren) + slider_rep.GetPoint1Coordinate().SetCoordinateSystemToDisplay() + slider_rep.GetPoint1Coordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) + + length=0.04 + width=0.04 + cap_length=0.01 + cap_width=0.01 + tube_width=0.005 slider_rep.SetSliderLength(length) - slider_rep.SetSliderWidth(length) + slider_rep.SetSliderWidth(width) slider_rep.SetEndCapLength(cap_length) slider_rep.SetEndCapWidth(cap_width) slider_rep.SetTubeWidth(tube_width) @@ -42,16 +46,18 @@ def slider(iren, callback, min_value=0, max_value=255, value=125, class SliderWidget(vtk.vtkSliderWidget): - def place(self, coord1=None, coord2=None): + def place(self, renderer): + + slider_rep = self.GetRepresentation() + slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPoint2Coordinate().SetValue(*right_normalized_pos) + + coord2_display = slider_rep.GetPoint2Coordinate().GetComputedDisplayValue(renderer) + slider_rep.GetPoint1Coordinate().SetCoordinateSystemToDisplay() + slider_rep.GetPoint1Coordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) - slider_rep = slider.GetRepresentation() - if coord1 is not None: - slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPoint1Coordinate().SetValue(*coord1) + # slider_rep.SetLabelFormat(label_format) - if coord1 is not None: - slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPoint2Coordinate().SetValue(*coord2) slider = SliderWidget() slider.SetInteractor(iren) @@ -131,7 +137,9 @@ def text(iren, callback, message="Accelerating computational anatomy...", # Create the text representation. Used for positioning the text_actor text_representation = vtk.vtkTextRepresentation() + text_representation.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() text_representation.GetPositionCoordinate().SetValue(*coord1) + text_representation.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() text_representation.GetPosition2Coordinate().SetValue(*coord2) if border: text_representation.SetShowBorderToOn() From 238a9c0c5001a76c256e14af98363bf9e218d1ed Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 11 May 2015 09:56:07 -0400 Subject: [PATCH 063/242] More on text widget --- dipy/viz/tests/test_fvtk_widgets.py | 7 ++++-- dipy/viz/widget.py | 37 ++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index f77fb7c9bb..4e95786535 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -155,9 +155,12 @@ def text_callback(obj, event): print('Rep') print(obj.GetRepresentation()) - text = widget.text(show_manager.iren, text_callback, + text = widget.text(show_manager.iren, + show_manager.ren, + text_callback, message="Accelerating anatomy...", - coord1=(.4, .2), coord2=(.5, .2), + right_normalized_pos=(0.9, 0.5), + size=(100, 0), opacity=1., selectable=False, border=True) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 1630ae959a..108673e7e5 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -122,8 +122,10 @@ def place(self, renderer): return button -def text(iren, callback, message="Accelerating computational anatomy...", - coord1=(.2, .2), coord2=(.7, .2), +def text(iren, ren, callback, message="Accelerating computational anatomy...", + # coord1=(.2, .2), coord2=(.7, .2), + right_normalized_pos=(0.9, 0.5), + size=(50, 0), color=(.9, .9, .9), opacity=1., selectable=True, @@ -137,10 +139,19 @@ def text(iren, callback, message="Accelerating computational anatomy...", # Create the text representation. Used for positioning the text_actor text_representation = vtk.vtkTextRepresentation() - text_representation.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() - text_representation.GetPositionCoordinate().SetValue(*coord1) + text_representation.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() - text_representation.GetPosition2Coordinate().SetValue(*coord2) + text_representation.GetPosition2Coordinate().SetValue(*right_normalized_pos) + + coord2_display = text_representation.GetPosition2Coordinate().GetComputedDisplayValue(ren) + text_representation.GetPositionCoordinate().SetCoordinateSystemToDisplay() + text_representation.GetPositionCoordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) + + # text_representation.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() + # text_representation.GetPositionCoordinate().SetValue(*coord1) + # text_representation.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() + # text_representation.GetPosition2Coordinate().SetValue(*coord2) + if border: text_representation.SetShowBorderToOn() else: @@ -155,7 +166,21 @@ def text(iren, callback, message="Accelerating computational anatomy...", # the user to "move" the widget, and no selection is possible. Otherwise # the SelectRegion() method is invoked. - text_widget = vtk.vtkTextWidget() + class TextWidget(vtk.vtkTextWidget): + + def place(self, renderer): + + slider_rep = self.GetRepresentation() + slider_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() + slider_rep.GetPosition2Coordinate().SetValue(*right_normalized_pos) + + coord2_display = slider_rep.GetPosition2Coordinate().GetComputedDisplayValue(renderer) + slider_rep.GetPositionCoordinate().SetCoordinateSystemToDisplay() + slider_rep.GetPositionCoordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) + slider_rep.SetPlaceFactor(1) + self.On() + + text_widget = TextWidget() text_widget.SetRepresentation(text_representation) text_widget.SetInteractor(iren) text_widget.SetTextActor(text_actor) From 5d54bff58a3cafdee1d83ecab363d2ac0cb55225 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 11 May 2015 13:26:01 -0400 Subject: [PATCH 064/242] More updates on text widget --- dipy/viz/tests/test_fvtk_widgets.py | 50 +++++++++++----------- dipy/viz/widget.py | 64 ++++++++++++++--------------- 2 files changed, 56 insertions(+), 58 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 4e95786535..72ee7b6329 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -2,6 +2,7 @@ from dipy.viz import actor, window, widget from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt +from Tkinter import * @npt.dec.skipif(not actor.have_vtk) @@ -123,52 +124,51 @@ def test_text_widget(): window.add(renderer, stream_actor) - # renderer.ResetCamera() + renderer.ResetCamera() show_manager = window.ShowManager(renderer) - - def button_callback(obj, event): - print('Button Pressed') - show_manager.initialize() + show_manager.render() fetch_viz_icons() button_png = read_viz_icons(fname='home3.png') + def button_callback(obj, event): + print('Button Pressed') + button = widget.button(show_manager.iren, button_callback, button_png, (.8, 1.2), (40, 40)) + def text_callback(obj, event): + + print('Text selected') + obj.GetTextActor().SetInput("DIPY!") + show_manager.render() + + text = widget.text(show_manager.iren, + show_manager.ren, + text_callback, + message="Expected", + left_down_pos=(0.15, 0.15), # (.2, 0.5), + right_top_pos=(0.7, 0.2), # (.7, 0.6), + opacity=.5, + border=True) + button.place(renderer) + text.place(renderer) + + show_manager.render() def win_callback(obj, event): print('Window modified') button.place(renderer) + text.place(renderer) show_manager.add_window_callback(win_callback) - show_manager.render() - - def text_callback(obj, event): - print(event) - print('Text moved') - print(obj) - print('Rep') - print(obj.GetRepresentation()) - - text = widget.text(show_manager.iren, - show_manager.ren, - text_callback, - message="Accelerating anatomy...", - right_normalized_pos=(0.9, 0.5), - size=(100, 0), - opacity=1., - selectable=False, border=True) - show_manager.render() show_manager.start() - # show(renderer) - arr = window.snapshot(renderer, size=(600, 600)) report = window.analyze_snapshot(arr) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 108673e7e5..6a13682d3b 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -122,40 +122,38 @@ def place(self, renderer): return button -def text(iren, ren, callback, message="Accelerating computational anatomy...", - # coord1=(.2, .2), coord2=(.7, .2), - right_normalized_pos=(0.9, 0.5), - size=(50, 0), - color=(.9, .9, .9), +def text(iren, ren, callback, message="DIPY", + left_down_pos=(0.8, 0.5), + right_top_pos=(0.9, 0.5), + color=(1., .5, .0), opacity=1., - selectable=True, - border=True): + font_size=10., + border=False): # Create the TextActor text_actor = vtk.vtkTextActor() text_actor.SetInput(message) text_actor.GetTextProperty().SetColor(color) text_actor.GetTextProperty().SetOpacity(opacity) + #text_actor.GetTextProperty().SetJustificationToLeft() + #text_actor.GetTextProperty().SetFontSize(int(font_size)) + #text_actor.GetTextProperty().SetFontFamilyToArial() # Create the text representation. Used for positioning the text_actor - text_representation = vtk.vtkTextRepresentation() + text_rep = vtk.vtkTextRepresentation() - text_representation.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() - text_representation.GetPosition2Coordinate().SetValue(*right_normalized_pos) + text_rep.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() + text_rep.GetPositionCoordinate().SetValue(*left_down_pos) - coord2_display = text_representation.GetPosition2Coordinate().GetComputedDisplayValue(ren) - text_representation.GetPositionCoordinate().SetCoordinateSystemToDisplay() - text_representation.GetPositionCoordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) + text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() + text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) - # text_representation.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() - # text_representation.GetPositionCoordinate().SetValue(*coord1) - # text_representation.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() - # text_representation.GetPosition2Coordinate().SetValue(*coord2) + text_rep.SetPlaceFactor(1) if border: - text_representation.SetShowBorderToOn() + text_rep.SetShowBorderToOn() else: - text_representation.SetShowBorderToOff() + text_rep.SetShowBorderToOff() # Create the TextWidget # Note that the SelectableOff method MUST be invoked! @@ -169,28 +167,28 @@ def text(iren, ren, callback, message="Accelerating computational anatomy...", class TextWidget(vtk.vtkTextWidget): def place(self, renderer): + text_rep = self.GetRepresentation() - slider_rep = self.GetRepresentation() - slider_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPosition2Coordinate().SetValue(*right_normalized_pos) + text_rep.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() + text_rep.GetPositionCoordinate().SetValue(*left_down_pos) - coord2_display = slider_rep.GetPosition2Coordinate().GetComputedDisplayValue(renderer) - slider_rep.GetPositionCoordinate().SetCoordinateSystemToDisplay() - slider_rep.GetPositionCoordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) - slider_rep.SetPlaceFactor(1) + text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() + text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) + text_rep.SetPlaceFactor(1) self.On() + text_widget = TextWidget() - text_widget.SetRepresentation(text_representation) + text_widget.SetRepresentation(text_rep) text_widget.SetInteractor(iren) text_widget.SetTextActor(text_actor) - if selectable: - text_widget.SelectableOn() - else: - text_widget.SelectableOff() - text_widget.On() + text_widget.SelectableOn() + + # text_widget.AddObserver(vtk.vtkCommand.InteractionEvent, callback) + text_widget.AddObserver(vtk.vtkCommand.WidgetActivateEvent, callback) + # text_widget.AddObserver(vtk.vtkCommand.KeyPressEvent, callback) - text_widget.AddObserver(vtk.vtkCommand.InteractionEvent, callback) + text_widget.On() # This is a hack for avoiding not plotting the text widget when # backface culling in On on a different actor From a1710c7eee9f67d671cf36e4fd3e2adeff1c8bc3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 11 May 2015 13:30:15 -0400 Subject: [PATCH 065/242] TEST:Minor text change --- dipy/viz/tests/test_fvtk_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 72ee7b6329..0f9477ce8a 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -148,7 +148,7 @@ def text_callback(obj, event): text = widget.text(show_manager.iren, show_manager.ren, text_callback, - message="Expected", + message="Diffusion Imaging in Python", left_down_pos=(0.15, 0.15), # (.2, 0.5), right_top_pos=(0.7, 0.2), # (.7, 0.6), opacity=.5, From 1ca2e48fb73bbb3188016052339cc1eeaaae756e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 11 May 2015 22:06:52 -0400 Subject: [PATCH 066/242] Finished playing with text widget, adding documentation tomorrow --- dipy/viz/tests/test_fvtk_widgets.py | 31 ++++++++++++++++++----------- dipy/viz/widget.py | 18 +++++++++++------ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 0f9477ce8a..acec5183cd 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -1,5 +1,5 @@ import numpy as np -from dipy.viz import actor, window, widget +from dipy.viz import actor, window, widget, fvtk from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt from Tkinter import * @@ -118,15 +118,13 @@ def test_text_widget(): renderer = window.renderer() - lines = [np.random.rand(10, 3), np.random.rand(20, 3)] - colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) - stream_actor = actor.line(lines, colors) + axes = fvtk.axes() - window.add(renderer, stream_actor) + window.add(renderer, axes) renderer.ResetCamera() - show_manager = window.ShowManager(renderer) + show_manager = window.ShowManager(renderer, size=(1200, 1200)) show_manager.initialize() show_manager.render() @@ -137,22 +135,31 @@ def button_callback(obj, event): print('Button Pressed') button = widget.button(show_manager.iren, button_callback, - button_png, (.8, 1.2), (40, 40)) + button_png, (.8, 1.2), (100, 100)) + + global rulez + rulez = True def text_callback(obj, event): + global rulez print('Text selected') - obj.GetTextActor().SetInput("DIPY!") + if rulez: + obj.GetTextActor().SetInput("Diffusion Imaging Rulez!!") + rulez = False + else: + obj.GetTextActor().SetInput("Diffusion Imaging in Python") + rulez = True show_manager.render() text = widget.text(show_manager.iren, show_manager.ren, text_callback, message="Diffusion Imaging in Python", - left_down_pos=(0.15, 0.15), # (.2, 0.5), - right_top_pos=(0.7, 0.2), # (.7, 0.6), - opacity=.5, - border=True) + left_down_pos=(0., 0.), # (.2, 0.5), + right_top_pos=(0.4, 0.05), # (.7, 0.6), + opacity=1., + border=False) button.place(renderer) text.place(renderer) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 6a13682d3b..445ec3fba9 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -141,6 +141,7 @@ def text(iren, ren, callback, message="DIPY", # Create the text representation. Used for positioning the text_actor text_rep = vtk.vtkTextRepresentation() + text_rep.SetPlaceFactor(1) text_rep.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() text_rep.GetPositionCoordinate().SetValue(*left_down_pos) @@ -148,17 +149,12 @@ def text(iren, ren, callback, message="DIPY", text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) - text_rep.SetPlaceFactor(1) if border: text_rep.SetShowBorderToOn() else: text_rep.SetShowBorderToOff() - # Create the TextWidget - # Note that the SelectableOff method MUST be invoked! - # According to the documentation : - # # SelectableOn/Off indicates whether the interior region of the widget can # be selected or not. If not, then events (such as left mouse down) allow # the user to "move" the widget, and no selection is possible. Otherwise @@ -167,6 +163,7 @@ def text(iren, ren, callback, message="DIPY", class TextWidget(vtk.vtkTextWidget): def place(self, renderer): + text_rep = self.GetRepresentation() text_rep.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() @@ -174,7 +171,12 @@ def place(self, renderer): text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) - text_rep.SetPlaceFactor(1) + + #text_rep.SetPlaceFactor(1) + self.SelectableOn() + self.ResizableOff() + text_rep.ProportionalResizeOn() + self.On() @@ -183,6 +185,10 @@ def place(self, renderer): text_widget.SetInteractor(iren) text_widget.SetTextActor(text_actor) text_widget.SelectableOn() + text_widget.ResizableOff() + text_widget.GetRepresentation().ProportionalResizeOn() + + #1/0 # text_widget.AddObserver(vtk.vtkCommand.InteractionEvent, callback) text_widget.AddObserver(vtk.vtkCommand.WidgetActivateEvent, callback) From a49f1c1c66d6217e6bd20754993502d4f6943080 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 12:32:39 -0400 Subject: [PATCH 067/242] DOC: read_viz_icons --- dipy/data/fetcher.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 257ed6bb65..d3baa03e27 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -593,6 +593,22 @@ def fetch_viz_icons(): def read_viz_icons(style='icomoon', fname='infinity.png'): + """ Read specific icon from specific style + + Parameters + ---------- + style: str + Current icon style. Default is icomoon. + fname: str + Filename of icon. This should be found in folder HOME/.dipy/style/. + Default is infinity.png. + + Returns + -------- + path: str + Complete path of icon. + + """ folder = pjoin(dipy_home, 'icons', style) return pjoin(folder, fname) From 33efd92f7eb62092c87598fb637472c439809fd5 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 12:33:10 -0400 Subject: [PATCH 068/242] TEST: finished test for text widget --- dipy/viz/tests/test_fvtk_widgets.py | 80 +++++++++-------------------- 1 file changed, 23 insertions(+), 57 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index acec5183cd..8fe77415c4 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -2,59 +2,24 @@ from dipy.viz import actor, window, widget, fvtk from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt -from Tkinter import * - - -@npt.dec.skipif(not actor.have_vtk) -@npt.dec.skipif(not actor.have_vtk_colors) -def test_slider_widget(): - - renderer = window.Renderer() - - # Create 2 lines with 2 different colors - lines = [np.random.rand(10, 3), np.random.rand(20, 3)] - colors = np.array([[1., 0., 0.], [0.8, 0., 0.]]) - c = actor.line(lines, colors, linewidth=3) - - renderer.add(c) - - show_manager = window.ShowManager(renderer, size=(400, 400)) - show_manager.initialize() - - def slider_callback(obj, event): - print(obj) - print(event) - renderer.SetBackground(np.random.rand(3)) - - slider = widget.slider(iren=show_manager.iren, - ren=show_manager.ren, - right_normalized_pos=(.98, 0.5), - size=(120, 0), - callback=slider_callback) - # text = widget.text(slider.iren, None) - - show_manager.render() - show_manager.start() - - arr = window.snapshot(renderer, size=(600, 600)) - report = window.analyze_snapshot(arr) @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_button_and_slider_widgets(): - from dipy.viz.window import vtk - renderer = window.Renderer() + # create some random streamlines lines = [np.random.rand(10, 3), np.random.rand(20, 3)] colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) stream_actor = actor.streamtube(lines, colors) renderer.add(stream_actor) - show_manager= window.ShowManager(renderer, size=(800, 800)) + # the show manager allows to break the rendering process + # in steps so that the widgets can be added properly + show_manager = window.ShowManager(renderer, size=(800, 800)) def callback(obj, event): print(obj) @@ -116,7 +81,9 @@ def win_callback(obj, event): @npt.dec.skipif(not actor.have_vtk_colors) def test_text_widget(): - renderer = window.renderer() + interactive = False + + renderer = window.Renderer() axes = fvtk.axes() @@ -125,8 +92,10 @@ def test_text_widget(): renderer.ResetCamera() show_manager = window.ShowManager(renderer, size=(1200, 1200)) - show_manager.initialize() - show_manager.render() + + if interactive: + show_manager.initialize() + show_manager.render() fetch_viz_icons() button_png = read_viz_icons(fname='home3.png') @@ -156,37 +125,34 @@ def text_callback(obj, event): show_manager.ren, text_callback, message="Diffusion Imaging in Python", - left_down_pos=(0., 0.), # (.2, 0.5), - right_top_pos=(0.4, 0.05), # (.7, 0.6), + left_down_pos=(0., 0.), + right_top_pos=(0.4, 0.05), opacity=1., border=False) button.place(renderer) text.place(renderer) - show_manager.render() + if interactive: + show_manager.render() def win_callback(obj, event): print('Window modified') button.place(renderer) text.place(renderer) - show_manager.add_window_callback(win_callback) - - show_manager.render() - show_manager.start() - - arr = window.snapshot(renderer, size=(600, 600)) + if interactive: + show_manager.add_window_callback(win_callback) + show_manager.render() + show_manager.start() + arr = window.snapshot(renderer, size=(1200, 1200)) report = window.analyze_snapshot(arr) + npt.assert_equal(report.objects, 30) - print(report.objects) + # imshow(report.labels, origin='lower') if __name__ == '__main__': - # test_slider_widget() - # test_button_and_slider_widgets() - test_text_widget() - # test_button_widget_show() - # npt.run_module_suite() \ No newline at end of file + npt.run_module_suite() \ No newline at end of file From 78eafdb027cec1220c70269b661284b99d24baa8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 13:22:41 -0400 Subject: [PATCH 069/242] TEST: added a more interesting callback to the slider --- dipy/viz/tests/test_fvtk_widgets.py | 72 +++++++++++++++++------------ 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 8fe77415c4..26b1b8218c 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -11,7 +11,7 @@ def test_button_and_slider_widgets(): renderer = window.Renderer() # create some random streamlines - lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + lines = [np.random.rand(2, 3), np.random.rand(3, 3)] colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) stream_actor = actor.streamtube(lines, colors) @@ -21,57 +21,71 @@ def test_button_and_slider_widgets(): # in steps so that the widgets can be added properly show_manager = window.ShowManager(renderer, size=(800, 800)) - def callback(obj, event): - print(obj) - print('Pressed') + show_manager.initialize() + show_manager.render() + + def button_callback(obj, event): + print('Camera pressed') + + def button_plus_callback(obj, event): + print('+ pressed') + + def button_minus_callback(obj, event): + print('- pressed') fetch_viz_icons() button_png = read_viz_icons(fname='camera.png') - button = widget.button(show_manager.iren, callback, + button = widget.button(show_manager.iren, button_callback, button_png, (.98, 1.), (80, 50)) button_png_plus = read_viz_icons(fname='plus.png') - button_plus = widget.button(show_manager.iren, callback, + button_plus = widget.button(show_manager.iren, button_plus_callback, button_png_plus, (.98, .9), (120, 50)) button_png_minus = read_viz_icons(fname='minus.png') - button_minus = widget.button(show_manager.iren, callback, + button_minus = widget.button(show_manager.iren, button_minus_callback, button_png_minus, (.98, .9), (50, 50)) def print_status(obj, event): - # print(obj) - # print(event) - renderer.SetBackground(np.random.rand(3)) + print(obj) + rep = obj.GetRepresentation() + stream_actor.SetPosition((rep.GetValue(), 0, 0)) slider = widget.slider(show_manager.iren, show_manager.ren, callback=print_status, + min_value=-1, + max_value=1, + value=0.5, right_normalized_pos=(.98, 0.7), - size=(120, 0)) - - show_manager.initialize() - show_manager.render() + size=(120, 0), label_format="%0.2lf") button.place(renderer) button_plus.place(renderer) button_minus.place(renderer) slider.place(renderer) + # This callback is used to update the buttons/sliders' position + # so they can stay on the right side of the window when the window + # is being resized. + + global size + size = renderer.GetSize() + def win_callback(obj, event): - # print(obj) - print(event) - print(obj.GetSize()) + global size + if size != obj.GetSize(): - button.place(renderer) - button_plus.place(renderer) - button_minus.place(renderer) - slider.place(renderer) + button.place(renderer) + button_plus.place(renderer) + button_minus.place(renderer) + slider.place(renderer) + + size = obj.GetSize() # ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) show_manager.add_window_callback(win_callback) - - # show_manager.render() - + show_manager.render() show_manager.start() arr = window.snapshot(renderer, size=(800, 800)) @@ -84,11 +98,8 @@ def test_text_widget(): interactive = False renderer = window.Renderer() - axes = fvtk.axes() - window.add(renderer, axes) - renderer.ResetCamera() show_manager = window.ShowManager(renderer, size=(1200, 1200)) @@ -150,9 +161,10 @@ def win_callback(obj, event): report = window.analyze_snapshot(arr) npt.assert_equal(report.objects, 30) - # imshow(report.labels, origin='lower') + # To see the segmented objects after the analysis is done + # you can use imshow(report.labels, origin='lower') if __name__ == '__main__': - - npt.run_module_suite() \ No newline at end of file + test_button_and_slider_widgets() + # npt.run_module_suite() \ No newline at end of file From 1f38858ddf7ac524f5430bdc237aa7658d664a24 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 17:00:17 -0400 Subject: [PATCH 070/242] TEST: completed test for combination of buttons and sliders --- dipy/viz/tests/test_fvtk_widgets.py | 44 ++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 26b1b8218c..625b73b0c4 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -8,10 +8,12 @@ @npt.dec.skipif(not actor.have_vtk_colors) def test_button_and_slider_widgets(): + interactive = False renderer = window.Renderer() - # create some random streamlines - lines = [np.random.rand(2, 3), np.random.rand(3, 3)] + # create some minimalistic streamlines + lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), + np.array([[-1, 1, 0.], [1, 1, 0.]])] colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) stream_actor = actor.streamtube(lines, colors) @@ -21,8 +23,9 @@ def test_button_and_slider_widgets(): # in steps so that the widgets can be added properly show_manager = window.ShowManager(renderer, size=(800, 800)) - show_manager.initialize() - show_manager.render() + if interactive: + show_manager.initialize() + show_manager.render() def button_callback(obj, event): print('Camera pressed') @@ -48,7 +51,6 @@ def button_minus_callback(obj, event): button_png_minus, (.98, .9), (50, 50)) def print_status(obj, event): - print(obj) rep = obj.GetRepresentation() stream_actor.SetPosition((rep.GetValue(), 0, 0)) @@ -57,6 +59,7 @@ def print_status(obj, event): min_value=-1, max_value=1, value=0.5, + label="X", right_normalized_pos=(.98, 0.7), size=(120, 0), label_format="%0.2lf") @@ -80,15 +83,28 @@ def win_callback(obj, event): button_plus.place(renderer) button_minus.place(renderer) slider.place(renderer) - size = obj.GetSize() - # ren_win.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) - show_manager.add_window_callback(win_callback) - show_manager.render() - show_manager.start() + if interactive: + show_manager.add_window_callback(win_callback) + # you can also register any callback in a vtk way like this + # show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, + # win_callback) - arr = window.snapshot(renderer, size=(800, 800)) + show_manager.render() + show_manager.start() + + if not interactive: + button.Off() + slider.Off() + + arr = window.snapshot(renderer, size=(800, 800)) + report = window.analyze_snapshot(arr) + npt.assert_equal(report.objects, 4) + # imshow(report.labels, origin='lower') + + report = window.analyze_renderer(renderer) + npt.assert_equal(report.actors, 1) @npt.dec.skipif(not actor.have_vtk) @@ -161,10 +177,10 @@ def win_callback(obj, event): report = window.analyze_snapshot(arr) npt.assert_equal(report.objects, 30) - # To see the segmented objects after the analysis is done + # If you want to see the segmented objects after the analysis is finished # you can use imshow(report.labels, origin='lower') if __name__ == '__main__': - test_button_and_slider_widgets() - # npt.run_module_suite() \ No newline at end of file + + npt.run_module_suite() \ No newline at end of file From 48ee5f963425730c5d0086c745da1b1089e7c8a6 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 17:31:44 -0400 Subject: [PATCH 071/242] DOC: docstring added for slider --- dipy/viz/widget.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 445ec3fba9..42dcbd654f 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -1,4 +1,5 @@ - +# Widgets are different than actors in that they can interact with events +# To do so they need as input a vtkRenderWindowInteractor also known as iren. # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -14,7 +15,37 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, right_normalized_pos=(0.9, 0.5), size=(50, 0), label_format="%0.0lf"): - """ Create a 2D slider with normalized window coordinates + """ A 2D slider + + Parameters + ---------- + iren : vtkRenderWindowInteractor + Can also be given by the ``ShowManager``as ``iren``. Used to process + events and handle them to the slider. + ren : vtkRenderer or Renderer + Used to update the slider's position when the window changes. + callback : function + Function that has at least ``obj`` and ``event`` as parameters and + can be called when a specific event is being triggered. + min_value : float + Minimum value of slider. + max_value : float + Maximum value of slider. + value : + Default value of slider. + label : str + Slider's caption. + right_normalized_pos : tuple + 2d tuple holding the normalized right (X, Y) position of the slider. + size: tuple + 2d tuple holding the size of the slider in pixels. + label_format: str + Formating in which the slider's value will appear for example "%0.2lf" + allows for 2 decimal values. + + Returns + ------- + """ slider_rep = vtk.vtkSliderRepresentation2D() From 56fe445598b2dfa79002f94e8ece2098336dcdaa Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 18:03:56 -0400 Subject: [PATCH 072/242] RF: pep 8 in slider --- dipy/viz/widget.py | 61 ++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 42dcbd654f..e379d66d3f 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -20,10 +20,11 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, Parameters ---------- iren : vtkRenderWindowInteractor - Can also be given by the ``ShowManager``as ``iren``. Used to process - events and handle them to the slider. + Used to process events and handle them to the slider. Can also be given + by the ``ShowManager``as ``iren``. ren : vtkRenderer or Renderer - Used to update the slider's position when the window changes. + Used to update the slider's position when the window changes. Can also be given + by the ``ShowManager``as ``ren``. callback : function Function that has at least ``obj`` and ``event`` as parameters and can be called when a specific event is being triggered. @@ -45,10 +46,12 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, Returns ------- - + slider : obj + This object has a method called ``place`` which allows to update the + position of the slider if necessary. """ - slider_rep = vtk.vtkSliderRepresentation2D() + slider_rep = vtk.vtkSliderRepresentation2D() slider_rep.SetMinimumValue(min_value) slider_rep.SetMaximumValue(max_value) slider_rep.SetValue(value) @@ -57,22 +60,22 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() slider_rep.GetPoint2Coordinate().SetValue(*right_normalized_pos) - coord2_display = slider_rep.GetPoint2Coordinate().GetComputedDisplayValue(ren) + coord2 = slider_rep.GetPoint2Coordinate().GetComputedDisplayValue(ren) slider_rep.GetPoint1Coordinate().SetCoordinateSystemToDisplay() - slider_rep.GetPoint1Coordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) + slider_rep.GetPoint1Coordinate().SetValue(coord2[0] - size[0], + coord2[1] - size[1]) - length=0.04 - width=0.04 - cap_length=0.01 - cap_width=0.01 - tube_width=0.005 + length = 0.04 + width = 0.04 + cap_length = 0.01 + cap_width = 0.01 + tube_width = 0.005 slider_rep.SetSliderLength(length) slider_rep.SetSliderWidth(width) slider_rep.SetEndCapLength(cap_length) slider_rep.SetEndCapWidth(cap_width) slider_rep.SetTubeWidth(tube_width) - slider_rep.SetLabelFormat(label_format) class SliderWidget(vtk.vtkSliderWidget): @@ -80,15 +83,14 @@ class SliderWidget(vtk.vtkSliderWidget): def place(self, renderer): slider_rep = self.GetRepresentation() - slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() - slider_rep.GetPoint2Coordinate().SetValue(*right_normalized_pos) + coord2_norm = slider_rep.GetPoint2Coordinate() + coord2_norm.SetCoordinateSystemToNormalizedDisplay() + coord2_norm.SetValue(*right_normalized_pos) - coord2_display = slider_rep.GetPoint2Coordinate().GetComputedDisplayValue(renderer) + coord2 = coord2_norm.GetComputedDisplayValue(renderer) slider_rep.GetPoint1Coordinate().SetCoordinateSystemToDisplay() - slider_rep.GetPoint1Coordinate().SetValue(coord2_display[0] - size[0], coord2_display[1] - size[1]) - - # slider_rep.SetLabelFormat(label_format) - + slider_rep.GetPoint1Coordinate().SetValue(coord2[0] - size[0], + coord2[1] - size[1]) slider = SliderWidget() slider.SetInteractor(iren) @@ -104,17 +106,14 @@ def place(self, renderer): def button_display_coordinates(renderer, normalized_display_position, size): upperRight = vtk.vtkCoordinate() upperRight.SetCoordinateSystemToNormalizedDisplay() - upperRight.SetValue(normalized_display_position[0], normalized_display_position[1]) + upperRight.SetValue(normalized_display_position[0], + normalized_display_position[1]) bds = [0.0] * 6 - #1/0 bds[0] = upperRight.GetComputedDisplayValue(renderer)[0] - size[0] - print(upperRight.GetComputedDisplayValue(renderer)[0], - upperRight.GetComputedDisplayValue(renderer)[1]) - print(renderer.GetSize()) bds[1] = bds[0] + size[0] bds[2] = upperRight.GetComputedDisplayValue(renderer)[1] - size[1] bds[3] = bds[2] + size[1] - # print(bds) + return bds @@ -124,20 +123,17 @@ def button(iren, callback, fname, button_norm_coords, button_size): image1.SetFileName(fname) image1.Update() - #button_rep = vtk.vtkProp3DButtonRepresentation() button_rep = vtk.vtkTexturedButtonRepresentation2D() button_rep.SetNumberOfStates(2) button_rep.SetButtonTexture(0, image1.GetOutput()) button_rep.SetButtonTexture(1, image1.GetOutput()) - #button_rep.SetButtonTexture(1, image2.GetOutput()) - - # http://www.vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget class ButtonWidget(vtk.vtkButtonWidget): def place(self, renderer): - bds = button_display_coordinates(renderer, button_norm_coords, button_size) + bds = button_display_coordinates(renderer, button_norm_coords, + button_size) self.GetRepresentation().SetPlaceFactor(1) self.GetRepresentation().PlaceWidget(bds) self.On() @@ -147,9 +143,6 @@ def place(self, renderer): button.SetRepresentation(button_rep) button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) - #http://vtk.org/gitweb?p=VTK.git;a=blob;f=Interaction/Widgets/Testing/Cxx/TestButtonWidget.cxx - #http://vtk.org/Wiki/VTK/Examples/Cxx/Widgets/TexturedButtonWidget - return button From 3ab6c6e082c8537fa1df1ddb93144c35cae90c25 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 18:54:32 -0400 Subject: [PATCH 073/242] RF: in button widget --- dipy/viz/tests/test_fvtk_widgets.py | 27 ++++++++++++++------------ dipy/viz/widget.py | 30 ++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 625b73b0c4..a42fe03eda 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -8,7 +8,7 @@ @npt.dec.skipif(not actor.have_vtk_colors) def test_button_and_slider_widgets(): - interactive = False + interactive = True renderer = window.Renderer() # create some minimalistic streamlines @@ -39,15 +39,21 @@ def button_minus_callback(obj, event): fetch_viz_icons() button_png = read_viz_icons(fname='camera.png') - button = widget.button(show_manager.iren, button_callback, + button = widget.button(show_manager.iren, + show_manager.ren, + button_callback, button_png, (.98, 1.), (80, 50)) button_png_plus = read_viz_icons(fname='plus.png') - button_plus = widget.button(show_manager.iren, button_plus_callback, + button_plus = widget.button(show_manager.iren, + show_manager.ren, + button_plus_callback, button_png_plus, (.98, .9), (120, 50)) button_png_minus = read_viz_icons(fname='minus.png') - button_minus = widget.button(show_manager.iren, button_minus_callback, + button_minus = widget.button(show_manager.iren, + show_manager.ren, + button_minus_callback, button_png_minus, (.98, .9), (50, 50)) def print_status(obj, event): @@ -58,16 +64,11 @@ def print_status(obj, event): callback=print_status, min_value=-1, max_value=1, - value=0.5, + value=0., label="X", - right_normalized_pos=(.98, 0.7), + right_normalized_pos=(.98, 0.6), size=(120, 0), label_format="%0.2lf") - button.place(renderer) - button_plus.place(renderer) - button_minus.place(renderer) - slider.place(renderer) - # This callback is used to update the buttons/sliders' position # so they can stay on the right side of the window when the window # is being resized. @@ -130,7 +131,9 @@ def test_text_widget(): def button_callback(obj, event): print('Button Pressed') - button = widget.button(show_manager.iren, button_callback, + button = widget.button(show_manager.iren, + show_manager.ren, + button_callback, button_png, (.8, 1.2), (100, 100)) global rulez diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index e379d66d3f..8cf004c59a 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -15,13 +15,13 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, right_normalized_pos=(0.9, 0.5), size=(50, 0), label_format="%0.0lf"): - """ A 2D slider + """ A 2D slider widget Parameters ---------- iren : vtkRenderWindowInteractor Used to process events and handle them to the slider. Can also be given - by the ``ShowManager``as ``iren``. + by the attribute ``ShowManager.iren``. ren : vtkRenderer or Renderer Used to update the slider's position when the window changes. Can also be given by the ``ShowManager``as ``ren``. @@ -117,7 +117,26 @@ def button_display_coordinates(renderer, normalized_display_position, size): return bds -def button(iren, callback, fname, button_norm_coords, button_size): +def button(iren, ren, callback, fname, right_normalized_pos=(.98, .9), + size=(50, 50)): + """ A textured button widget + + Parameters + ---------- + iren : vtkRenderWindowInteractor + Used to process events and handle them to the button. Can also be given + by the attribute ``ShowManager.iren``. + ren : + callback : + fname : + right_normalized_pos : + size : + + Returns + ------- + + + """ image1 = vtk.vtkPNGReader() image1.SetFileName(fname) @@ -132,8 +151,8 @@ class ButtonWidget(vtk.vtkButtonWidget): def place(self, renderer): - bds = button_display_coordinates(renderer, button_norm_coords, - button_size) + bds = button_display_coordinates(renderer, right_normalized_pos, + size) self.GetRepresentation().SetPlaceFactor(1) self.GetRepresentation().PlaceWidget(bds) self.On() @@ -142,6 +161,7 @@ def place(self, renderer): button.SetInteractor(iren) button.SetRepresentation(button_rep) button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) + button.place(ren) return button From e41e840466185a027dad621a72f1413c689c6883 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 19:02:56 -0400 Subject: [PATCH 074/242] DOC: for button widget is ready --- dipy/viz/widget.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 8cf004c59a..e0e21517c8 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -24,10 +24,10 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, by the attribute ``ShowManager.iren``. ren : vtkRenderer or Renderer Used to update the slider's position when the window changes. Can also be given - by the ``ShowManager``as ``ren``. + by the ``ShowManager.ren`` attribute. callback : function - Function that has at least ``obj`` and ``event`` as parameters and - can be called when a specific event is being triggered. + Function that has at least ``obj`` and ``event`` as parameters. It will + be called when the slider's bar has changed. min_value : float Minimum value of slider. max_value : float @@ -119,23 +119,38 @@ def button_display_coordinates(renderer, normalized_display_position, size): def button(iren, ren, callback, fname, right_normalized_pos=(.98, .9), size=(50, 50)): - """ A textured button widget + """ A textured two state button widget Parameters ---------- iren : vtkRenderWindowInteractor Used to process events and handle them to the button. Can also be given by the attribute ``ShowManager.iren``. - ren : - callback : - fname : - right_normalized_pos : - size : + ren : vtkRenderer or Renderer + Used to update the slider's position when the window changes. Can also be given + by the ``ShowManager.ren`` attribute. + callback : function + Function that has at least ``obj`` and ``event`` as parameters. It will + be called when the button is pressed. + fname : str + PNG file path of the icon used for the button. + right_normalized_pos : tuple + 2d tuple holding the normalized right (X, Y) position of the slider. + size: tuple + 2d tuple holding the size of the slider in pixels. Returns ------- + button : obj + This object has a method called ``place`` which allows to update the + position of the slider if necessary. - + Notes + ------ + The button and slider widgets have similar positioning system. This enables + the developers to create a HUD-like collections of buttons and sliders on + the right side of the window that always stays in place when the dimensions + of the window change. """ image1 = vtk.vtkPNGReader() From df09a1b5928b325c3b1a5cd83e00324e2c9342c5 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 20:00:13 -0400 Subject: [PATCH 075/242] DOC: updated docstring for text widget --- dipy/viz/widget.py | 71 ++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index e0e21517c8..a19e80b7ff 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -4,12 +4,12 @@ # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package -#import vtk # Allow import, but disable doctests if we don't have vtk vtk, have_vtk, setup_module = optional_package('vtk') colors, have_vtk_colors, _ = optional_package('vtk.util.colors') numpy_support, have_ns, _ = optional_package('vtk.util.numpy_support') + def slider(iren, ren, callback, min_value=0, max_value=255, value=125, label="Slider", right_normalized_pos=(0.9, 0.5), @@ -46,9 +46,10 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, Returns ------- - slider : obj - This object has a method called ``place`` which allows to update the - position of the slider if necessary. + slider : SliderObject + This object inherits from vtkSliderWidget and has additional method + called ``place`` which allows to update the position of the slider + when for example the window is resized. """ slider_rep = vtk.vtkSliderRepresentation2D() @@ -141,9 +142,10 @@ def button(iren, ren, callback, fname, right_normalized_pos=(.98, .9), Returns ------- - button : obj - This object has a method called ``place`` which allows to update the - position of the slider if necessary. + button : ButtonWidget + This object inherits from vtkButtonWidget and has an additional method + called ``place`` which allows to update the position of the slider + if necessary. For example when the renderer size changes. Notes ------ @@ -182,21 +184,50 @@ def place(self, renderer): def text(iren, ren, callback, message="DIPY", - left_down_pos=(0.8, 0.5), - right_top_pos=(0.9, 0.5), - color=(1., .5, .0), - opacity=1., - font_size=10., - border=False): + left_down_pos=(0.8, 0.5), right_top_pos=(0.9, 0.5), + color=(1., .5, .0), opacity=1., border=False): + """ 2D text that can be clicked and process events + + Parameters + ---------- + iren : vtkRenderWindowInteractor + Used to process events and handle them to the button. Can also be given + by the attribute ``ShowManager.iren``. + ren : vtkRenderer or Renderer + Used to update the slider's position when the window changes. Can also be given + by the ``ShowManager.ren`` attribute. + callback : function + Function that has at least ``obj`` and ``event`` as parameters. It will + be called when the button is pressed. + message : str + Message to be shown in the text widget + left_down_pos : tuple + Normalized coordinates for left down corner of text. Default is + (0.8, 0.5). + right_top_pos : tuple + Normalized coordinates for left down corner of text. Default is + (0.9, 0.5). + color : tuple + Foreground RGB color of text. Default is (1., .5, .0). + opacity : float + Takes values from 0 to 1. Default is 1. + border : bool + Show text border. Default is False. + + Returns + ------- + text : TextWidget + This object inherits from ``vtkTextWidget`` has an additional method + called ``place`` which allows to update the position of the text if + necessary. + + """ # Create the TextActor text_actor = vtk.vtkTextActor() text_actor.SetInput(message) text_actor.GetTextProperty().SetColor(color) text_actor.GetTextProperty().SetOpacity(opacity) - #text_actor.GetTextProperty().SetJustificationToLeft() - #text_actor.GetTextProperty().SetFontSize(int(font_size)) - #text_actor.GetTextProperty().SetFontFamilyToArial() # Create the text representation. Used for positioning the text_actor text_rep = vtk.vtkTextRepresentation() @@ -208,17 +239,11 @@ def text(iren, ren, callback, message="DIPY", text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) - if border: text_rep.SetShowBorderToOn() else: text_rep.SetShowBorderToOff() - # SelectableOn/Off indicates whether the interior region of the widget can - # be selected or not. If not, then events (such as left mouse down) allow - # the user to "move" the widget, and no selection is possible. Otherwise - # the SelectRegion() method is invoked. - class TextWidget(vtk.vtkTextWidget): def place(self, renderer): @@ -231,14 +256,12 @@ def place(self, renderer): text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) - #text_rep.SetPlaceFactor(1) self.SelectableOn() self.ResizableOff() text_rep.ProportionalResizeOn() self.On() - text_widget = TextWidget() text_widget.SetRepresentation(text_rep) text_widget.SetInteractor(iren) From 4fefdd726926331b61c98c557a4964df14e9b18c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 20:04:42 -0400 Subject: [PATCH 076/242] RF: refactor text widget for pep8 --- dipy/viz/tests/test_fvtk_widgets.py | 2 +- dipy/viz/widget.py | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index a42fe03eda..9cf0b72df1 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -8,7 +8,7 @@ @npt.dec.skipif(not actor.have_vtk_colors) def test_button_and_slider_widgets(): - interactive = True + interactive = False renderer = window.Renderer() # create some minimalistic streamlines diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index a19e80b7ff..3d639a30fe 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -194,8 +194,8 @@ def text(iren, ren, callback, message="DIPY", Used to process events and handle them to the button. Can also be given by the attribute ``ShowManager.iren``. ren : vtkRenderer or Renderer - Used to update the slider's position when the window changes. Can also be given - by the ``ShowManager.ren`` attribute. + Used to update the slider's position when the window changes. Can also + be given by the ``ShowManager.ren`` attribute. callback : function Function that has at least ``obj`` and ``event`` as parameters. It will be called when the button is pressed. @@ -220,7 +220,6 @@ def text(iren, ren, callback, message="DIPY", This object inherits from ``vtkTextWidget`` has an additional method called ``place`` which allows to update the position of the text if necessary. - """ # Create the TextActor @@ -250,11 +249,13 @@ def place(self, renderer): text_rep = self.GetRepresentation() - text_rep.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() - text_rep.GetPositionCoordinate().SetValue(*left_down_pos) + position = text_rep.GetPositionCoordinate() + position.SetCoordinateSystemToNormalizedDisplay() + position.SetValue(*left_down_pos) - text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() - text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) + position2 = text_rep.GetPosition2Coordinate() + position2.SetCoordinateSystemToNormalizedDisplay() + position2.SetValue(*right_top_pos) self.SelectableOn() self.ResizableOff() @@ -270,12 +271,7 @@ def place(self, renderer): text_widget.ResizableOff() text_widget.GetRepresentation().ProportionalResizeOn() - #1/0 - - # text_widget.AddObserver(vtk.vtkCommand.InteractionEvent, callback) text_widget.AddObserver(vtk.vtkCommand.WidgetActivateEvent, callback) - # text_widget.AddObserver(vtk.vtkCommand.KeyPressEvent, callback) - text_widget.On() # This is a hack for avoiding not plotting the text widget when From 8254dbe8699acf887420c58ffc02859b6ed9f160 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 12 May 2015 20:21:28 -0400 Subject: [PATCH 077/242] Going back to the tutorial --- doc/examples/introduction_to_visualization.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index 411cbe36f5..b432d959a5 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -1,7 +1,7 @@ """ -========================================= -Introduction to interactive visualization -========================================= +==================================================== +Introduction to interactive visualization (Advanced) +==================================================== In DIPY we created a thin interface to access many of the capabilities available in the Visualization Toolkit framework (VTK) but tailored to the @@ -17,7 +17,7 @@ The main objects/functions which are used for drawing actors (e.g. slices, streamlines) in a window or in a file are available in window. And the actors are available in actor. There are also some objects which allow to add buttons -and slider and these interact both with windows and actors and those are in +and sliders and these interact both with windows and actors and those are in widjets. """ From c1f6725a7be0773a637af9f2234ebf7d4d0c69ce Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 16 May 2015 16:33:55 -0400 Subject: [PATCH 078/242] DOC: updating new viz tutorial --- doc/examples/introduction_to_visualization.py | 129 ++++++++++++++++-- 1 file changed, 119 insertions(+), 10 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index b432d959a5..05f9a9db48 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -1,27 +1,136 @@ """ -==================================================== -Introduction to interactive visualization (Advanced) -==================================================== +=============================================== +Advanced interactive visualization capabilities +=============================================== In DIPY we created a thin interface to access many of the capabilities available in the Visualization Toolkit framework (VTK) but tailored to the needs of structural and diffusion imaging. Initially the 3D visualization module was named ``fvtk``, meaning functions using vtk. This is still available for backwards compatibility but now there is a more comprehensive way to access -the main functions using the following import. +the main functions using the following modules. """ -from dipy.viz import window, actor, widgets +from dipy.viz import actor, window, widget """ -The main objects/functions which are used for drawing actors (e.g. slices, -streamlines) in a window or in a file are available in window. And the actors -are available in actor. There are also some objects which allow to add buttons -and sliders and these interact both with windows and actors and those are in -widjets. +In ``window`` we have all the objects that connect what needs to be rendered +to the display or the disk e.g. for saving screenshots. So, there you will find +key objects and functions like the ``Renderer`` class which holds and provides +access to all the actors and the ``show`` function which displays what is +in the renderer on a window. Also, this module provides access to functions +for opening/saving dialogs and printing screenshots (see ``snapshot``). + +In the ``actor`` module we can find all the different primitives e.g. +streamtubes, lines, image slices etc. + +In the ``widget`` we have some other objects which allow to add buttons +and sliders and these interact both with windows and actors. Because of this +they need input from the operating system so they can process events. + +So, let's get started. In this tutorial we will create a + """ +import numpy as np + +# Change with Stanford data +#dname = '/home/eleftherios/Data/Cunnane_Elef/08-111-609-AC15/work/' +dname = '/home/eleftherios/Data/fancy_data/2013_02_08_Gabriel_Girard/' + +import nibabel as nib +from nibabel import trackvis as tv + +world_coords = False +streamline_opacity = 1. +slicer_opacity = 1. +depth_peeling = False + + +img = nib.load(dname + 't1_warped.nii.gz') +data = img.get_data() +affine = img.get_affine() + + +img_fa = nib.load(dname + 'fa_1x1x1.nii.gz') +fa = img_fa.get_data() +affine_fa = img_fa.get_affine() + + +streams, hdr = tv.read(dname + 'TRK_files/bundles_cst.right.trk', + points_space="rasmm") +streamlines = [s[0] for s in streams] + +streams, hdr = tv.read(dname + 'TRK_files/bundles_af.left.trk', + points_space="rasmm") +streamlines += [s[0] for s in streams] + +streams, hdr = tv.read(dname + 'TRK_files/bundles_cc_1.trk', + points_space="rasmm") +streamlines += [s[0] for s in streams] + +if not world_coords: + from dipy.tracking.streamline import transform_streamlines + streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) + +ren = window.Renderer() + +stream_actor = actor.streamtube(streamlines, fa) + +if not world_coords: + slicer = actor.slice(data, affine=np.eye(4)) +else: + slicer = actor.slice(data, affine) + +slicer.GetProperty().SetOpacity(slicer_opacity) +stream_actor.GetProperty().SetOpacity(streamline_opacity) + +ren.add(stream_actor) +ren.add(slicer) + +def change_slice(obj, event): + global slicer + z = int(np.round(obj.GetSliderRepresentation().GetValue())) + + print(obj) + print(event) + print(z) + slicer.SetDisplayExtent(0, 255, 0, 255, z, z) + slicer.Update() + +import vtk + +ren_win = vtk.vtkRenderWindow() +ren_win.AddRenderer(renderer) + +if depth_peeling: + # http://www.vtk.org/Wiki/VTK/Depth_Peeling + ren_win.SetAlphaBitPlanes(1) + ren_win.SetMultiSamples(0) + renderer.SetUseDepthPeeling(1) + renderer.SetMaximumNumberOfPeels(10) + renderer.SetOcclusionRatio(0.1) + + +iren = vtk.vtkRenderWindowInteractor() +iren.SetRenderWindow(ren_win) + +slider = widget.slider(iren=iren, ren=renderer, callback=change_slice) + +iren.Initialize() + +ren_win.Render() + +if depth_peeling: + dp_bool = str(bool(renderer.GetLastRenderingUsedDepthPeeling())) + print('Depth peeling used? ' + dp_bool) + +iren.Start() + + +# ren_win.RemoveRenderer(renderer) +# renderer.SetRenderWindow(None) From 1ead7232c6f44c04554570038ab71477d4cd2cab Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 16 May 2015 19:47:42 -0400 Subject: [PATCH 079/242] On the way to fetching bundles --- doc/examples/introduction_to_visualization.py | 139 +++++++++--------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index 05f9a9db48..4046e98966 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -28,47 +28,62 @@ and sliders and these interact both with windows and actors. Because of this they need input from the operating system so they can process events. -So, let's get started. In this tutorial we will create a +So, let's get started. In this tutorial we will visualize some bundles and a +slicer. We will be able to change the slices using a ``slider`` widget. """ +def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], + bundles=['af.left', 'cst.right', 'cc_1']): -import numpy as np -# Change with Stanford data -#dname = '/home/eleftherios/Data/Cunnane_Elef/08-111-609-AC15/work/' -dname = '/home/eleftherios/Data/fancy_data/2013_02_08_Gabriel_Girard/' + dname = '/home/eleftherios/Data/bundles_2_subjects' -import nibabel as nib -from nibabel import trackvis as tv + import nibabel as nib + from nibabel import trackvis as tv + from os.path import join as pjoin -world_coords = False -streamline_opacity = 1. -slicer_opacity = 1. -depth_peeling = False + res = {} + + if 't1' in metrics: + img = nib.load(pjoin(dname, subj_id, 't1_warped.nii.gz')) + data = img.get_data() + affine = img.get_affine() + res['t1'] = data + + if 'fa' in metrics: + img_fa = nib.load(pjoin(dname, subj_id, 'fa_1x1x1.nii.gz')) + fa = img_fa.get_data() + affine = img_fa.get_affine() + res['fa'] = fa -img = nib.load(dname + 't1_warped.nii.gz') -data = img.get_data() -affine = img.get_affine() + res['affine'] = affine + for bun in bundles: -img_fa = nib.load(dname + 'fa_1x1x1.nii.gz') -fa = img_fa.get_data() -affine_fa = img_fa.get_affine() + streams, hdr = tv.read(pjoin(dname, subj_id, + 'bundles', 'bundles_' + bun + '.trk'), + points_space="rasmm") + streamlines = [s[0] for s in streams] + res[bun] = streamlines + return res + + +world_coords = True +streamline_opacity = 1. +slicer_opacity = 1. +depth_peeling = False -streams, hdr = tv.read(dname + 'TRK_files/bundles_cst.right.trk', - points_space="rasmm") -streamlines = [s[0] for s in streams] +res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], + ['af.left', 'cst.right', 'cc_1']) -streams, hdr = tv.read(dname + 'TRK_files/bundles_af.left.trk', - points_space="rasmm") -streamlines += [s[0] for s in streams] -streams, hdr = tv.read(dname + 'TRK_files/bundles_cc_1.trk', - points_space="rasmm") -streamlines += [s[0] for s in streams] +streamlines = res['af.left'] + res['cst.right'] + res['cc_1'] +data = res['fa'] +shape = data.shape +affine = res['affine'] if not world_coords: from dipy.tracking.streamline import transform_streamlines @@ -76,65 +91,57 @@ ren = window.Renderer() -stream_actor = actor.streamtube(streamlines, fa) +stream_actor = actor.line(streamlines) if not world_coords: - slicer = actor.slice(data, affine=np.eye(4)) + image = actor.slice(data, affine=np.eye(4)) else: - slicer = actor.slice(data, affine) + image = actor.slice(data, affine) -slicer.GetProperty().SetOpacity(slicer_opacity) -stream_actor.GetProperty().SetOpacity(streamline_opacity) +# slicer.GetProperty().SetOpacity(slicer_opacity) +# stream_actor.GetProperty().SetOpacity(streamline_opacity) ren.add(stream_actor) -ren.add(slicer) +ren.add(image) + +show_m = window.ShowManager(ren, size=(1200, 900)) +show_m.initialize() def change_slice(obj, event): - global slicer z = int(np.round(obj.GetSliderRepresentation().GetValue())) - - print(obj) - print(event) print(z) - slicer.SetDisplayExtent(0, 255, 0, 255, z, z) - slicer.Update() - -import vtk - -ren_win = vtk.vtkRenderWindow() -ren_win.AddRenderer(renderer) - -if depth_peeling: - # http://www.vtk.org/Wiki/VTK/Depth_Peeling - ren_win.SetAlphaBitPlanes(1) - ren_win.SetMultiSamples(0) - renderer.SetUseDepthPeeling(1) - renderer.SetMaximumNumberOfPeels(10) - renderer.SetOcclusionRatio(0.1) - - -iren = vtk.vtkRenderWindowInteractor() -iren.SetRenderWindow(ren_win) - -slider = widget.slider(iren=iren, ren=renderer, callback=change_slice) - -iren.Initialize() -ren_win.Render() + image.SetDisplayExtent(0, shape[0] - 1, + 0, shape[1] - 1, z, z) + image.Update() -if depth_peeling: - dp_bool = str(bool(renderer.GetLastRenderingUsedDepthPeeling())) - print('Depth peeling used? ' + dp_bool) +slider = widget.slider(show_m.iren, show_m.ren, + callback=change_slice, + min_value=0, + max_value=shape[2] - 1, + value=shape[2] / 2, + label="Z-axis", + right_normalized_pos=(.98, 0.6), + size=(120, 0), label_format="%0.lf") -iren.Start() +show_m.render() +show_m.start() -# ren_win.RemoveRenderer(renderer) -# renderer.SetRenderWindow(None) +# if depth_peeling: +# # http://www.vtk.org/Wiki/VTK/Depth_Peeling +# ren_win.SetAlphaBitPlanes(1) +# ren_win.SetMultiSamples(0) +# renderer.SetUseDepthPeeling(1) +# renderer.SetMaximumNumberOfPeels(10) +# renderer.SetOcclusionRatio(0.1) +#if depth_peeling: +# dp_bool = str(bool(renderer.GetLastRenderingUsedDepthPeeling())) +# print('Depth peeling used? ' + dp_bool) From 456e4e40de3852d811adc72016f96d1b25f60ef2 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 17 May 2015 00:09:32 -0400 Subject: [PATCH 080/242] New fetcher for experimtal bundles and metrics for 2 subjects --- dipy/data/__init__.py | 4 ++- dipy/data/fetcher.py | 66 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/dipy/data/__init__.py b/dipy/data/__init__.py index 8065a15db8..df0e94b638 100644 --- a/dipy/data/__init__.py +++ b/dipy/data/__init__.py @@ -46,7 +46,9 @@ def loads_compat(bytes): fetch_stanford_pve_maps, read_stanford_pve_maps, fetch_viz_icons, - read_viz_icons) + read_viz_icons, + fetch_bundles_2_subjects, + read_bundles_2_subjects) from ..utils.arrfuncs import as_native_array diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index d3baa03e27..b33280e70a 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -612,3 +612,69 @@ def read_viz_icons(style='icomoon', fname='infinity.png'): folder = pjoin(dipy_home, 'icons', style) return pjoin(folder, fname) + + +def fetch_bundles_2_subjects(): + """ Download 2 subjects with their bundles + """ + url = 'https://dl.dropboxusercontent.com/u/2481924/' + fname = 'bundles_2_subjects.tar.gz' + url = url + fname + folder = pjoin(dipy_home, 'exp_bundles_and_maps') + + url_list = [url] + md5_list = ['97756fbef11ce2df31f1bedf1fc7aac7'] + fname_list = [fname] + + if not os.path.exists(folder): + print('Creating new directory %s' % folder) + os.makedirs(folder) + print('Downloading dataset ...') + for i in range(len(md5_list)): + _get_file_data(pjoin(folder, fname_list[i]), url_list[i]) + new_path = pjoin(folder, fname_list[i]) + check_md5(new_path, md5_list[i]) + ar = tarfile.open(new_path) + ar.extractall(path=folder) + ar.close() + + print('Done.') + print('Files copied in folder %s' % folder) + else: + msg = 'Dataset is already in place. If you want to fetch it again, ' + msg += 'please first remove the folder %s ' + print(msg % folder) + + +def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], + bundles=['af.left', 'cst.right', 'cc_1']): + + dname = pjoin(dipy_home, 'exp_bundles_and_maps', 'bundles_2_subjects') + + from nibabel import trackvis as tv + + res = {} + + if 't1' in metrics: + img = nib.load(pjoin(dname, subj_id, 't1_warped.nii.gz')) + data = img.get_data() + affine = img.get_affine() + res['t1'] = data + + if 'fa' in metrics: + img_fa = nib.load(pjoin(dname, subj_id, 'fa_1x1x1.nii.gz')) + fa = img_fa.get_data() + affine = img_fa.get_affine() + res['fa'] = fa + + res['affine'] = affine + + for bun in bundles: + + streams, hdr = tv.read(pjoin(dname, subj_id, + 'bundles', 'bundles_' + bun + '.trk'), + points_space="rasmm") + streamlines = [s[0] for s in streams] + res[bun] = streamlines + + return res \ No newline at end of file From 5169928145d3a43e48b8ff7db6a34ffa654234ba Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 17 May 2015 00:11:18 -0400 Subject: [PATCH 081/242] RF: adding fetcher in tutorial --- doc/examples/introduction_to_visualization.py | 38 +------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index 4046e98966..79a27b9791 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -33,43 +33,9 @@ """ -def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], - bundles=['af.left', 'cst.right', 'cc_1']): - - - dname = '/home/eleftherios/Data/bundles_2_subjects' - - import nibabel as nib - from nibabel import trackvis as tv - from os.path import join as pjoin - - res = {} - - if 't1' in metrics: - img = nib.load(pjoin(dname, subj_id, 't1_warped.nii.gz')) - data = img.get_data() - affine = img.get_affine() - res['t1'] = data - - if 'fa' in metrics: - img_fa = nib.load(pjoin(dname, subj_id, 'fa_1x1x1.nii.gz')) - fa = img_fa.get_data() - affine = img_fa.get_affine() - res['fa'] = fa - - - res['affine'] = affine - - for bun in bundles: - - streams, hdr = tv.read(pjoin(dname, subj_id, - 'bundles', 'bundles_' + bun + '.trk'), - points_space="rasmm") - streamlines = [s[0] for s in streams] - res[bun] = streamlines - - return res +from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects +fetch_bundles_2_subjects() world_coords = True streamline_opacity = 1. From 46eb620861b12ecc2607e54952b50951a01a6c12 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 19 May 2015 11:44:29 -0400 Subject: [PATCH 082/242] todo added --- doc/examples/introduction_to_visualization.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index 79a27b9791..db503e6375 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -93,7 +93,8 @@ def change_slice(obj, event): show_m.render() show_m.start() - +# TODO +# check why the window is not closing From cc013f6a88f530633752eb27b57e0b1f7d3220a3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 19 May 2015 12:26:29 -0400 Subject: [PATCH 083/242] BF: ShowManager is now able to close the window by deleting iren and window attributes --- dipy/viz/window.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 34def24464..a83453e3ea 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -204,6 +204,8 @@ def start(self): # ren.SetRenderWindow(None) self.window.RemoveRenderer(self.ren) self.ren.SetRenderWindow(None) + del self.iren + del self.window def add_window_callback(self, win_callback): self.window.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) From c38484bd3a767580c900ac0c002bf8656c69efc9 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 09:09:15 -0400 Subject: [PATCH 084/242] DOC: Beginning documenting slice --- dipy/viz/actor.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index ae1951698a..be607dc31c 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -22,6 +22,20 @@ def slice(data, affine): + """ Cuts 3D images + + Parameters + ---------- + data : array, shape (X, Y, Z) + A volume as a numpy array. + affine : array, shape (3, 3) + Grid to space (usually RAS 1mm) transformation matrix + + Returns + ------- + vtkImageActor + + """ vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) vol = vol.astype('uint8') From bcf6ac3ff1b54d9b8db7c76588b3f9381a8a1037 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 10:16:02 -0400 Subject: [PATCH 085/242] DOC: doctstring of slice looks ready --- dipy/viz/actor.py | 101 ++++++++---------- doc/examples/introduction_to_visualization.py | 11 +- 2 files changed, 49 insertions(+), 63 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index be607dc31c..c11c3ea54c 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,19 +21,27 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() -def slice(data, affine): - """ Cuts 3D images +def slice(data, affine=None, opacity=1., lookup_colormap=None): + """ Cuts 3D volumes into images Parameters ---------- data : array, shape (X, Y, Z) - A volume as a numpy array. + A 3D volume as a numpy array. affine : array, shape (3, 3) Grid to space (usually RAS 1mm) transformation matrix + opacity : float + Opacity of 0 means completely transparent and 1 completely visible. + lookup_colormap : vtkLookupTable + If None (default) then a grayscale map is created. Returns ------- - vtkImageActor + image_actor : ImageActor + An object that is capable of displaying different parts of the volume + as slices. The key method of this object is ``display_extent`` where + one can input grid coordinates and display the slice in space (or grid) + coordinates as calculated by the affine parameter. """ @@ -58,17 +66,19 @@ def slice(data, affine): i, j, k = index im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) + if affine is None: + affine = np.eye(4) + # Set the transform (identity if none given) transform = vtk.vtkTransform() - if affine is not None: - transform_matrix = vtk.vtkMatrix4x4() - transform_matrix.DeepCopy(( - affine[0][0], affine[0][1], affine[0][2], affine[0][3], - affine[1][0], affine[1][1], affine[1][2], affine[1][3], - affine[2][0], affine[2][1], affine[2][2], affine[2][3], - affine[3][0], affine[3][1], affine[3][2], affine[3][3])) - transform.SetMatrix(transform_matrix) - transform.Inverse() + transform_matrix = vtk.vtkMatrix4x4() + transform_matrix.DeepCopy(( + affine[0][0], affine[0][1], affine[0][2], affine[0][3], + affine[1][0], affine[1][1], affine[1][2], affine[1][3], + affine[2][0], affine[2][1], affine[2][2], affine[2][3], + affine[3][0], affine[3][1], affine[3][2], affine[3][3])) + transform.SetMatrix(transform_matrix) + transform.Inverse() # Set the reslicing image_resliced = vtk.vtkImageReslice() @@ -78,58 +88,37 @@ def slice(data, affine): image_resliced.SetInterpolationModeToLinear() image_resliced.Update() - # Get back resliced image - # im = image_data #image_resliced.GetOutput() - - # An outline provides context around the data. - # outline_data = vtk.vtkOutlineFilter() - # set_input(outline_data, im) - # - # mapOutline = vtk.vtkPolyDataMapper() - # mapOutline.SetInputConnection(outline_data.GetOutputPort()) - # outline_ = vtk.vtkActor() - # outline_.SetMapper(mapOutline) - # outline_.GetProperty().SetColor(1, 0, 0) - - # Now we are creating three orthogonal planes passing through the - # volume. Each plane uses a different texture map and therefore has - # diferent coloration. - - # Start by creatin a black/white lookup table. - lut = vtk.vtkLookupTable() - lut.SetTableRange(0, 255) - # print(data.min(), data.max()) - lut.SetSaturationRange(0, 0) - lut.SetHueRange(0, 0) - lut.SetValueRange(0, 1) - lut.SetRampToLinear() - lut.Build() + # Start by creating a black/white lookup table. + if lookup_colormap is None: + lut = colormap_lookup_table((0, 255), (0, 0), (0, 0), (0, 1)) + else: + lut = lookup_colormap x1, x2, y1, y2, z1, z2 = im.GetExtent() - # Create the first of the three planes. The filter vtkImageMapToColors - # maps the data through the corresponding lookup table created above. - # The vtkImageActor is a type of vtkProp and conveniently displays an - # image on a single quadrilateral plane. It does this using texture - # mapping and as a result is quite fast. (Note: the input image has to - # be unsigned char values, which the vtkImageMapToColors produces.) - # Note also that by specifying the DisplayExtent, the pipeline - # requests data of this extent and the vtkImageMapToColors only - # processes a slice of data. plane_colors = vtk.vtkImageMapToColors() plane_colors.SetLookupTable(lut) plane_colors.SetInputConnection(image_resliced.GetOutputPort()) plane_colors.Update() - saggital = vtk.vtkImageActor() - # set_input(saggital, plane_colors.GetOutput()) - saggital.GetMapper().SetInputConnection(plane_colors.GetOutputPort()) - # saggital.SetDisplayExtent(0, 0, y1, y2, z1, z2) - saggital.SetDisplayExtent(x1, x2, y1, y2, z2/2, z2/2) - # saggital.SetDisplayExtent(25, 25, 0, 49, 0, 49) - saggital.Update() + class ImageActor(vtk.vtkImageActor): + + def input_connection(self, output_port): + self.GetMapper().SetInputConnection(output_port) + + def display_extent(self, x1, x2, y1, y2, z1, z2): + self.SetDisplayExtent(x1, x2, y1, y2, z1, z2) + self.Update() + + def opacity(self, value): + self.GetProperty().SetOpacity(value) + + image_actor = ImageActor() + image_actor.input_connection(plane_colors.GetOutputPort()) + image_actor.display_extent(x1, x2, y1, y2, z2/2, z2/2) + image_actor.opacity(opacity) - return saggital + return image_actor def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index db503e6375..d30b622537 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -39,7 +39,7 @@ world_coords = True streamline_opacity = 1. -slicer_opacity = 1. +slicer_opacity = .6 depth_peeling = False res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], @@ -64,7 +64,7 @@ else: image = actor.slice(data, affine) -# slicer.GetProperty().SetOpacity(slicer_opacity) +image.opacity(slicer_opacity) # stream_actor.GetProperty().SetOpacity(streamline_opacity) ren.add(stream_actor) @@ -75,11 +75,8 @@ def change_slice(obj, event): z = int(np.round(obj.GetSliderRepresentation().GetValue())) - print(z) - - image.SetDisplayExtent(0, shape[0] - 1, - 0, shape[1] - 1, z, z) - image.Update() + image.display_extent(0, shape[0] - 1, + 0, shape[1] - 1, z, z) slider = widget.slider(show_m.iren, show_m.ren, callback=change_slice, From 56298db71682f3033aa7d50ae1ec7bdda64b6f71 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 10:24:35 -0400 Subject: [PATCH 086/242] DOC: colormap lut --- dipy/viz/actor.py | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index c11c3ea54c..fcba4bc10b 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -88,8 +88,8 @@ def slice(data, affine=None, opacity=1., lookup_colormap=None): image_resliced.SetInterpolationModeToLinear() image_resliced.Update() - # Start by creating a black/white lookup table. if lookup_colormap is None: + # Create a black/white lookup table. lut = colormap_lookup_table((0, 255), (0, 0), (0, 0), (0, 1)) else: lut = lookup_colormap @@ -418,27 +418,43 @@ def lines_to_vtk_polydata(lines, colors=None): def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), - saturation_range=(1, 1), value_range=(0.8, 0.8)): - """ Default Lookup table for the colormap + saturation_range=(1, 1), value_range=(0.8, 0.8)): + """ Lookup table for the colormap + + Parameters + ---------- + scale_range : tuple + It can be anything e.g. (0, 1) or (0, 255). Usually it is the mininum + and maximum value of your data. + hue_range : tuple of floats + HSV values (min 0 and max 1) + saturation_range : tuple of floats + HSV values (min 0 and max 1) + value_range : tuple of floats + HSV value (min 0 and max 1) + + Returns + ------- + lookup_table : vtkLookupTable + """ - vtk_lookup_table = vtk.vtkLookupTable() - vtk_lookup_table.SetRange(scale_range) - vtk_lookup_table.SetTableRange(scale_range) + lookup_table = vtk.vtkLookupTable() + lookup_table.SetRange(scale_range) + lookup_table.SetTableRange(scale_range) - vtk_lookup_table.SetHueRange(hue_range) - vtk_lookup_table.SetSaturationRange(saturation_range) - vtk_lookup_table.SetValueRange(value_range) + lookup_table.SetHueRange(hue_range) + lookup_table.SetSaturationRange(saturation_range) + lookup_table.SetValueRange(value_range) - vtk_lookup_table.Build() - return vtk_lookup_table + lookup_table.Build() + return lookup_table def scalar_bar(lookup_table, title=" "): """ Default Scalar bar actor for the colormap - - Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it """ lookup_table_copy = vtk.vtkLookupTable() + # Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it lookup_table_copy.DeepCopy(lookup_table) scalar_bar = vtk.vtkScalarBarActor() scalar_bar.SetTitle(title) From 4b8b57f901ce04effb937e2875f6a44055029d7b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 10:32:48 -0400 Subject: [PATCH 087/242] DOC: lines to vtk_polydata --- dipy/viz/actor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index fcba4bc10b..704eae2283 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -340,10 +340,9 @@ def lines_to_vtk_polydata(lines, colors=None): list of N curves represented as 2D ndarrays colors : array (N, 3), tuple (3,) or colormap - Returns - ---------- - poly_data : VTK polydata + ------- + poly_data : vtkPolyData is_colormap : bool, true if the input color array was a colormap """ From 903ee362980d2da56e19bf00de4a038c4c6d05d2 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 10:55:24 -0400 Subject: [PATCH 088/242] NF: added open file dialog --- dipy/viz/window.py | 53 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index a83453e3ea..1bef7b4b3f 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -40,9 +40,13 @@ class Renderer(vtk.vtkRenderer): """ def background(self, color): + """ Set a background color + """ self.SetBackground(color) def add(self, actor): + """ Add an actor to the renderer + """ if isinstance(actor, vtk.vtkVolume): self.AddVolume(actor) else: @@ -122,16 +126,51 @@ def rm_all(ren): ren.rm_all() -def save_file_dialog(initial_file='dipy.png', default_extension='.png', - filetypes=(("PNG file", "*.png"), ("All Files", "*.*"))): - """ Simple Tk file dialog +def open_file_dialog(file_types=[("All files", "*")]): + """ Simple Tk file dialog for opening files + + Parameters + ---------- + file_types : tuples of tuples + Accepted file types. + + Returns + ------- + file_paths : sequence of str + Returns the full paths of all selected files """ + + root = Tkinter.Tk() + root.withdraw() + file_paths = tkFileDialog.askopenfilenames(filetypes=file_types) + return file_paths + + +def save_file_dialog(initial_file='dipy.png', default_ext='.png', + file_types=(("PNG file", "*.png"), ("All Files", "*.*"))): + """ Simple Tk file dialog for saving a file + + Parameters + ---------- + initial_file : str + For example ``dipy.png``. + default_ext : str + Default extension to appear in the save dialog. + file_types : tuples of tuples + Accepted file types. + + Returns + ------- + filepath : str + Complete filename of saved file + """ + root = Tkinter.Tk() root.withdraw() - filepath = tkFileDialog.asksaveasfilename(initialfile='dipy.png', - defaultextension='.png', - filetypes=filetypes) - return filepath + file_path = tkFileDialog.asksaveasfilename(initialfile=initial_file, + defaultextension=default_ext, + filetypes=file_types) + return file_path class ShowManager(object): From 9e2fc6a0f66331f958f3a6eefabbaef3df89dbea Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 12:28:20 -0400 Subject: [PATCH 089/242] TEST: added new test for parallel projection --- dipy/viz/tests/test_fvtk_window.py | 36 +++++++++++++++++++++--- dipy/viz/window.py | 45 +++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 4fa9c69ccf..fcca68163f 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -16,7 +16,7 @@ def test_renderer(): ren.background(bg_float) - # window.show(ren) + window.show(ren) arr = window.snapshot(ren) report = window.analyze_snapshot(arr, bg_color=bg_color, @@ -26,7 +26,6 @@ def test_renderer(): axes = fvtk.axes() ren.add(axes) - # window.show(ren) arr = window.snapshot(ren) @@ -64,8 +63,37 @@ def test_renderer(): npt.assert_equal(report.actors, 0) +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_parallel_projection(): + + ren = window.Renderer() + axes = fvtk.axes() + ren.add(axes) + + axes2 = fvtk.axes() + axes2.SetPosition((2, 0, 0)) + ren.add(axes2) + + # Put the camera on a angle so that the + # camera can show the difference between perspective + # and parallel projection + fvtk.camera(ren, pos=(1.5, 1.5, 1.5)) + ren.GetActiveCamera().Zoom(2) + + # window.show(ren, reset_camera=True) + ren.reset_camera() + arr = window.snapshot(ren) + + ren.projection('parallel') + # window.show(ren, reset_camera=False) + arr2 = window.snapshot(ren) + # Because of the parallel projection the two axes + # will have the same size and therefore occupy more + # pixels rather than in perspective projection were + # the axes being further will be smaller. + npt.assert_equal(np.sum(arr2 > 0) > np.sum(arr > 0), True) if __name__ == '__main__': - test_renderer() - # npt.run_module_suite() + npt.run_module_suite() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 1bef7b4b3f..fc51d536b9 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -67,6 +67,25 @@ def rm_all(self): """ self.RemoveAllViewProps() + def projection(self, proj_type='perspective'): + """ Deside between parallel or perspective projection + + Parameters + ---------- + proj_type : str + Can be 'parallel' or 'perspective' (default). + + """ + if proj_type == 'parallel': + self.GetActiveCamera().ParallelProjectionOn() + else: + self.GetActiveCamera().ParallelProjectionOff() + + def reset_camera(self): + """ Allow the renderer to reset the camera + """ + self.ResetCamera() + def renderer(background=None): """ Create a renderer. @@ -78,9 +97,7 @@ def renderer(background=None): Returns ------- - v : vtkRenderer() object - Renderer. - + v : Renderer Examples -------- @@ -175,13 +192,16 @@ def save_file_dialog(initial_file='dipy.png', default_ext='.png', class ShowManager(object): - def __init__(self, ren, title='Dipy', size=(300, 300), png_magnify=1): + def __init__(self, ren, title='Dipy', size=(300, 300), + png_magnify=1, reset_camera=True): self.title = title self.size = size self.png_magnify = png_magnify - ren.ResetCamera() + if reset_camera: + ren.ResetCamera() + window = vtk.vtkRenderWindow() window.AddRenderer(ren) # window.SetAAFrames(6) @@ -251,13 +271,10 @@ def add_window_callback(self, win_callback): self.window.Render() -def show(ren, title='Dipy', size=(300, 300), png_magnify=1): - """ Show window +def show(ren, title='Dipy', size=(300, 300), + png_magnify=1, reset_camera=True): + """ Show window with current renderer - Notes - ----- - To save a screenshot press's' and check your current directory - for ``fvtk.png``. Parameters ------------ @@ -281,7 +298,8 @@ def show(ren, title='Dipy', size=(300, 300), png_magnify=1): See also --------- - dipy.viz.fvtk.record + dipy.viz.window.record + dipy.viz.window.snapshot Examples ---------- @@ -302,7 +320,8 @@ def show(ren, title='Dipy', size=(300, 300), png_magnify=1): """ - show_manager = ShowManager(ren, title, size, png_magnify) + show_manager = ShowManager(ren, title, size, + png_magnify, reset_camera) show_manager.initialize() show_manager.render() show_manager.start() From e02e3cf1a1d5a9abf86093b0f97837a30078d575 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 13:45:23 -0400 Subject: [PATCH 090/242] Minor changes --- dipy/viz/actor.py | 7 +++++++ dipy/viz/tests/test_fvtk_window.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 704eae2283..dcec6338b8 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -166,6 +166,13 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, from dipy.tracking.distances import approx_polygon_track lines = [approx_polygon_track(line, 0.2) for line in lines] + + Alternatively we suggest using the ``line`` actor which is much more + efficient. + + See Also + -------- + dipy.viz.fvtk.line """ # Poly data with lines and colors poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index fcca68163f..b99d5737dc 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -16,7 +16,7 @@ def test_renderer(): ren.background(bg_float) - window.show(ren) + # window.show(ren) arr = window.snapshot(ren) report = window.analyze_snapshot(arr, bg_color=bg_color, From bb0b51b118df270e7afac9293630ff4d20b57e23 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 18:21:51 -0400 Subject: [PATCH 091/242] DOC: adding more explanations to the tutorial --- doc/examples/introduction_to_visualization.py | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index d30b622537..306751410a 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -28,29 +28,47 @@ and sliders and these interact both with windows and actors. Because of this they need input from the operating system so they can process events. -So, let's get started. In this tutorial we will visualize some bundles and a -slicer. We will be able to change the slices using a ``slider`` widget. +So, let's get started. In this tutorial, we will visualize some bundles +together with FA or T1. We will be able to change the slices using +a ``slider`` widget. +First we need to fetch and load some datasets. """ from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects fetch_bundles_2_subjects() -world_coords = True -streamline_opacity = 1. -slicer_opacity = .6 -depth_peeling = False +""" +The following function outputs a dictionary with the required bundles e.g. af +left and maps, e.g. FA for a specific subject. +""" res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], ['af.left', 'cst.right', 'cc_1']) +""" +We will use 3 bundles, FA and the affine transformation that brings the voxel +cordinates to world coordinates (RAS 1mm). +""" streamlines = res['af.left'] + res['cst.right'] + res['cc_1'] data = res['fa'] shape = data.shape affine = res['affine'] +""" +With our current design it is easy to decide in which space you want the +streamlines and slices to appear. The default we have here is to appear in +world coordinates (RAS 1mm). +""" + +world_coords = True + +""" +If the +""" + if not world_coords: from dipy.tracking.streamline import transform_streamlines streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) @@ -59,13 +77,14 @@ stream_actor = actor.line(streamlines) +slicer_opacity = .6 + if not world_coords: image = actor.slice(data, affine=np.eye(4)) else: image = actor.slice(data, affine) image.opacity(slicer_opacity) -# stream_actor.GetProperty().SetOpacity(streamline_opacity) ren.add(stream_actor) ren.add(image) @@ -83,16 +102,13 @@ def change_slice(obj, event): min_value=0, max_value=shape[2] - 1, value=shape[2] / 2, - label="Z-axis", + label="Move slice", right_normalized_pos=(.98, 0.6), size=(120, 0), label_format="%0.lf") show_m.render() show_m.start() -# TODO -# check why the window is not closing - # if depth_peeling: From e7f485f7b1e9184a4fd5d65439fb8bfa189568e4 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 21:58:37 -0400 Subject: [PATCH 092/242] DOC: progress with tutorial --- doc/examples/introduction_to_visualization.py | 79 ++++++++++++++----- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index 306751410a..12e7fa3ad9 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -66,36 +66,62 @@ world_coords = True """ -If the +If we want to see the objects in native space we need to make sure that all +objects which are currently in world coordinates are transformed back to +native space using the inverse of the affine. """ if not world_coords: from dipy.tracking.streamline import transform_streamlines streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) -ren = window.Renderer() +""" +Now we create, a ``Renderer`` object and add the streamlines using the ``line`` +function and an image plane using the ``slice`` function. +""" +ren = window.Renderer() stream_actor = actor.line(streamlines) -slicer_opacity = .6 - if not world_coords: - image = actor.slice(data, affine=np.eye(4)) + image_actor = actor.slice(data, affine=np.eye(4)) else: - image = actor.slice(data, affine) + image_actor = actor.slice(data, affine) + +""" +For fun let's change also the opacity of the slicer +""" -image.opacity(slicer_opacity) +slicer_opacity = .6 +image_actor.opacity(slicer_opacity) + +""" +Connect the actors with the Renderer. +""" ren.add(stream_actor) -ren.add(image) +ren.add(image_actor) + +""" +Now we would like to change the position of the ``image_actor`` using a slider. +The sliders are widgets which require access to different areas of the +visualization pipeline and therefore we don't recommend using them with +``show``. The more appropriate way is to use them with the ``ShowManager`` +object which allows accessing the pipeline in different areas. Here is how: +""" show_m = window.ShowManager(ren, size=(1200, 900)) show_m.initialize() +""" +After we have initialized the ``ShowManager`` we can go ahead and create a +callback which will be given to the ``slider`` function. +""" + def change_slice(obj, event): z = int(np.round(obj.GetSliderRepresentation().GetValue())) - image.display_extent(0, shape[0] - 1, - 0, shape[1] - 1, z, z) + image_actor.display_extent(0, shape[0] - 1, + 0, shape[1] - 1, z, z) slider = widget.slider(show_m.iren, show_m.ren, callback=change_slice, @@ -106,23 +132,34 @@ def change_slice(obj, event): right_normalized_pos=(.98, 0.6), size=(120, 0), label_format="%0.lf") +""" +Then, we can render all the widget and everything else in the screen and +start the interaction using ``show_m.start()``. +""" + show_m.render() -show_m.start() +# show_m.start() +""" +However, if you change the window size, the slider will not update its position +properly. The solution to this issue is to update the position of the slider +using its ``place`` method everytime the window size changes. +""" +global size +size = ren.GetSize() -# if depth_peeling: -# # http://www.vtk.org/Wiki/VTK/Depth_Peeling -# ren_win.SetAlphaBitPlanes(1) -# ren_win.SetMultiSamples(0) -# renderer.SetUseDepthPeeling(1) -# renderer.SetMaximumNumberOfPeels(10) -# renderer.SetOcclusionRatio(0.1) +def win_callback(obj, event): + global size + if size != obj.GetSize(): -#if depth_peeling: -# dp_bool = str(bool(renderer.GetLastRenderingUsedDepthPeeling())) -# print('Depth peeling used? ' + dp_bool) + slider.place(ren) + size = obj.GetSize() +show_m.initialize() +show_m.add_window_callback(win_callback) +show_m.render() +show_m.start() From be0ee42ec6ac53ac26e4b22d2ce564a36dabe4da Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 22:05:00 -0400 Subject: [PATCH 093/242] Commented interactive output --- doc/examples/introduction_to_visualization.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/introduction_to_visualization.py index 12e7fa3ad9..d6eebf204c 100644 --- a/doc/examples/introduction_to_visualization.py +++ b/doc/examples/introduction_to_visualization.py @@ -1,7 +1,7 @@ """ -=============================================== -Advanced interactive visualization capabilities -=============================================== +================================== +Advanced interactive visualization +================================== In DIPY we created a thin interface to access many of the capabilities available in the Visualization Toolkit framework (VTK) but tailored to the @@ -137,7 +137,7 @@ def change_slice(obj, event): start the interaction using ``show_m.start()``. """ -show_m.render() +# show_m.render() # show_m.start() """ @@ -158,8 +158,14 @@ def win_callback(obj, event): show_m.initialize() show_m.add_window_callback(win_callback) -show_m.render() -show_m.start() + +""" +Finally, please uncomment the following lines so that you can interact with +the available 3D and 2D objects. +""" + +# show_m.render() +# show_m.start() From 31b7ff8ea78493385175c43dbfe5d2865ccc3d74 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 20 May 2015 22:09:44 -0400 Subject: [PATCH 094/242] RF: renamed tutorial --- ...oduction_to_visualization.py => advanced_interactive_viz.py} | 0 doc/examples/valid_examples.txt | 2 +- doc/examples_index.rst | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename doc/examples/{introduction_to_visualization.py => advanced_interactive_viz.py} (100%) diff --git a/doc/examples/introduction_to_visualization.py b/doc/examples/advanced_interactive_viz.py similarity index 100% rename from doc/examples/introduction_to_visualization.py rename to doc/examples/advanced_interactive_viz.py diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index 2790377aea..e75ff044b8 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -36,4 +36,4 @@ bundle_registration.py tracking_tissue_classifier.py piesno.py - introduction_to_visualization.py \ No newline at end of file + advanced_interactive_viz.py diff --git a/doc/examples_index.rst b/doc/examples_index.rst index 8ebd83228b..2a09ac1b56 100644 --- a/doc/examples_index.rst +++ b/doc/examples_index.rst @@ -193,7 +193,7 @@ File Formats Visualization ------------- -- :ref:`example_introduction_to_visualization` +- :ref:`example_advanced_interactive_viz` .. In order to build the examples, you'll need (on Debian) From f753021ac92c66ba193cc5f7869b94567388aa65 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 26 Jun 2015 18:55:57 -0400 Subject: [PATCH 095/242] Minor corrections --- doc/examples/advanced_interactive_viz.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/examples/advanced_interactive_viz.py b/doc/examples/advanced_interactive_viz.py index d6eebf204c..a3a8b79bf0 100644 --- a/doc/examples/advanced_interactive_viz.py +++ b/doc/examples/advanced_interactive_viz.py @@ -10,7 +10,7 @@ for backwards compatibility but now there is a more comprehensive way to access the main functions using the following modules. """ - +import numpy as np from dipy.viz import actor, window, widget """ @@ -164,8 +164,8 @@ def win_callback(obj, event): the available 3D and 2D objects. """ -# show_m.render() -# show_m.start() +show_m.render() +show_m.start() From 29c02b898697ccbba9ce6888d6c3cb6c76bdaafb Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 2 Jul 2015 17:16:37 -0400 Subject: [PATCH 096/242] TEST: corrected flooring error in analyze snapshot --- dipy/viz/tests/test_fvtk_window.py | 5 ++++- dipy/viz/window.py | 5 +---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index b99d5737dc..e99f5e8998 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -10,9 +10,11 @@ def test_renderer(): ren = window.Renderer() + # background color for renderer bg_float = (1, 0.5, 0) - bg_color = tuple((np.round(255 * np.array(bg_float))).astype('uint8')) + # that will come in the image in the 0-255 uint scale + bg_color = tuple((np.floor(255 * np.array(bg_float))).astype('uint8')) ren.background(bg_float) @@ -94,6 +96,7 @@ def test_parallel_projection(): # the axes being further will be smaller. npt.assert_equal(np.sum(arr2 > 0) > np.sum(arr > 0), True) + if __name__ == '__main__': npt.run_module_suite() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index fc51d536b9..01dc5c6282 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -549,7 +549,7 @@ class ReportSnapshot(object): flags = [False] * len(colors) for (i, col) in enumerate(colors): # find if the current color exist in the array - flags[i] = np.any(np.all(im == col, axis = -1)) + flags[i] = np.any(np.all(im == col, axis=-1)) report.colors_found = flags @@ -568,6 +568,3 @@ class ReportSnapshot(object): report.objects = objects return report - - - From 3275d93e5080f0ef24d1105aedfcb175bc0e9c1e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 08:42:36 -0400 Subject: [PATCH 097/242] Background color can change in different OS version --- dipy/viz/tests/test_fvtk_window.py | 4 +++- dipy/viz/window.py | 12 +++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index e99f5e8998..5ef2e1dec9 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -20,6 +20,7 @@ def test_renderer(): # window.show(ren) arr = window.snapshot(ren) + print(bg_color) report = window.analyze_snapshot(arr, bg_color=bg_color, colors=[bg_color, (0, 127, 0)]) @@ -99,4 +100,5 @@ def test_parallel_projection(): if __name__ == '__main__': - npt.run_module_suite() + test_renderer() + #npt.run_module_suite() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 01dc5c6282..e161795896 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -23,12 +23,15 @@ version = vtk.vtkVersion.GetVTKSourceVersion().split(' ')[-1] major_version = vtk.vtkVersion.GetVTKMajorVersion() from vtk.util.numpy_support import vtk_to_numpy + vtkRenderer = vtk.vtkRenderer +else: + vtkRenderer = object if have_imread: from scipy.misc import imread -class Renderer(vtk.vtkRenderer): +class Renderer(vtkRenderer): """ The key rendering preparation object This is an important object that is responsible for preparing objects @@ -556,8 +559,15 @@ class ReportSnapshot(object): if find_objects is True: weights = [0.299, 0.587, 0.144] gray = np.dot(im[..., :3], weights) + bg_color = im[0, 0] background = np.dot(bg_color, weights) + print('-----------') + print(im[0, 0]) + print(im.dtype) + print(gray[0, 0]) + print(background) + if strel is None: strel = np.array([[0, 1, 0], [1, 1, 1], From 3b87a15e97f394ed899520184fbd603d8ad54a9b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 10:48:52 -0400 Subject: [PATCH 098/242] RF: in Python 3 is tkinter not TKinter --- dipy/viz/tests/test_fvtk_window.py | 1 - dipy/viz/window.py | 11 ++++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 5ef2e1dec9..d954b262b3 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -1,6 +1,5 @@ import numpy as np from dipy.viz import actor, window, fvtk -from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt diff --git a/dipy/viz/window.py b/dipy/viz/window.py index e161795896..a5504bcda0 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -2,7 +2,12 @@ import numpy as np from scipy import ndimage -import Tkinter + +try: + import Tkinter as tkinter +except ImportError: + import tkinter + import tkFileDialog # Conditional import machinery for vtk @@ -160,7 +165,7 @@ def open_file_dialog(file_types=[("All files", "*")]): Returns the full paths of all selected files """ - root = Tkinter.Tk() + root = tkinter.Tk() root.withdraw() file_paths = tkFileDialog.askopenfilenames(filetypes=file_types) return file_paths @@ -185,7 +190,7 @@ def save_file_dialog(initial_file='dipy.png', default_ext='.png', Complete filename of saved file """ - root = Tkinter.Tk() + root = tkinter.Tk() root.withdraw() file_path = tkFileDialog.asksaveasfilename(initialfile=initial_file, defaultextension=default_ext, From 47409bfa29e382d7a217c79df58afb376f4a09a7 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 11:16:26 -0400 Subject: [PATCH 099/242] Changed background color --- dipy/viz/tests/test_fvtk_window.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index d954b262b3..07e15c1dae 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -10,13 +10,12 @@ def test_renderer(): ren = window.Renderer() # background color for renderer - bg_float = (1, 0.5, 0) + bg_float = (1, 0.4, 0) # that will come in the image in the 0-255 uint scale bg_color = tuple((np.floor(255 * np.array(bg_float))).astype('uint8')) ren.background(bg_float) - # window.show(ren) arr = window.snapshot(ren) print(bg_color) From e2ee441d2a9e76c62a1170b27d62831a888f52a1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 11:20:35 -0400 Subject: [PATCH 100/242] Added support for Py3 for filedialog --- dipy/viz/window.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index a5504bcda0..63c02dabf9 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -8,7 +8,10 @@ except ImportError: import tkinter -import tkFileDialog +try: + import tkFileDialog as filedialog +except ImportError: + filedialog = tkinter.filedialog # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -167,7 +170,7 @@ def open_file_dialog(file_types=[("All files", "*")]): root = tkinter.Tk() root.withdraw() - file_paths = tkFileDialog.askopenfilenames(filetypes=file_types) + file_paths = filedialog.askopenfilenames(filetypes=file_types) return file_paths @@ -192,9 +195,9 @@ def save_file_dialog(initial_file='dipy.png', default_ext='.png', root = tkinter.Tk() root.withdraw() - file_path = tkFileDialog.asksaveasfilename(initialfile=initial_file, - defaultextension=default_ext, - filetypes=file_types) + file_path = filedialog.asksaveasfilename(initialfile=initial_file, + defaultextension=default_ext, + filetypes=file_types) return file_path From 97c32c6c556386daf3485c2271c5d1bfaef24421 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 11:27:26 -0400 Subject: [PATCH 101/242] Checking stability of different colors close to 0.5 --- dipy/viz/tests/test_fvtk_window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 07e15c1dae..ae32bc3473 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -10,10 +10,10 @@ def test_renderer(): ren = window.Renderer() # background color for renderer - bg_float = (1, 0.4, 0) + bg_float = (1, 0.501, 0) # that will come in the image in the 0-255 uint scale - bg_color = tuple((np.floor(255 * np.array(bg_float))).astype('uint8')) + bg_color = tuple((np.round(255 * np.array(bg_float))).astype('uint8')) ren.background(bg_float) # window.show(ren) From 734e3a8e693f72a82e2ca3950e8607fe03a2119f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 11:34:58 -0400 Subject: [PATCH 102/242] RF: Removed print statements and added comment on numerical issues --- dipy/viz/tests/test_fvtk_window.py | 9 +++++---- dipy/viz/window.py | 6 ------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index ae32bc3473..edeac12f28 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -9,7 +9,9 @@ def test_renderer(): ren = window.Renderer() - # background color for renderer + # background color for renderer (1, 0.5, 0) + # 0.01 added here to remove numerical errors across change from float + # to int bg_float = (1, 0.501, 0) # that will come in the image in the 0-255 uint scale @@ -18,7 +20,7 @@ def test_renderer(): ren.background(bg_float) # window.show(ren) arr = window.snapshot(ren) - print(bg_color) + report = window.analyze_snapshot(arr, bg_color=bg_color, colors=[bg_color, (0, 127, 0)]) @@ -98,5 +100,4 @@ def test_parallel_projection(): if __name__ == '__main__': - test_renderer() - #npt.run_module_suite() + npt.run_module_suite() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 63c02dabf9..7f51a8248d 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -570,12 +570,6 @@ class ReportSnapshot(object): bg_color = im[0, 0] background = np.dot(bg_color, weights) - print('-----------') - print(im[0, 0]) - print(im.dtype) - print(gray[0, 0]) - print(background) - if strel is None: strel = np.array([[0, 1, 0], [1, 1, 1], From ae86061846ae88e8fa11e1307170d4b91d3e3d7e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 11:41:21 -0400 Subject: [PATCH 103/242] Minor comment correction --- dipy/viz/tests/test_fvtk_window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index edeac12f28..93200f1807 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -10,8 +10,8 @@ def test_renderer(): ren = window.Renderer() # background color for renderer (1, 0.5, 0) - # 0.01 added here to remove numerical errors across change from float - # to int + # 0.01 added here to remove numerical errors when moving from float + # to int values bg_float = (1, 0.501, 0) # that will come in the image in the 0-255 uint scale From b9043f7c18d87b2decc8cb030784b310edbaf511 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 15:17:57 -0400 Subject: [PATCH 104/242] BF: tkinter filedialog incorrectly imported --- dipy/viz/window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 7f51a8248d..85f70280a8 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -11,7 +11,7 @@ try: import tkFileDialog as filedialog except ImportError: - filedialog = tkinter.filedialog + from tkinter import filedialog # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package From 4d6e5c7be05c7cef3643e6dde2a1e5460eb48f2c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 15:57:56 -0400 Subject: [PATCH 105/242] DOC: Updated docstring of lines_to_vtk_polydata --- dipy/viz/actor.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index dcec6338b8..546a6fc294 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -130,7 +130,8 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, ---------- lines : list list of N curves represented as 2D ndarrays - colors : array (N, 3), tuple (3,) or colormap + colors : array (N, 3), tuple (3,), array (K,), array (X, Y, Z) + opacity : float linewidth : float tube_sides : int @@ -249,28 +250,13 @@ def line(lines, colors=None, opacity=1, linewidth=1, Parameters ------------ - lines : list of arrays representing lines as 3d points for example - lines = [np.random.rand(10,3),np.random.rand(20,3)] - represents 2 lines the first with 10 points and the second with - 20 points in x,y,z coordinates. + lines : list of arrays + colors : array, shape (N,3) Colormap where every triplet is encoding red, green and blue e.g. - :: - r1,g1,b1 - r2,g2,b2 - ... - rN,gN,bN - - where - - :: - 0= Date: Tue, 7 Jul 2015 16:03:38 -0400 Subject: [PATCH 106/242] DOC: Also updated docstrings of line and streamtube --- dipy/viz/actor.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 546a6fc294..d8bb7df3ff 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -130,7 +130,20 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, ---------- lines : list list of N curves represented as 2D ndarrays - colors : array (N, 3), tuple (3,), array (K,), array (X, Y, Z) + + colors : array (N, 3), list of arrays, tuple (3,), array (K,), None + If None then a standard orientation colormap is used for every line. + If one tuple of color is used. Then all streamlines will have the same + colour. + If an array (N, 3) is given, where N is equal to the number of lines. + Then every line is coloured with a different RGB color. + If a list of RGB arrays is given then every point of every line takes + a different color. + If an array (K, ) is given, where K is the number of points of all + lines then these are considered as the values to be used by the + colormap. + If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the + colormap are interpolated automatically using trilinear interpolation. opacity : float linewidth : float @@ -252,8 +265,19 @@ def line(lines, colors=None, opacity=1, linewidth=1, ------------ lines : list of arrays - colors : array, shape (N,3) - Colormap where every triplet is encoding red, green and blue e.g. + colors : array (N, 3), list of arrays, tuple (3,), array (K,), None + If None then a standard orientation colormap is used for every line. + If one tuple of color is used. Then all streamlines will have the same + colour. + If an array (N, 3) is given, where N is equal to the number of lines. + Then every line is coloured with a different RGB color. + If a list of RGB arrays is given then every point of every line takes + a different color. + If an array (K, ) is given, where K is the number of points of all + lines then these are considered as the values to be used by the + colormap. + If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the + colormap are interpolated automatically using trilinear interpolation. opacity : float, optional From 0e40b7b8172ead81b9195f9e7e962ffbecfc414d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 16:53:25 -0400 Subject: [PATCH 107/242] BF: vtkLOD actor was not being using in line --- dipy/viz/actor.py | 4 ++-- dipy/viz/tests/test_fvtk_actors.py | 33 ++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index d8bb7df3ff..f339a7dc57 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -186,7 +186,7 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, See Also -------- - dipy.viz.fvtk.line + dipy.viz.actor.line """ # Poly data with lines and colors poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) @@ -340,7 +340,7 @@ def line(lines, colors=None, opacity=1, linewidth=1, else: actor = vtk.vtkActor() - actor = vtk.vtkActor() + # actor = vtk.vtkActor() actor.SetMapper(poly_mapper) actor.GetProperty().SetLineWidth(linewidth) actor.GetProperty().SetOpacity(opacity) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 20577eebf4..4918057196 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -110,8 +110,37 @@ def test_bundle_maps(): npt.assert_almost_equal(report.actors, 1) # window.show(renderer) + renderer.clear() + + nb_points = np.sum([len(b) for b in bundle]) + values = 100 * np.random.rand(nb_points) + # values[:nb_points/2] = 0 + + line = actor.streamtube(bundle, values, linewidth=0.1, lookup_colormap=lut) + renderer.add(line) + # window.show(renderer) + + report = window.analyze_renderer(renderer) + npt.assert_equal(report.actors_classnames[0], 'vtkLODActor') + + renderer.clear() + + colors = np.random.rand(nb_points, 3) + # values[:nb_points/2] = 0 + + line = actor.line(bundle, colors, linewidth=2) + renderer.add(line) + # window.show(renderer) + + report = window.analyze_renderer(renderer) + npt.assert_equal(report.actors_classnames[0], 'vtkLODActor') + # window.show(renderer) + + arr = window.snapshot(renderer) + report2 = window.analyze_snapshot(arr) + npt.assert_equal(report2.objects, 1) + + if __name__ == "__main__": npt.run_module_suite() - # test_bundle_maps() - # test_streamtube_and_line_actors() From 3df5359aad552ad1faa6f4fb35b19a02a6f5e70c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 7 Jul 2015 16:58:14 -0400 Subject: [PATCH 108/242] Pep8 --- dipy/viz/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 0edfc9f929..f493beffc7 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -131,7 +131,7 @@ def trilinear_interp(input_array, indices): """ Evaluate the input_array data at the given indices """ - if input_array.ndim <= 2 or input_array.ndim >= 5: + if input_array.ndim <= 2 or input_array.ndim >= 5: raise ValueError("Input array can only be 3d or 4d") x_indices = indices[:, 0] From 5977c3180c9962f5142fa1b92dd3859aa42dcfb5 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Jul 2015 16:56:12 -0400 Subject: [PATCH 109/242] Replacing with map_coordinates --- dipy/viz/tests/test_fvtk_utils.py | 83 +++++++++++++++++++++++++++++++ dipy/viz/utils.py | 55 ++++++++------------ 2 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 dipy/viz/tests/test_fvtk_utils.py diff --git a/dipy/viz/tests/test_fvtk_utils.py b/dipy/viz/tests/test_fvtk_utils.py new file mode 100644 index 0000000000..376f2d40bb --- /dev/null +++ b/dipy/viz/tests/test_fvtk_utils.py @@ -0,0 +1,83 @@ +import numpy as np +import numpy.testing as npt + + +def trilinear_interp(input_array, indices): + """ Evaluate the input_array data at the given indices + """ + + if input_array.ndim <= 2 or input_array.ndim >= 5: + raise ValueError("Input array can only be 3d or 4d") + + x_indices = indices[:, 0] + y_indices = indices[:, 1] + z_indices = indices[:, 2] + + x0 = x_indices.astype(np.integer) + y0 = y_indices.astype(np.integer) + z0 = z_indices.astype(np.integer) + x1 = x0 + 1 + y1 = y0 + 1 + z1 = z0 + 1 + + # Check if xyz1 is beyond array boundary: + x1[np.where(x1 == input_array.shape[0])] = x0.max() + y1[np.where(y1 == input_array.shape[1])] = y0.max() + z1[np.where(z1 == input_array.shape[2])] = z0.max() + + if input_array.ndim == 3: + x = x_indices - x0 + y = y_indices - y0 + z = z_indices - z0 + + elif input_array.ndim == 4: + x = np.expand_dims(x_indices - x0, axis=1) + y = np.expand_dims(y_indices - y0, axis=1) + z = np.expand_dims(z_indices - z0, axis=1) + + output = (input_array[x0, y0, z0] * (1 - x) * (1 - y) * (1 - z) + + input_array[x1, y0, z0] * x * (1 - y) * (1 - z) + + input_array[x0, y1, z0] * (1 - x) * y * (1-z) + + input_array[x0, y0, z1] * (1 - x) * (1 - y) * z + + input_array[x1, y0, z1] * x * (1 - y) * z + + input_array[x0, y1, z1] * (1 - x) * y * z + + input_array[x1, y1, z0] * x * y * (1 - z) + + input_array[x1, y1, z1] * x * y * z) + + return output + + +def test_trilinear_interp(): + + A = np.zeros((5, 5, 5)) + A[2, 2, 2] = 1 + + indices = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [1.5, 1.5, 1.5]]) + + values = trilinear_interp(A, indices) + print(values) + + values2 = map_coordinates(A, indices.T, order=1) + print(values2) + + npt.assert_almost_equal(values, values2) + + B = np.zeros((5, 5, 5, 3)) + B[2, 2, 2] = np.array([1, 1, 1]) + + values = trilinear_interp(B, indices) + print(values) + + values_4d = [] + for i in range(B.shape[-1]): + values_tmp = map_coordinates(B[..., i], indices.T, order=1) + values_4d.append(values_tmp) + values_4d = np.ascontiguousarray(np.array(values_4d).T) + + print(values_4d) + npt.assert_almost_equal(values, values_4d) + + +if __name__ == '__main__': + + test_trilinear_interp() \ No newline at end of file diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index f493beffc7..4be491de0f 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -3,6 +3,7 @@ import numpy as np from dipy.core.ndindex import ndindex +from scipy.ndimage import map_coordinates # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -129,47 +130,31 @@ def rotation_from_lines(lines, use_line_dir=True, use_full_eig=False): def trilinear_interp(input_array, indices): """ Evaluate the input_array data at the given indices + + Parameters + ---------- + input_array : ndarray, + 3D or 4D array + + Returns + ------- + output : ndarray + 1D or 2D array """ if input_array.ndim <= 2 or input_array.ndim >= 5: raise ValueError("Input array can only be 3d or 4d") - x_indices = indices[:, 0] - y_indices = indices[:, 1] - z_indices = indices[:, 2] - - x0 = x_indices.astype(np.integer) - y0 = y_indices.astype(np.integer) - z0 = z_indices.astype(np.integer) - x1 = x0 + 1 - y1 = y0 + 1 - z1 = z0 + 1 - - # Check if xyz1 is beyond array boundary: - x1[np.where(x1 == input_array.shape[0])] = x0.max() - y1[np.where(y1 == input_array.shape[1])] = y0.max() - z1[np.where(z1 == input_array.shape[2])] = z0.max() - if input_array.ndim == 3: - x = x_indices - x0 - y = y_indices - y0 - z = z_indices - z0 - - elif input_array.ndim == 4: - x = np.expand_dims(x_indices - x0, axis=1) - y = np.expand_dims(y_indices - y0, axis=1) - z = np.expand_dims(z_indices - z0, axis=1) - - output = (input_array[x0, y0, z0] * (1 - x) * (1 - y) * (1 - z) + - input_array[x1, y0, z0] * x * (1 - y) * (1 - z) + - input_array[x0, y1, z0] * (1 - x) * y * (1-z) + - input_array[x0, y0, z1] * (1 - x) * (1 - y) * z + - input_array[x1, y0, z1] * x * (1 - y) * z + - input_array[x0, y1, z1] * (1 - x) * y * z + - input_array[x1, y1, z0] * x * y * (1 - z) + - input_array[x1, y1, z1] * x * y * z) - - return output + return map_coordinates(input_array, indices.T, order=1) + + if input_array.ndim == 4: + values_4d = [] + for i in range(input_array.shape[-1]): + values_tmp = map_coordinates(input_array[..., i], + indices.T, order=1) + values_4d.append(values_tmp) + return np.ascontiguousarray(np.array(values_4d).T) def rescale_to_uint8(data): From 7db5b9d29a116f0e6305c10f4b5e3c477547079d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Jul 2015 18:44:45 -0400 Subject: [PATCH 110/242] TEST: updated map_coordinates 3d and 4d --- dipy/viz/actor.py | 4 ++-- dipy/viz/tests/test_fvtk_utils.py | 25 +++++++------------------ dipy/viz/utils.py | 4 +++- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index f339a7dc57..94c39e1918 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -4,7 +4,7 @@ from dipy.viz.colormap import line_colors from dipy.viz.utils import numpy_to_vtk_points, numpy_to_vtk_colors -from dipy.viz.utils import set_input, trilinear_interp +from dipy.viz.utils import set_input, map_coordinates_3d_4d from dipy.core.ndindex import ndindex # Conditional import machinery for vtk @@ -431,7 +431,7 @@ def lines_to_vtk_polydata(lines, colors=None): vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) else: # colormap # get colors for each vertex - cols_arr = trilinear_interp(cols_arr, points_array) + cols_arr = map_coordinates_3d_4d(cols_arr, points_array) vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) is_colormap = True diff --git a/dipy/viz/tests/test_fvtk_utils.py b/dipy/viz/tests/test_fvtk_utils.py index 376f2d40bb..91fd76b1ad 100644 --- a/dipy/viz/tests/test_fvtk_utils.py +++ b/dipy/viz/tests/test_fvtk_utils.py @@ -1,8 +1,9 @@ import numpy as np import numpy.testing as npt +from dipy.viz.utils import map_coordinates_3d_4d -def trilinear_interp(input_array, indices): +def trilinear_interp_numpy(input_array, indices): """ Evaluate the input_array data at the given indices """ @@ -54,30 +55,18 @@ def test_trilinear_interp(): indices = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [1.5, 1.5, 1.5]]) - values = trilinear_interp(A, indices) - print(values) - - values2 = map_coordinates(A, indices.T, order=1) - print(values2) - + values = trilinear_interp_numpy(A, indices) + values2 = map_coordinates_3d_4d(A, indices) npt.assert_almost_equal(values, values2) B = np.zeros((5, 5, 5, 3)) B[2, 2, 2] = np.array([1, 1, 1]) - values = trilinear_interp(B, indices) - print(values) - - values_4d = [] - for i in range(B.shape[-1]): - values_tmp = map_coordinates(B[..., i], indices.T, order=1) - values_4d.append(values_tmp) - values_4d = np.ascontiguousarray(np.array(values_4d).T) - - print(values_4d) + values = trilinear_interp_numpy(B, indices) + values_4d = map_coordinates_3d_4d(B, indices) npt.assert_almost_equal(values, values_4d) if __name__ == '__main__': - test_trilinear_interp() \ No newline at end of file + npt.run_module_suite() \ No newline at end of file diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 4be491de0f..31cb49dfef 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -128,13 +128,15 @@ def rotation_from_lines(lines, use_line_dir=True, use_full_eig=False): return transform -def trilinear_interp(input_array, indices): +def map_coordinates_3d_4d(input_array, indices): """ Evaluate the input_array data at the given indices + using trilinear interpolation Parameters ---------- input_array : ndarray, 3D or 4D array + indices : ndarray Returns ------- From e98db4f4c8f0954dd255068fe78486b2f3823bfb Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Jul 2015 18:49:48 -0400 Subject: [PATCH 111/242] RF: removed unused function --- dipy/viz/utils.py | 48 ----------------------------------------------- 1 file changed, 48 deletions(-) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 31cb49dfef..1c9a1b09f6 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -80,54 +80,6 @@ def evec_from_lines(lines, use_line_dir=True): return e_vec -def rotation_from_lines(lines, use_line_dir=True, use_full_eig=False): - """ Get the rotation from lines directions in vtk.vtkTransform() object - - if use_line_dir is set to False - only use the points position information - - if use_full_eig is set to True - the rotation will be the full eigen_vector matrix - (not only the Yaw and Pitch) - - Example - ---------- - >>> camera = renderer.GetActiveCamera() - >>> rotation = rotation_from_lines(lines) - >>> camera.ApplyTransform(rotation) - >>> fvtk.show(renderer) - """ - e_vec = evec_from_lines(lines, use_line_dir) - - matrix = vtk.vtkMatrix4x4() - - if use_full_eig: - for (i, j) in ndindex((3, 3)) : - matrix.SetElement(j, i, e_vec[i,j]) - - else: - v1 = e_vec[2] - v2 = np.array([0,0,1]) - v3 = np.cross(v1,v2) - v3 = v3/(np.sqrt(np.sum(v3**2))) - v4 = np.cross(v3,v1) - v4 = v4/(np.sqrt(np.sum(v4**2))) - - m1 = np.array([v1,v4,v3]) - cos = np.dot(v2,v1) - sin = np.dot(v2,v4) - m2 = np.array([[cos,sin,0],[-sin,cos,0],[0,0,1]]) - - m = np.dot( np.dot(m1.T,m2), m1) - - for (i, j) in ndindex((3, 3)) : - matrix.SetElement(i, j, m[i,j]) - - transform = vtk.vtkTransform() - transform.SetMatrix(matrix) - return transform - - def map_coordinates_3d_4d(input_array, indices): """ Evaluate the input_array data at the given indices using trilinear interpolation From 4df61356fa536f864e4fa77cec322ea9013403d5 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Jul 2015 19:02:27 -0400 Subject: [PATCH 112/242] RF: minor corrections --- dipy/viz/tests/test_fvtk_window.py | 2 +- dipy/viz/utils.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 93200f1807..56db8a7030 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -10,7 +10,7 @@ def test_renderer(): ren = window.Renderer() # background color for renderer (1, 0.5, 0) - # 0.01 added here to remove numerical errors when moving from float + # 0.001 added here to remove numerical errors when moving from float # to int values bg_float = (1, 0.501, 0) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 1c9a1b09f6..4f2ba30615 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -2,7 +2,6 @@ from __future__ import division, print_function, absolute_import import numpy as np -from dipy.core.ndindex import ndindex from scipy.ndimage import map_coordinates # Conditional import machinery for vtk From 569de4fb9d9c4d5860ecc55584e5c7ffb5512c05 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 8 Jul 2015 19:23:36 -0400 Subject: [PATCH 113/242] NF: Added set/get value in slider widget --- dipy/viz/widget.py | 10 ++++++++-- doc/examples/advanced_interactive_viz.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 3d639a30fe..3be80f4788 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -23,8 +23,8 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, Used to process events and handle them to the slider. Can also be given by the attribute ``ShowManager.iren``. ren : vtkRenderer or Renderer - Used to update the slider's position when the window changes. Can also be given - by the ``ShowManager.ren`` attribute. + Used to update the slider's position when the window changes. Can also + be given by the ``ShowManager.ren`` attribute. callback : function Function that has at least ``obj`` and ``event`` as parameters. It will be called when the slider's bar has changed. @@ -93,6 +93,12 @@ def place(self, renderer): slider_rep.GetPoint1Coordinate().SetValue(coord2[0] - size[0], coord2[1] - size[1]) + def set_value(self, value): + return self.GetSliderRepresentation().SetValue(value) + + def get_value(self): + return self.GetSliderRepresentation().GetValue() + slider = SliderWidget() slider.SetInteractor(iren) slider.SetRepresentation(slider_rep) diff --git a/doc/examples/advanced_interactive_viz.py b/doc/examples/advanced_interactive_viz.py index a3a8b79bf0..691e5a25e9 100644 --- a/doc/examples/advanced_interactive_viz.py +++ b/doc/examples/advanced_interactive_viz.py @@ -119,7 +119,7 @@ """ def change_slice(obj, event): - z = int(np.round(obj.GetSliderRepresentation().GetValue())) + z = int(np.round(obj.get_value())) image_actor.display_extent(0, shape[0] - 1, 0, shape[1] - 1, z, z) From 5dd66beae062c5f83b50c23079684b494279f605 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Jul 2015 10:59:49 -0400 Subject: [PATCH 114/242] Trying to correct tube width change when window is resized --- dipy/viz/widget.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 3be80f4788..1833990f9f 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -93,6 +93,21 @@ def place(self, renderer): slider_rep.GetPoint1Coordinate().SetValue(coord2[0] - size[0], coord2[1] - size[1]) + old_coord2 * 0.04/new_coord2 + + length = 0.04 + width = 0.04 + cap_length = 0.01 + cap_width = 0.01 + tube_width = 0.005 + + slider_rep.SetSliderLength(length) + slider_rep.SetSliderWidth(width) + slider_rep.SetEndCapLength(cap_length) + slider_rep.SetEndCapWidth(cap_width) + slider_rep.SetTubeWidth(tube_width) + slider_rep.SetLabelFormat(label_format) + def set_value(self, value): return self.GetSliderRepresentation().SetValue(value) From 35f433cc39cc3a9c5e869e9baa6d48e6fb379b48 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Jul 2015 12:09:23 -0400 Subject: [PATCH 115/242] Slider width and length will keep their size when window is resized --- dipy/viz/widget.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 1833990f9f..d33d6c119c 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -66,6 +66,7 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, slider_rep.GetPoint1Coordinate().SetValue(coord2[0] - size[0], coord2[1] - size[1]) + initial_window_size = ren.GetSize() length = 0.04 width = 0.04 cap_length = 0.01 @@ -81,32 +82,24 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, class SliderWidget(vtk.vtkSliderWidget): - def place(self, renderer): + def place(self, ren): slider_rep = self.GetRepresentation() coord2_norm = slider_rep.GetPoint2Coordinate() coord2_norm.SetCoordinateSystemToNormalizedDisplay() coord2_norm.SetValue(*right_normalized_pos) - coord2 = coord2_norm.GetComputedDisplayValue(renderer) + coord2 = coord2_norm.GetComputedDisplayValue(ren) slider_rep.GetPoint1Coordinate().SetCoordinateSystemToDisplay() slider_rep.GetPoint1Coordinate().SetValue(coord2[0] - size[0], coord2[1] - size[1]) - old_coord2 * 0.04/new_coord2 - - length = 0.04 - width = 0.04 - cap_length = 0.01 - cap_width = 0.01 - tube_width = 0.005 + window_size = ren.GetSize() + length = initial_window_size[0] * 0.04 / window_size[0] + width = initial_window_size[1] * 0.04 / window_size[1] slider_rep.SetSliderLength(length) slider_rep.SetSliderWidth(width) - slider_rep.SetEndCapLength(cap_length) - slider_rep.SetEndCapWidth(cap_width) - slider_rep.SetTubeWidth(tube_width) - slider_rep.SetLabelFormat(label_format) def set_value(self, value): return self.GetSliderRepresentation().SetValue(value) From f6d565a8230d1ce4458ae2ce2a63ec8d8dfbef83 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 9 Jul 2015 17:29:27 -0400 Subject: [PATCH 116/242] BF: save_dialog parameters corrected --- dipy/viz/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 85f70280a8..d5a89e5094 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -241,8 +241,8 @@ def key_press_standard(obj, event): file_types = (("PNG file", "*.png"), ("All Files", "*.*")) filepath = save_file_dialog(initial_file='dipy.png', - default_extension='.png', - filetypes=file_types) + default_ext='.png', + file_types=file_types) if filepath == '': print('No file was provided in the dialog') else: From 47cf544b7af709ce7e2e48652f21db91124c6d3d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Jul 2015 15:03:31 -0400 Subject: [PATCH 117/242] NF: added copy method to slice actor --- dipy/viz/actor.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 94c39e1918..1aff044982 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,7 +21,7 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() -def slice(data, affine=None, opacity=1., lookup_colormap=None): +def slice(data, affine=None, value_range=None, opacity=1., lookup_colormap=None): """ Cuts 3D volumes into images Parameters @@ -45,7 +45,10 @@ def slice(data, affine=None, opacity=1., lookup_colormap=None): """ - vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) + if value_range is None: + vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) + else: + vol = np.interp(data, xp=[value_range[0], value_range[1]], fp=[0, 255]) vol = vol.astype('uint8') im = vtk.vtkImageData() @@ -105,14 +108,30 @@ class ImageActor(vtk.vtkImageActor): def input_connection(self, output_port): self.GetMapper().SetInputConnection(output_port) + self.output_port = output_port def display_extent(self, x1, x2, y1, y2, z1, z2): self.SetDisplayExtent(x1, x2, y1, y2, z1, z2) self.Update() + self.x1 = x1 + self.x2 = x2 + self.y1 = y1 + self.y2 = y2 + self.z1 = z1 + self.z2 = z2 def opacity(self, value): self.GetProperty().SetOpacity(value) + def copy(self): + im_actor = ImageActor() + im_actor.input_connection(self.output_port) + im_actor.SetDisplayExtent(self.x1, self.x2, + self.y1, self.y2, + self.z1, self.z2) + im_actor.opacity(opacity) + return im_actor + image_actor = ImageActor() image_actor.input_connection(plane_colors.GetOutputPort()) image_actor.display_extent(x1, x2, y1, y2, z2/2, z2/2) From d5e8705aebef85493871fd78caf5295fbf09a083 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Jul 2015 15:04:32 -0400 Subject: [PATCH 118/242] DOC: added new tutorial about volume vizualization --- doc/examples/viz_slice.py | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 doc/examples/viz_slice.py diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py new file mode 100644 index 0000000000..e6f50012ed --- /dev/null +++ b/doc/examples/viz_slice.py @@ -0,0 +1,65 @@ + +""" +========================== +Simple image visualization +========================== +""" +import numpy as np +import nibabel as nib +from dipy.data import fetch_sherbrooke_3shell, read_sherbrooke_3shell +from dipy.viz import window, actor +from dipy.core.histeq import histeq +from dipy.align.reslice import reslice + +#fetch_sherbrooke_3shell() +#img, gtab = read_sherbrooke_3shell() + + +# fraw = '/home/eleftherios/Data/MPI_Elef/fa_1x1x1.nii.gz' +fraw = '/home/eleftherios/Data/Jorge_Rudas/tensor_fa.nii.gz' +img = nib.load(fraw) + +# import nibabel as nib + + + +data = img.get_data() +affine = img.get_affine() +zooms = img.get_header().get_zooms()[:3] +new_zooms = (2, 2, 2.) + +print(affine) +print(data.shape) + +data, affine = reslice(data, affine, zooms, new_zooms) + +print(affine) +print(data.shape) + +renderer = window.Renderer() + +# S0 = data[..., 0] + +vol = histeq(data) + +world_coord = True +if world_coord: + slice_actor = actor.slice(vol, affine) +else: + slice_actor = actor.slice(vol) + +renderer.add(slice_actor) + +slice_actor2 = slice_actor.copy() + +# slice_actor2.display_extent(64, 64, 0, 127, 0, 59) +# slice_actor2.display_extent(186/2, 186/2, 0, 231, 0, 185) +# slice_actor2.display_extent(120/2, 120/2, 0, 119, 0, 74) +slice_actor2.display_extent(data.shape[0]/2, data.shape[0]/2, + 0, data.shape[1] - 1, 0, data.shape[2] - 1) + +renderer.background((1, 1, 1)) + +renderer.add(slice_actor2) + +window.show(renderer) From d2f281ea0be4f0b7f264c764b6f655d7e375137a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 10 Jul 2015 22:36:01 -0400 Subject: [PATCH 119/242] BF: display extent was not updated after reslicing. Now looks good --- dipy/viz/actor.py | 27 +++++++++++++++++---------- doc/examples/viz_slice.py | 31 ++++++++++++++++--------------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 1aff044982..8d6c4c4ceb 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -98,6 +98,9 @@ def slice(data, affine=None, value_range=None, opacity=1., lookup_colormap=None) lut = lookup_colormap x1, x2, y1, y2, z1, z2 = im.GetExtent() + print(im.GetExtent()) + print(image_resliced.GetOutput().GetExtent()) + ex1, ex2, ey1, ey2, ez1, ez2 = image_resliced.GetOutput().GetExtent() plane_colors = vtk.vtkImageMapToColors() plane_colors.SetLookupTable(lut) @@ -109,16 +112,22 @@ class ImageActor(vtk.vtkImageActor): def input_connection(self, output_port): self.GetMapper().SetInputConnection(output_port) self.output_port = output_port + self.shape = (ex2 + 1, ey2 + 1, ez2 + 1) def display_extent(self, x1, x2, y1, y2, z1, z2): self.SetDisplayExtent(x1, x2, y1, y2, z1, z2) self.Update() - self.x1 = x1 - self.x2 = x2 - self.y1 = y1 - self.y2 = y2 - self.z1 = z1 - self.z2 = z2 + + def display(self, x=None, y=None, z=None): + if x is None and y is None and z is None: + self.display_extent(ex1, ex2, ey1, ey2, ez2/2, ez2/2) + if x is not None: + self.display_extent(x, x, ey1, ey2, ez1, ez2) + if y is not None: + self.display_extent(ex1, ex2, y, y, ez1, ez2) + if z is not None: + self.display_extent(ex1, ex2, ey1, ey2, z, z) + def opacity(self, value): self.GetProperty().SetOpacity(value) @@ -126,15 +135,13 @@ def opacity(self, value): def copy(self): im_actor = ImageActor() im_actor.input_connection(self.output_port) - im_actor.SetDisplayExtent(self.x1, self.x2, - self.y1, self.y2, - self.z1, self.z2) + im_actor.SetDisplayExtent(*self.GetDisplayExtent()) im_actor.opacity(opacity) return im_actor image_actor = ImageActor() image_actor.input_connection(plane_colors.GetOutputPort()) - image_actor.display_extent(x1, x2, y1, y2, z2/2, z2/2) + image_actor.display() image_actor.opacity(opacity) return image_actor diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index e6f50012ed..3a97675bd1 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -15,26 +15,31 @@ #img, gtab = read_sherbrooke_3shell() -# fraw = '/home/eleftherios/Data/MPI_Elef/fa_1x1x1.nii.gz' -fraw = '/home/eleftherios/Data/Jorge_Rudas/tensor_fa.nii.gz' +fraw = '/home/eleftherios/Data/MPI_Elef/fa_1x1x1.nii.gz' +fraw = '/home/eleftherios/Data/trento_processed/subj_01/MPRAGE_32/rawbet.nii.gz' +fraw = '/home/eleftherios/Data/trento_processed/subj_01/MPRAGE_32/T1_flirt_out.nii.gz' +# fraw = '/home/eleftherios/Data/Jorge_Rudas/tensor_fa.nii.gz' img = nib.load(fraw) # import nibabel as nib - - data = img.get_data() affine = img.get_affine() -zooms = img.get_header().get_zooms()[:3] -new_zooms = (2, 2, 2.) + +affine = np.dot(np.diag([2., 2., 2., 1]), affine) print(affine) print(data.shape) -data, affine = reslice(data, affine, zooms, new_zooms) +reslice = False -print(affine) -print(data.shape) +if reslice: + zooms = img.get_header().get_zooms()[:3] + new_zooms = (2, 2, 2.) + data, affine = reslice(data, affine, zooms, new_zooms) + + print(affine) + print(data.shape) renderer = window.Renderer() @@ -52,14 +57,10 @@ slice_actor2 = slice_actor.copy() -# slice_actor2.display_extent(64, 64, 0, 127, 0, 59) -# slice_actor2.display_extent(186/2, 186/2, 0, 231, 0, 185) -# slice_actor2.display_extent(120/2, 120/2, 0, 119, 0, 74) -slice_actor2.display_extent(data.shape[0]/2, data.shape[0]/2, - 0, data.shape[1] - 1, 0, data.shape[2] - 1) +slice_actor2.display(slice_actor2.shape[0]/2, None, None) renderer.background((1, 1, 1)) -renderer.add(slice_actor2) +#renderer.add(slice_actor2) window.show(renderer) From 323b9cbec7a2bd35e97c8ced4a9e7ac925f12e5a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 12 Jul 2015 15:52:23 -0400 Subject: [PATCH 120/242] NF: slice has also value range parameter --- dipy/viz/actor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 8d6c4c4ceb..ec0537bcc1 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,7 +21,8 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() -def slice(data, affine=None, value_range=None, opacity=1., lookup_colormap=None): +def slice(data, affine=None, value_range=None, opacity=1., + lookup_colormap=None): """ Cuts 3D volumes into images Parameters @@ -30,6 +31,9 @@ def slice(data, affine=None, value_range=None, opacity=1., lookup_colormap=None) A 3D volume as a numpy array. affine : array, shape (3, 3) Grid to space (usually RAS 1mm) transformation matrix + value_range : None or tuple (2,) + If None then the values will be interpolated to (0, 255) from + (min, max). Otherwise from (value_range[0], value_range[1]). opacity : float Opacity of 0 means completely transparent and 1 completely visible. lookup_colormap : vtkLookupTable @@ -44,6 +48,8 @@ def slice(data, affine=None, value_range=None, opacity=1., lookup_colormap=None) coordinates as calculated by the affine parameter. """ + if data.ndim < 3 or data.ndim > 4: + raise ValueError('Only 3D or 4D data are supported') if value_range is None: vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) @@ -128,7 +134,6 @@ def display(self, x=None, y=None, z=None): if z is not None: self.display_extent(ex1, ex2, ey1, ey2, z, z) - def opacity(self, value): self.GetProperty().SetOpacity(value) From 66fa99b159d55541038e552f3e03f51f54ae1f0e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 12 Jul 2015 15:55:47 -0400 Subject: [PATCH 121/242] Slice works only with 3D data --- dipy/viz/actor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index ec0537bcc1..14f322ef6b 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -48,8 +48,8 @@ def slice(data, affine=None, value_range=None, opacity=1., coordinates as calculated by the affine parameter. """ - if data.ndim < 3 or data.ndim > 4: - raise ValueError('Only 3D or 4D data are supported') + if data.ndim != 3: + raise ValueError('Only 3D arrays are currently supported.') if value_range is None: vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) From a09d813649375dc159bcf6e1daf98ecc4cf4d980 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 12 Jul 2015 16:02:26 -0400 Subject: [PATCH 122/242] DOC: updated simple visualization example. Needs more text. --- doc/examples/viz_slice.py | 56 +++++++++++++-------------------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 3a97675bd1..f6ca6dd21d 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -1,57 +1,39 @@ """ -========================== -Simple image visualization -========================== +============================ +Simple volume visualization +============================ + +Here we present an example + """ -import numpy as np +import os import nibabel as nib -from dipy.data import fetch_sherbrooke_3shell, read_sherbrooke_3shell +from dipy.data import fetch_bundles_2_subjects from dipy.viz import window, actor -from dipy.core.histeq import histeq -from dipy.align.reslice import reslice - -#fetch_sherbrooke_3shell() -#img, gtab = read_sherbrooke_3shell() -fraw = '/home/eleftherios/Data/MPI_Elef/fa_1x1x1.nii.gz' -fraw = '/home/eleftherios/Data/trento_processed/subj_01/MPRAGE_32/rawbet.nii.gz' -fraw = '/home/eleftherios/Data/trento_processed/subj_01/MPRAGE_32/T1_flirt_out.nii.gz' -# fraw = '/home/eleftherios/Data/Jorge_Rudas/tensor_fa.nii.gz' -img = nib.load(fraw) +fetch_bundles_2_subjects() -# import nibabel as nib +fname = os.path.join(os.path.expanduser('~'), '.dipy', 'exp_bundles_and_maps', + 'bundles_2_subjects', 'subj_1', 't1_warped.nii.gz') +img = nib.load(fname) data = img.get_data() affine = img.get_affine() -affine = np.dot(np.diag([2., 2., 2., 1]), affine) - -print(affine) -print(data.shape) - -reslice = False - -if reslice: - zooms = img.get_header().get_zooms()[:3] - new_zooms = (2, 2, 2.) - data, affine = reslice(data, affine, zooms, new_zooms) - - print(affine) - print(data.shape) - renderer = window.Renderer() -# S0 = data[..., 0] +mean, std = data[data > 0].mean(), data[data > 0].std() -vol = histeq(data) +value_range = (mean - 0.5 * std, mean + 1.5 * std) world_coord = True + if world_coord: - slice_actor = actor.slice(vol, affine) + slice_actor = actor.slice(data, affine, value_range) else: - slice_actor = actor.slice(vol) + slice_actor = actor.slice(data, value_range=value_range) renderer.add(slice_actor) @@ -61,6 +43,6 @@ renderer.background((1, 1, 1)) -#renderer.add(slice_actor2) +renderer.add(slice_actor2) -window.show(renderer) +window.show(renderer, size=(600, 600)) From cad26e903b27f52164a3375b5e831e7fb3ee8578 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 12 Jul 2015 18:21:48 -0400 Subject: [PATCH 123/242] DOC: updated slicing example --- doc/examples/viz_slice.py | 66 +++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index f6ca6dd21d..f86c3b6acb 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -4,45 +4,91 @@ Simple volume visualization ============================ -Here we present an example +Here we present an example for visualizing slices from 3D images. """ + import os import nibabel as nib from dipy.data import fetch_bundles_2_subjects from dipy.viz import window, actor +""" +Let's download and load a T1. +""" + fetch_bundles_2_subjects() fname = os.path.join(os.path.expanduser('~'), '.dipy', 'exp_bundles_and_maps', 'bundles_2_subjects', 'subj_1', 't1_warped.nii.gz') + img = nib.load(fname) data = img.get_data() affine = img.get_affine() +""" +Create a Renderer object which holds all the actors which we want to visualize. +""" + renderer = window.Renderer() +renderer.background((1, 1, 1)) -mean, std = data[data > 0].mean(), data[data > 0].std() +""" +The T1 has usually a higher range of values than what can be visualized in an +image. We can set the range that we would like to see. +""" +mean, std = data[data > 0].mean(), data[data > 0].std() value_range = (mean - 0.5 * std, mean + 1.5 * std) -world_coord = True +""" +The ``slice`` function will read data and resample the data using an affine +transformation matrix. The default behavior of this function is to show the +the middle slice of the last dimension of the resampled data. +""" + +slice_actor = actor.slice(data, affine, value_range) -if world_coord: - slice_actor = actor.slice(data, affine, value_range) -else: - slice_actor = actor.slice(data, value_range=value_range) +""" +The ``slice_actor`` contains an axial slice. +""" renderer.add(slice_actor) +""" +The same actor can show any different slice from the given data using its +``display`` function. However, if we want to show multiple slices we need to +copy the actor first. +""" + slice_actor2 = slice_actor.copy() -slice_actor2.display(slice_actor2.shape[0]/2, None, None) +""" +Now we have a new ``slice_actor`` which displays the middle slice of saggital +plane. +""" -renderer.background((1, 1, 1)) +slice_actor2.display(slice_actor2.shape[0]/2, None, None) renderer.add(slice_actor2) -window.show(renderer, size=(600, 600)) +""" +In order to interact with the data you will need to uncomment the line below. +""" + +# window.show(renderer, size=(600, 600)) + +""" +Otherwise, you can save a screenshot using the following command. +""" + +window.snapshot(renderer, 'slices.png', size=(600, 600)) + +""" +.. figure:: slices.png + :align: center + + **Simple slice viewer**. +""" \ No newline at end of file From 72105654ea25298be283afafbb691deff522dad3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 11:20:41 -0400 Subject: [PATCH 124/242] DOC: new tutorial done --- dipy/viz/actor.py | 2 -- doc/examples/viz_slice.py | 52 +++++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 14f322ef6b..869e307f0b 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -104,8 +104,6 @@ def slice(data, affine=None, value_range=None, opacity=1., lut = lookup_colormap x1, x2, y1, y2, z1, z2 = im.GetExtent() - print(im.GetExtent()) - print(image_resliced.GetOutput().GetExtent()) ex1, ex2, ey1, ey2, ez1, ez2 = image_resliced.GetOutput().GetExtent() plane_colors = vtk.vtkImageMapToColors() diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index f86c3b6acb..b9652bca6b 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -1,7 +1,7 @@ """ ============================ -Simple volume visualization +Simple volume slicing ============================ Here we present an example for visualizing slices from 3D images. @@ -20,11 +20,12 @@ fetch_bundles_2_subjects() -fname = os.path.join(os.path.expanduser('~'), '.dipy', 'exp_bundles_and_maps', - 'bundles_2_subjects', 'subj_1', 't1_warped.nii.gz') +fname_t1 = os.path.join(os.path.expanduser('~'), '.dipy', + 'exp_bundles_and_maps', 'bundles_2_subjects', + 'subj_1', 't1_warped.nii.gz') -img = nib.load(fname) +img = nib.load(fname_t1) data = img.get_data() affine = img.get_affine() @@ -91,4 +92,45 @@ :align: center **Simple slice viewer**. -""" \ No newline at end of file + +It is also possible to set the colormap of your preference. Here we are loading +an FA image and showing it in a non-standard way using an HSV colormap. +""" + +fname_fa = os.path.join(os.path.expanduser('~'), '.dipy', + 'exp_bundles_and_maps', 'bundles_2_subjects', + 'subj_1', 'fa_1x1x1.nii.gz') + +img = nib.load(fname_fa) +fa = img.get_data() + +""" +Notice here how the scale range is (0, 255) and not (0, 1) which is the usual +range of FA values. +""" + +lut = actor.colormap_lookup_table(scale_range=(0, 255), + hue_range=(0.4, 1.), + saturation_range=(1, 1.), + value_range=(0., 1.)) + +""" +This is because the lookup table is applied in the slice after interpolating +to (0, 255). +""" + +fa_actor = actor.slice(fa, affine, lookup_colormap=lut) + +renderer.clear() +renderer.add(fa_actor) + +# window.show(renderer, size=(600, 600)) + +window.snapshot(renderer, 'slices_lut.png', size=(600, 600)) + +""" +.. figure:: slices_lut.png + :align: center + + **Simple slice viewer with an HSV colormap**. +""" From bd28e7f38a91ee9e00094d780a49a9462c678ba6 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 14:09:21 -0400 Subject: [PATCH 125/242] RF: renamed tutorial --- doc/examples/{advanced_interactive_viz.py => viz_advanced.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename doc/examples/{advanced_interactive_viz.py => viz_advanced.py} (99%) diff --git a/doc/examples/advanced_interactive_viz.py b/doc/examples/viz_advanced.py similarity index 99% rename from doc/examples/advanced_interactive_viz.py rename to doc/examples/viz_advanced.py index 691e5a25e9..c07527ebaa 100644 --- a/doc/examples/advanced_interactive_viz.py +++ b/doc/examples/viz_advanced.py @@ -164,8 +164,8 @@ def win_callback(obj, event): the available 3D and 2D objects. """ -show_m.render() -show_m.start() +# show_m.render() +# show_m.start() From edbc850b6affbb019543bb7465a29d600f4a4476 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 14:11:51 -0400 Subject: [PATCH 126/242] New tutorial about visualization of bundles --- doc/examples/viz_bundles.py | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 doc/examples/viz_bundles.py diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py new file mode 100644 index 0000000000..6a62281663 --- /dev/null +++ b/doc/examples/viz_bundles.py @@ -0,0 +1,82 @@ +""" +======================================= +Visualize bundle and metrics on bundles +======================================= + +""" + +import numpy as np +import nibabel as nib +from dipy.viz import window, actor +from dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects + +fetch_bundles_2_subjects() +dix = read_bundles_2_subjects() + +fa = dix['fa'] +affine = dix['affine'] +bundle = dix['cst.right'] + +renderer = window.Renderer() + +stream_actor = actor.line(bundle) + +renderer.add(stream_actor) + +window.show(renderer) + +renderer.clear() + +stream_actor2 = actor.line(bundle, fa) + +renderer.add(stream_actor2) + +window.show(renderer) + +1/0 + +""" +Load colormap (FA map for this example) +""" +fa_file = nib.load(dname + "../fa_1x1x1.nii.gz") +fa_colormap = fa_file.get_data() +colormap_affine = fa_file.get_affine() + +""" +4. Transform lines in the same coordinates +""" +transfo = np.linalg.inv(colormap_affine) +lines = [nib.affines.apply_affine(transfo, s) for s in lines] + +""" +5. Generate and render fvtk streamline with scalar_bar +""" +width = 0.1 +fvtk_tubes = vtk_a.streamtube(lines, fa_colormap, linewidth=width) +scalar_bar = vtk_a.scalar_bar(fvtk_tubes.GetMapper().GetLookupTable()) + +renderer = fvtk.ren() +fvtk.add(renderer, fvtk_tubes) +fvtk.add(renderer, scalar_bar) +fvtk.show(renderer) + +""" +6. Generate and render fvtk streamline with scalar_bar +""" + +saturation = [0.0, 1.0] # white to red +hue = [0.0, 0.0] # Red only + +lut_cmap = vtk_a.colormap_lookup_table(hue_range=hue, saturation_range=saturation) + +fvtk_tubes = vtk_a.streamtube(lines, fa_colormap, linewidth=width, + lookup_colormap=lut_cmap) + +scalar_bar = vtk_a.scalar_bar(fvtk_tubes.GetMapper().GetLookupTable()) + +renderer = fvtk.ren() +fvtk.add(renderer, fvtk_tubes) +fvtk.add(renderer, scalar_bar) +fvtk.show(renderer) + + From bb739eb8e9fabee0d8e8492c21b174fc99afaea1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 14:14:28 -0400 Subject: [PATCH 127/242] DOC: docstring corrected --- dipy/tracking/streamline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dipy/tracking/streamline.py b/dipy/tracking/streamline.py index 9894889a4c..5f58efb4cc 100644 --- a/dipy/tracking/streamline.py +++ b/dipy/tracking/streamline.py @@ -84,6 +84,8 @@ def transform_streamlines(streamlines, mat): ---------- streamlines : list List of 2D ndarrays of shape[-1]==3 + mat : array, (4, 4) + transformation matrix Returns ------- From 662ca077a8e3a46b8c726b81508eb8a9b10d641f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 14:19:14 -0400 Subject: [PATCH 128/242] Linked of new tutorials to the website --- doc/examples/valid_examples.txt | 4 +++- doc/examples_index.rst | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index 1888f427b6..6e228747f1 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -37,4 +37,6 @@ bundle_registration.py tracking_tissue_classifier.py piesno.py - advanced_interactive_viz.py + viz_advanced.py + viz_slice.py + viz_bundle_maps.py diff --git a/doc/examples_index.rst b/doc/examples_index.rst index d15a7f48f2..719c190f3e 100644 --- a/doc/examples_index.rst +++ b/doc/examples_index.rst @@ -194,8 +194,9 @@ File Formats Visualization ------------- -- :ref:`example_advanced_interactive_viz` - +- :ref:`example_viz_advanced` +- :ref:`example_viz_slice` +- :ref:`example_viz_bundles` .. In order to build the examples, you'll need (on Debian) sudo apt-get install python-tables python-matplotib python-vtk From aa80f32e2ab736d7d450517f681a7e022ab1bdae Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 17:28:16 -0400 Subject: [PATCH 129/242] DOC: updated bundle mapping tutorial --- doc/examples/viz_bundles.py | 74 ++++++++++++++----------------------- 1 file changed, 27 insertions(+), 47 deletions(-) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 6a62281663..3aa15682a9 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -1,21 +1,21 @@ """ -======================================= -Visualize bundle and metrics on bundles -======================================= - +======================================== +Visualize bundles and metrics on bundles +======================================== """ import numpy as np -import nibabel as nib from dipy.viz import window, actor from dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects +from dipy.tracking.streamline import transform_streamlines fetch_bundles_2_subjects() -dix = read_bundles_2_subjects() +dix = read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], + bundles=['cg.left', 'cst.right']) fa = dix['fa'] affine = dix['affine'] -bundle = dix['cst.right'] +bundle = dix['cg.left'] renderer = window.Renderer() @@ -27,56 +27,36 @@ renderer.clear() -stream_actor2 = actor.line(bundle, fa) +bundle_img = transform_streamlines(bundle, np.linalg.inv(affine)) + +stream_actor2 = actor.line(bundle_img, fa) renderer.add(stream_actor2) window.show(renderer) +renderer.clear() -1/0 - -""" -Load colormap (FA map for this example) -""" -fa_file = nib.load(dname + "../fa_1x1x1.nii.gz") -fa_colormap = fa_file.get_data() -colormap_affine = fa_file.get_affine() - -""" -4. Transform lines in the same coordinates -""" -transfo = np.linalg.inv(colormap_affine) -lines = [nib.affines.apply_affine(transfo, s) for s in lines] - -""" -5. Generate and render fvtk streamline with scalar_bar -""" -width = 0.1 -fvtk_tubes = vtk_a.streamtube(lines, fa_colormap, linewidth=width) -scalar_bar = vtk_a.scalar_bar(fvtk_tubes.GetMapper().GetLookupTable()) +stream_actor3 = actor.streamtube(bundle_img, fa, linewidth=0.1) +bar = actor.scalar_bar() -renderer = fvtk.ren() -fvtk.add(renderer, fvtk_tubes) -fvtk.add(renderer, scalar_bar) -fvtk.show(renderer) +renderer.add(stream_actor3) +renderer.add(bar) -""" -6. Generate and render fvtk streamline with scalar_bar -""" - -saturation = [0.0, 1.0] # white to red -hue = [0.0, 0.0] # Red only +window.show(renderer) -lut_cmap = vtk_a.colormap_lookup_table(hue_range=hue, saturation_range=saturation) +renderer.clear() -fvtk_tubes = vtk_a.streamtube(lines, fa_colormap, linewidth=width, - lookup_colormap=lut_cmap) +hue = [0.0, 0.0] # red only +saturation = [0.0, 1.0] # white to red -scalar_bar = vtk_a.scalar_bar(fvtk_tubes.GetMapper().GetLookupTable()) +lut_cmap = actor.colormap_lookup_table(hue_range=hue, + saturation_range=saturation) -renderer = fvtk.ren() -fvtk.add(renderer, fvtk_tubes) -fvtk.add(renderer, scalar_bar) -fvtk.show(renderer) +stream_actor4 = actor.streamtube(bundle_img, fa, linewidth=0.1, + lookup_colormap=lut_cmap) +bar2 = actor.scalar_bar(lut_cmap) +renderer.add(stream_actor4) +renderer.add(bar2) +window.show(renderer) From efb8e5cb1ad0e820a03d424bccb22aebdb1927cc Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 17:29:45 -0400 Subject: [PATCH 130/242] Added default lut for scalar bar actor --- dipy/viz/actor.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 869e307f0b..50c8975bf0 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -507,11 +507,24 @@ def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), return lookup_table -def scalar_bar(lookup_table, title=" "): - """ Default Scalar bar actor for the colormap +def scalar_bar(lookup_table=None, title=" "): + """ Default scalar bar actor for a given colormap + + Parameters + ---------- + lookup_table : vtkLookupTable or None + If None then ``colormap_lookup_table`` is called with default options. + title : str + + Returns + ------- + scalar_bar : vtkScalarBarActor + """ lookup_table_copy = vtk.vtkLookupTable() # Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it + if lookup_table is None: + lookup_table = colormap_lookup_table() lookup_table_copy.DeepCopy(lookup_table) scalar_bar = vtk.vtkScalarBarActor() scalar_bar.SetTitle(title) From eda8f379e401a53913c640e69a335516f273dd6e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 17:30:54 -0400 Subject: [PATCH 131/242] NF: add option for setting the camera in the renderer --- dipy/viz/window.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index d5a89e5094..25aceb575b 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -97,6 +97,23 @@ def reset_camera(self): """ self.ResetCamera() + def get_camera(self): + return self.GetActiveCamera() + + def camera_info(self): + cam = self.get_camere() + print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) + print('Camera Focal Point (%.2f,%.2f,%.2f)' % cam.GetFocalPoint()) + print('Camera View Up (%.2f,%.2f,%.2f)' % cam.GetViewUp()) + + def set_camera(self, pos=None, focal=None, viewup=None): + if pos is not None: + ren.GetActiveCamera().SetPosition(*pos) + if focal is not None: + ren.GetActiveCamera().SetFocalPoint(*focal) + if viewup is not None: + ren.GetActiveCamera().SetViewUp(*viewup) + def renderer(background=None): """ Create a renderer. From afee1dd25b880f044950d38b64fc24cade85d98f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 13 Jul 2015 22:00:50 -0400 Subject: [PATCH 132/242] NF: camera's position can be updated from the renderer --- dipy/viz/window.py | 16 ++++++++-------- doc/examples/viz_bundles.py | 15 +++++++++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 25aceb575b..0681bbcd0d 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -101,18 +101,18 @@ def get_camera(self): return self.GetActiveCamera() def camera_info(self): - cam = self.get_camere() + cam = self.get_camera() print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) print('Camera Focal Point (%.2f,%.2f,%.2f)' % cam.GetFocalPoint()) print('Camera View Up (%.2f,%.2f,%.2f)' % cam.GetViewUp()) - def set_camera(self, pos=None, focal=None, viewup=None): - if pos is not None: - ren.GetActiveCamera().SetPosition(*pos) - if focal is not None: - ren.GetActiveCamera().SetFocalPoint(*focal) - if viewup is not None: - ren.GetActiveCamera().SetViewUp(*viewup) + def set_camera(self, position=None, focal_point=None, view_up=None): + if position is not None: + self.GetActiveCamera().SetPosition(*position) + if focal_point is not None: + self.GetActiveCamera().SetFocalPoint(*focal_point) + if view_up is not None: + self.GetActiveCamera().SetViewUp(*view_up) def renderer(background=None): diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 3aa15682a9..7da95741e4 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -21,9 +21,16 @@ stream_actor = actor.line(bundle) + renderer.add(stream_actor) -window.show(renderer) +renderer.set_camera(position=(-302.62,7.14,33.44), + focal_point=(-4.72, 24.53, 54.96), + view_up=(-0.08,0.17,0.98)) + +window.show(renderer, reset_camera=False) + +renderer.camera_info() renderer.clear() @@ -33,7 +40,7 @@ renderer.add(stream_actor2) -window.show(renderer) +window.show(renderer, reset_camera=False) renderer.clear() stream_actor3 = actor.streamtube(bundle_img, fa, linewidth=0.1) @@ -42,7 +49,7 @@ renderer.add(stream_actor3) renderer.add(bar) -window.show(renderer) +window.show(renderer, reset_camera=False) renderer.clear() @@ -59,4 +66,4 @@ renderer.add(stream_actor4) renderer.add(bar2) -window.show(renderer) +window.show(renderer, reset_camera=False) From 07b9db6ac6a484b0c681a29647291a52aabc7514 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 16:17:03 -0400 Subject: [PATCH 133/242] DOC: added figure in viz_advanced --- doc/examples/viz_advanced.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index c07527ebaa..bfe78d0f0a 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -10,6 +10,7 @@ for backwards compatibility but now there is a more comprehensive way to access the main functions using the following modules. """ + import numpy as np from dipy.viz import actor, window, widget @@ -167,5 +168,12 @@ def win_callback(obj, event): # show_m.render() # show_m.start() +window.snapshot(ren, 'bundles_and_a_slice.png', size=(1200, 900)) + +""" +.. figure:: bundles_and_a_slice.png + :align: center + **A few bundles with interactive slicing**. +""" From 2c72046c7d563dfff30432146a34e7ac44dce856 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 16:28:51 -0400 Subject: [PATCH 134/242] DOC: updated bundle visualization tutorial --- doc/examples/viz_bundles.py | 105 +++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 7da95741e4..f157952ffc 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -2,6 +2,9 @@ ======================================== Visualize bundles and metrics on bundles ======================================== + +Frist, let's download some available datasets. Here we are using a dataset +which provides metrics and bundles. """ import numpy as np @@ -13,43 +16,99 @@ dix = read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], bundles=['cg.left', 'cst.right']) +""" +Store franctional anisotropy. +""" + fa = dix['fa'] + +""" +Store grid to world transformation matrix. +""" + affine = dix['affine'] + +""" +Store the cingulum bundle. A bundle is a set of streamlines. +""" + bundle = dix['cg.left'] +""" +It happened that this bundle is in world coordinates and therefore we need to +transform in native image coordinates so that it is in the same coordinate +space as the ``fa``. +""" + +bundle_img = transform_streamlines(bundle, np.linalg.inv(affine)) + +""" +Show every streamline with an orientation color +=============================================== + +This is the default option when you are using ``line`` or ``streamtube``. +""" + renderer = window.Renderer() -stream_actor = actor.line(bundle) +stream_actor = actor.line(bundle_img) +renderer.set_camera(position=(-176.42, 118.52, 128.20), + focal_point=(113.30, 128.31, 76.56), + view_up=(0.18, 0.00, 0.98)) renderer.add(stream_actor) -renderer.set_camera(position=(-302.62,7.14,33.44), - focal_point=(-4.72, 24.53, 54.96), - view_up=(-0.08,0.17,0.98)) +# window.show(renderer, size=(600, 600), reset_camera=False) +window.snapshot(renderer, 'bundle1.png', size=(600, 600)) -window.show(renderer, reset_camera=False) +""" +.. figure:: bundle1.png + :align: center -renderer.camera_info() + **One orientation color for every streamline**. -renderer.clear() +You may wonder how we knew how to set the camera. This is very easy. You just +need to run ``window.show`` once see how you want to see the object and then +close the window and call the ``camera_info`` method which prints the position, +focal point and view up vectors of the camera. +""" -bundle_img = transform_streamlines(bundle, np.linalg.inv(affine)) +renderer.camera_info() -stream_actor2 = actor.line(bundle_img, fa) +""" +Show every point with a value from a metric with default colormap +================================================================= -renderer.add(stream_actor2) +Here we will need to input the ``fa`` map in ``streamtube`` or ``line``. +""" -window.show(renderer, reset_camera=False) renderer.clear() +stream_actor2 = actor.line(bundle_img, fa, linewidth=0.1) + +""" +We can also show the scalar bar. +""" -stream_actor3 = actor.streamtube(bundle_img, fa, linewidth=0.1) bar = actor.scalar_bar() -renderer.add(stream_actor3) +renderer.add(stream_actor2) renderer.add(bar) -window.show(renderer, reset_camera=False) +# window.show(renderer, size=(600, 600), reset_camera=False) +window.snapshot(renderer, 'bundle2.png', size=(600, 600)) + +""" +.. figure:: bundle2.png + :align: center + + **Every point with a color from FA**. + +Show every point with a value from a metric with your colormap +============================================================== + +Here we will need to input the ``fa`` map in ``streamtube`` or `` +""" renderer.clear() @@ -59,11 +118,21 @@ lut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation) -stream_actor4 = actor.streamtube(bundle_img, fa, linewidth=0.1, - lookup_colormap=lut_cmap) +stream_actor3 = actor.line(bundle_img, fa, linewidth=0.1, + lookup_colormap=lut_cmap) bar2 = actor.scalar_bar(lut_cmap) -renderer.add(stream_actor4) +renderer.add(stream_actor3) renderer.add(bar2) -window.show(renderer, reset_camera=False) +# window.show(renderer, size=(600, 600), reset_camera=False) +window.snapshot(renderer, 'bundle3.png', size=(600, 600)) + +""" +.. figure:: bundle3.png + :align: center + + **Every point with a color from FA using a non default colomap**. +""" + + From a022c8acbcf68b8c072b029a0038acc448c0ad76 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 16:31:32 -0400 Subject: [PATCH 135/242] DOC: removed extra line --- doc/examples/viz_slice.py | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index b9652bca6b..19a5560fe6 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -13,7 +13,6 @@ from dipy.data import fetch_bundles_2_subjects from dipy.viz import window, actor - """ Let's download and load a T1. """ From 41b0bd616dbf8e2e85f8c72f431558d51a7c3a0e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 16:37:23 -0400 Subject: [PATCH 136/242] DOC: added new tutorial for creating a minimalistic user interface --- doc/examples/viz_hud.py | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 doc/examples/viz_hud.py diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py new file mode 100644 index 0000000000..2a6dd46fc3 --- /dev/null +++ b/doc/examples/viz_hud.py @@ -0,0 +1,121 @@ +""" +===================================== +Create a minimalistic user interface +===================================== + +""" + +from dipy.viz import window, actor, widget +from dipy.data import fetch_viz_icons, read_viz_icons + +interactive = True +renderer = window.Renderer() + + +lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), + np.array([[-1, 1, 0.], [1, 1, 0.]])] +colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) +stream_actor = actor.streamtube(lines, colors) + +renderer.add(stream_actor) + +# the show manager allows to break the rendering process +# in steps so that the widgets can be added properly +show_manager = window.ShowManager(renderer, size=(800, 800)) + +if interactive: + show_manager.initialize() + show_manager.render() + + +global opacity +opacity = 1. + +def button_callback(obj, event): + print('Camera pressed') + window.save_file_dialog(file_types=[("PNG files", "*.png")]) + +def button_plus_callback(obj, event): + print('+ pressed') + global opacity + if opacity < 1: + opacity += 0.2 + stream_actor.GetProperty().SetOpacity(opacity) + + +def button_minus_callback(obj, event): + print('- pressed') + global opacity + if opacity > 0: + opacity -= 0.2 + + stream_actor.GetProperty().SetOpacity(opacity) + +fetch_viz_icons() +button_png = read_viz_icons(fname='camera.png') + +button = widget.button(show_manager.iren, + show_manager.ren, + button_callback, + button_png, (.98, 1.), (80, 50)) + +button_png_plus = read_viz_icons(fname='plus.png') +button_plus = widget.button(show_manager.iren, + show_manager.ren, + button_plus_callback, + button_png_plus, (.98, .9), (120, 50)) + +button_png_minus = read_viz_icons(fname='minus.png') +button_minus = widget.button(show_manager.iren, + show_manager.ren, + button_minus_callback, + button_png_minus, (.98, .9), (50, 50)) + +def print_status(obj, event): + rep = obj.GetRepresentation() + stream_actor.SetPosition((rep.GetValue(), 0, 0)) + +slider = widget.slider(show_manager.iren, show_manager.ren, + callback=print_status, + min_value=-1, + max_value=1, + value=0., + label="X", + right_normalized_pos=(.98, 0.7), + size=(120, 0), label_format="%0.2lf") + +# This callback is used to update the buttons/sliders' position +# so they can stay on the right side of the window when the window +# is being resized. + +global size +size = renderer.GetSize() + +def win_callback(obj, event): + global size + if size != obj.GetSize(): + + button.place(renderer) + button_plus.place(renderer) + button_minus.place(renderer) + slider.place(renderer) + size = obj.GetSize() + show_manager.render() + +if interactive: + show_manager.add_window_callback(win_callback) + # you can also register any callback in a vtk way like this + # show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, + # win_callback) + + show_manager.render() + show_manager.start() + +if not interactive: + button.Off() + slider.Off() + + arr = window.snapshot(renderer, size=(800, 800)) + # imshow(report.labels, origin='lower') + +report = window.analyze_renderer(renderer) From 9007f9d71c825ca19f6c414e3bf043e84ebc456f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 17:29:38 -0400 Subject: [PATCH 137/242] Added option for setting the color of slider --- dipy/viz/widget.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index d33d6c119c..3a93f98cae 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -14,7 +14,9 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, label="Slider", right_normalized_pos=(0.9, 0.5), size=(50, 0), - label_format="%0.0lf"): + label_format="%0.0lf", + color=(0.5, 0.5, 0.5), + selected_color = (0.9, 0.2, 0.1)): """ A 2D slider widget Parameters @@ -80,6 +82,16 @@ def slider(iren, ren, callback, min_value=0, max_value=255, value=125, slider_rep.SetTubeWidth(tube_width) slider_rep.SetLabelFormat(label_format) + slider_rep.GetLabelProperty().SetColor(*color) + slider_rep.GetTubeProperty().SetColor(*color) + slider_rep.GetCapProperty().SetColor(*color) + slider_rep.GetTitleProperty().SetColor(*color) + slider_rep.GetSelectedProperty().SetColor(*selected_color) + slider_rep.GetSliderProperty().SetColor(*color) + + slider_rep.GetLabelProperty().SetShadow(0) + slider_rep.GetTitleProperty().SetShadow(0) + class SliderWidget(vtk.vtkSliderWidget): def place(self, ren): @@ -115,6 +127,7 @@ def get_value(self): slider.AddObserver("InteractionEvent", callback) slider.SetEnabled(True) + return slider From 7d77425302456f891320adb5d273ea8dad1edb9d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 17:38:09 -0400 Subject: [PATCH 138/242] Updated slicer color --- doc/examples/viz_advanced.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index bfe78d0f0a..904780a7fa 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -131,7 +131,9 @@ def change_slice(obj, event): value=shape[2] / 2, label="Move slice", right_normalized_pos=(.98, 0.6), - size=(120, 0), label_format="%0.lf") + size=(120, 0), label_format="%0.lf", + color=(1., 1., 1.), + selected_color=(0.86, 0.33, 1.)) """ Then, we can render all the widget and everything else in the screen and @@ -150,6 +152,7 @@ def change_slice(obj, event): global size size = ren.GetSize() + def win_callback(obj, event): global size if size != obj.GetSize(): From fc5cf72a3f376994a93b56e57aef10b8d1d87a50 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 18:41:14 -0400 Subject: [PATCH 139/242] pep 8 --- dipy/viz/widget.py | 5 ++--- doc/examples/viz_hud.py | 34 +++++++++++++++------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index 3a93f98cae..dfdc2973cf 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -127,7 +127,6 @@ def get_value(self): slider.AddObserver("InteractionEvent", callback) slider.SetEnabled(True) - return slider @@ -155,8 +154,8 @@ def button(iren, ren, callback, fname, right_normalized_pos=(.98, .9), Used to process events and handle them to the button. Can also be given by the attribute ``ShowManager.iren``. ren : vtkRenderer or Renderer - Used to update the slider's position when the window changes. Can also be given - by the ``ShowManager.ren`` attribute. + Used to update the slider's position when the window changes. Can also + be given by the ``ShowManager.ren`` attribute. callback : function Function that has at least ``obj`` and ``event`` as parameters. It will be called when the button is pressed. diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index 2a6dd46fc3..68278d86cc 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -5,13 +5,13 @@ """ +import numpy as np from dipy.viz import window, actor, widget from dipy.data import fetch_viz_icons, read_viz_icons interactive = True renderer = window.Renderer() - lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), np.array([[-1, 1, 0.], [1, 1, 0.]])] colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) @@ -31,15 +31,16 @@ global opacity opacity = 1. + def button_callback(obj, event): - print('Camera pressed') - window.save_file_dialog(file_types=[("PNG files", "*.png")]) + print('Infinity button pressed') + def button_plus_callback(obj, event): print('+ pressed') global opacity if opacity < 1: - opacity += 0.2 + opacity += 0.1 stream_actor.GetProperty().SetOpacity(opacity) @@ -47,12 +48,12 @@ def button_minus_callback(obj, event): print('- pressed') global opacity if opacity > 0: - opacity -= 0.2 - + opacity -= 0.1 stream_actor.GetProperty().SetOpacity(opacity) + fetch_viz_icons() -button_png = read_viz_icons(fname='camera.png') +button_png = read_viz_icons(fname='infinite.png') button = widget.button(show_manager.iren, show_manager.ren, @@ -71,18 +72,21 @@ def button_minus_callback(obj, event): button_minus_callback, button_png_minus, (.98, .9), (50, 50)) -def print_status(obj, event): + +def move_lines(obj, event): rep = obj.GetRepresentation() stream_actor.SetPosition((rep.GetValue(), 0, 0)) slider = widget.slider(show_manager.iren, show_manager.ren, - callback=print_status, + callback=move_lines, min_value=-1, max_value=1, value=0., label="X", right_normalized_pos=(.98, 0.7), - size=(120, 0), label_format="%0.2lf") + size=(120, 0), label_format="%0.2lf", + color=(0.4, 0.4, 0.4), + selected_color=(0.9, 0.5, 0.5)) # This callback is used to update the buttons/sliders' position # so they can stay on the right side of the window when the window @@ -91,6 +95,7 @@ def print_status(obj, event): global size size = renderer.GetSize() + def win_callback(obj, event): global size if size != obj.GetSize(): @@ -110,12 +115,3 @@ def win_callback(obj, event): show_manager.render() show_manager.start() - -if not interactive: - button.Off() - slider.Off() - - arr = window.snapshot(renderer, size=(800, 800)) - # imshow(report.labels, origin='lower') - -report = window.analyze_renderer(renderer) From 8ba796afb75c798c81198d10f6fee8613e6917dc Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 18:44:47 -0400 Subject: [PATCH 140/242] RF: removed interactive variable --- doc/examples/viz_hud.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index 68278d86cc..08927691ae 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -9,7 +9,7 @@ from dipy.viz import window, actor, widget from dipy.data import fetch_viz_icons, read_viz_icons -interactive = True + renderer = window.Renderer() lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), @@ -23,9 +23,8 @@ # in steps so that the widgets can be added properly show_manager = window.ShowManager(renderer, size=(800, 800)) -if interactive: - show_manager.initialize() - show_manager.render() +show_manager.initialize() +show_manager.render() global opacity @@ -86,7 +85,7 @@ def move_lines(obj, event): right_normalized_pos=(.98, 0.7), size=(120, 0), label_format="%0.2lf", color=(0.4, 0.4, 0.4), - selected_color=(0.9, 0.5, 0.5)) + selected_color=(0.2, 0.2, 0.2)) # This callback is used to update the buttons/sliders' position # so they can stay on the right side of the window when the window @@ -107,11 +106,11 @@ def win_callback(obj, event): size = obj.GetSize() show_manager.render() -if interactive: - show_manager.add_window_callback(win_callback) - # you can also register any callback in a vtk way like this - # show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, - # win_callback) - show_manager.render() - show_manager.start() +show_manager.add_window_callback(win_callback) +# you can also register any callback in a vtk way like this +# show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, +# win_callback) + +show_manager.render() +show_manager.start() From 977514bb64c9d1cfee7108cb010507c6f3b1c1e7 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 14 Jul 2015 18:45:18 -0400 Subject: [PATCH 141/242] Updated examples_index and valid_examples --- doc/examples/valid_examples.txt | 3 ++- doc/examples_index.rst | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index 6e228747f1..15c60ca590 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -39,4 +39,5 @@ piesno.py viz_advanced.py viz_slice.py - viz_bundle_maps.py + viz_bundles.py + viz_hud.py diff --git a/doc/examples_index.rst b/doc/examples_index.rst index 719c190f3e..11a948703b 100644 --- a/doc/examples_index.rst +++ b/doc/examples_index.rst @@ -197,6 +197,7 @@ Visualization - :ref:`example_viz_advanced` - :ref:`example_viz_slice` - :ref:`example_viz_bundles` +- :ref:`example_viz_hud` .. In order to build the examples, you'll need (on Debian) sudo apt-get install python-tables python-matplotib python-vtk From 836c4c7c6f32ff299eefdd55e67693b8625c0899 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 15 Jul 2015 13:44:10 -0400 Subject: [PATCH 142/242] Added roll, zoom, azimuth and roll methods in Renderer --- dipy/viz/window.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 0681bbcd0d..bb3c0252fb 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -102,9 +102,9 @@ def get_camera(self): def camera_info(self): cam = self.get_camera() - print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) - print('Camera Focal Point (%.2f,%.2f,%.2f)' % cam.GetFocalPoint()) - print('Camera View Up (%.2f,%.2f,%.2f)' % cam.GetViewUp()) + print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) + print('Camera Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) + print('Camera View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) def set_camera(self, position=None, focal_point=None, view_up=None): if position is not None: @@ -114,6 +114,19 @@ def set_camera(self, position=None, focal_point=None, view_up=None): if view_up is not None: self.GetActiveCamera().SetViewUp(*view_up) + @property + def size(self): + return self.GetSize() + + def zoom(self, value): + self.GetActiveCamera().Zoom(value) + + def azimuth(self, angle): + self.GetActiveCamera().Azimuth(angle) + + def roll(self, angle): + self.GetActiveCamera().Roll(angle) + def renderer(background=None): """ Create a renderer. From 94498552255ee4a0dad58ef22fe77131c6a34450 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 15 Jul 2015 14:54:49 -0400 Subject: [PATCH 143/242] DOC: finalized mini user interface --- doc/examples/viz_hud.py | 81 +++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index 08927691ae..a5a8b2e8fe 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -3,38 +3,46 @@ Create a minimalistic user interface ===================================== +DIPY allows to create a minimalistic interface using widgets. + +In this example we will create: a) two parallel steamtubes, b) add some buttons +which will change the opacity of these tubes and c) move the streamtubes using +a slider. """ import numpy as np from dipy.viz import window, actor, widget from dipy.data import fetch_viz_icons, read_viz_icons +""" +First, we add the streamtubes to the +""" renderer = window.Renderer() lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), np.array([[-1, 1, 0.], [1, 1, 0.]])] -colors = np.array([[1., 0., 0.], [0.3, 0.7, 0.]]) -stream_actor = actor.streamtube(lines, colors) +colors = np.array([[1., 0., 0.], [1., 0.5, 0.]]) +stream_actor = actor.streamtube(lines, colors, linewidth=0.3) renderer.add(stream_actor) -# the show manager allows to break the rendering process -# in steps so that the widgets can be added properly +""" +The ``ShowManager`` allows to break the visualization process in steps so that +the widgets can be added and updated properly. +""" + show_manager = window.ShowManager(renderer, size=(800, 800)) show_manager.initialize() -show_manager.render() +""" +Next we add the widgets and their callbacks. +""" global opacity opacity = 1. - -def button_callback(obj, event): - print('Infinity button pressed') - - def button_plus_callback(obj, event): print('+ pressed') global opacity @@ -51,15 +59,13 @@ def button_minus_callback(obj, event): stream_actor.GetProperty().SetOpacity(opacity) -fetch_viz_icons() -button_png = read_viz_icons(fname='infinite.png') - -button = widget.button(show_manager.iren, - show_manager.ren, - button_callback, - button_png, (.98, 1.), (80, 50)) +""" +We need to download some icons to create a face for our buttons ... +""" +fetch_viz_icons() button_png_plus = read_viz_icons(fname='plus.png') + button_plus = widget.button(show_manager.iren, show_manager.ren, button_plus_callback, @@ -71,10 +77,13 @@ def button_minus_callback(obj, event): button_minus_callback, button_png_minus, (.98, .9), (50, 50)) - def move_lines(obj, event): - rep = obj.GetRepresentation() - stream_actor.SetPosition((rep.GetValue(), 0, 0)) + + stream_actor.SetPosition((obj.get_value(), 0, 0)) + +""" +And then we create the slider. +""" slider = widget.slider(show_manager.iren, show_manager.ren, callback=move_lines, @@ -87,24 +96,22 @@ def move_lines(obj, event): color=(0.4, 0.4, 0.4), selected_color=(0.2, 0.2, 0.2)) -# This callback is used to update the buttons/sliders' position -# so they can stay on the right side of the window when the window -# is being resized. - global size size = renderer.GetSize() +""" +This callback is used to update the buttons/sliders' position so they can stay +on the correct side of the window when the window is being resized. +""" def win_callback(obj, event): global size if size != obj.GetSize(): - button.place(renderer) button_plus.place(renderer) button_minus.place(renderer) slider.place(renderer) size = obj.GetSize() - show_manager.render() show_manager.add_window_callback(win_callback) @@ -112,5 +119,25 @@ def win_callback(obj, event): # show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, # win_callback) +renderer.zoom(0.7) +renderer.roll(10.) + show_manager.render() -show_manager.start() + +""" +Uncomment the following line to start the interaction. +""" + +# show_manager.start() + +window.snapshot(renderer, 'mini_ui.png', size=(800, 800)) + +del show_manager + +""" +.. figure:: mini_ui.png + :align: center + + **A minimalistic user interface**. +""" + From 23b16fa4dacef2922998dfbf6c7f943821e36a04 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 15 Jul 2015 17:44:24 -0400 Subject: [PATCH 144/242] NF: allow to have a color per streamline a array of values which will be mapped by a colormap --- dipy/viz/actor.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 50c8975bf0..a091308dd2 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -171,6 +171,9 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, If an array (K, ) is given, where K is the number of points of all lines then these are considered as the values to be used by the colormap. + If an array (L, ) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the colormap are interpolated automatically using trilinear interpolation. @@ -305,6 +308,9 @@ def line(lines, colors=None, opacity=1, linewidth=1, If an array (K, ) is given, where K is the number of points of all lines then these are considered as the values to be used by the colormap. + If an array (L, ) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the colormap are interpolated automatically using trilinear interpolation. @@ -395,6 +401,9 @@ def lines_to_vtk_polydata(lines, colors=None): If an array (K, ) is given, where K is the number of points of all lines then these are considered as the values to be used by the colormap. + If an array (L, ) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the colormap are interpolated automatically using trilinear interpolation. @@ -451,9 +460,18 @@ def lines_to_vtk_polydata(lines, colors=None): vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) is_colormap = True - elif cols_arr.ndim == 1: # the same colors for all points - vtk_colors = numpy_to_vtk_colors( - np.tile(255 * cols_arr, (nb_points, 1))) + elif cols_arr.ndim == 1: + if len(cols_arr) == nb_lines: # values for every streamline + cols_arrx = [] + for (i, value) in enumerate(colors): + cols_arrx += lines[i].shape[0]*[value] + cols_arrx = np.array(cols_arrx) + vtk_colors = numpy_support.numpy_to_vtk(cols_arrx, + deep=True) + is_colormap = True + else: # the same colors for all points + vtk_colors = numpy_to_vtk_colors( + np.tile(255 * cols_arr, (nb_points, 1))) elif cols_arr.ndim == 2: # map color to each line colors_mapper = np.repeat(lines_range, points_per_line, axis=0) From 1aa8ac056ce4226567edbe2a70a8d707447a8304 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 15 Jul 2015 17:57:35 -0400 Subject: [PATCH 145/242] RF: changed bundle_img to bundle_native --- doc/examples/viz_bundles.py | 98 ++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index f157952ffc..a5bcd62e79 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -40,7 +40,7 @@ space as the ``fa``. """ -bundle_img = transform_streamlines(bundle, np.linalg.inv(affine)) +bundle_native = transform_streamlines(bundle, np.linalg.inv(affine)) """ Show every streamline with an orientation color @@ -51,7 +51,7 @@ renderer = window.Renderer() -stream_actor = actor.line(bundle_img) +stream_actor = actor.line(bundle_native) renderer.set_camera(position=(-176.42, 118.52, 128.20), focal_point=(113.30, 128.31, 76.56), @@ -77,14 +77,14 @@ renderer.camera_info() """ -Show every point with a value from a metric with default colormap +Show every point with a value from a volume with default colormap ================================================================= Here we will need to input the ``fa`` map in ``streamtube`` or ``line``. """ renderer.clear() -stream_actor2 = actor.line(bundle_img, fa, linewidth=0.1) +stream_actor2 = actor.line(bundle_native, fa, linewidth=0.1) """ We can also show the scalar bar. @@ -104,7 +104,7 @@ **Every point with a color from FA**. -Show every point with a value from a metric with your colormap +Show every point with a value from a volume with your colormap ============================================================== Here we will need to input the ``fa`` map in ``streamtube`` or `` @@ -118,7 +118,7 @@ lut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation) -stream_actor3 = actor.line(bundle_img, fa, linewidth=0.1, +stream_actor3 = actor.line(bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap) bar2 = actor.scalar_bar(lut_cmap) @@ -133,6 +133,92 @@ :align: center **Every point with a color from FA using a non default colomap**. + + +Show every bundle with a specific color +======================================== + +You can have a bundle with a specific color. Here orange. +""" + +renderer.clear() +stream_actor4 = actor.line(bundle_native, (1., 0.5, 0), linewidth=0.1) + +renderer.add(stream_actor4) + +# window.show(renderer, size=(600, 600), reset_camera=False) +window.snapshot(renderer, 'bundle4.png', size=(600, 600)) + +""" +.. figure:: bundle4.png + :align: center + + **Entire bundle with a specific color**. + +Show every streamline of a bundle with a different color +======================================================== + +Let's make a colormap where every streamline of the bundle is colored by its +length. """ +renderer.clear() + +from dipy.tracking.streamline import length + +lengths = length(bundle_native) + +hue = [0.5, 0.5] # red only +saturation = [0.0, 1.0] # black to white + +lut_cmap = actor.colormap_lookup_table( + scale_range=(lengths.min(), lengths.max()), + hue_range=hue, + saturation_range=saturation) + +stream_actor5 = actor.line(bundle_native, lengths, linewidth=0.1, + lookup_colormap=lut_cmap) + +renderer.add(stream_actor5) +bar3 = actor.scalar_bar(lut_cmap) +renderer.add(bar3) + +# window.show(renderer, size=(600, 600), reset_camera=False) +window.snapshot(renderer, 'bundle5.png', size=(600, 600)) + +""" +.. figure:: bundle5.png + :align: center + + **Color by length of streamline **. + +Show every point of every streamline with a different color +============================================================ + +In this case in which we want to have a color per point and per streamline, +we can create a list of the colors to correspond to the list of streamlines +(bundles). Here in ``colors`` we will insert some random RGB colors. +""" + +renderer.clear() + +colors = [np.random.rand(*streamline.shape) for streamline in bundle_native] + +stream_actor6 = actor.line(bundle_native, colors, linewidth=0.2, opacity=1) + +renderer.add(stream_actor6) + +# window.show(renderer, size=(600, 600), reset_camera=False) +window.snapshot(renderer, 'bundle6.png', size=(600, 600)) + +""" +.. figure:: bundle6.png + :align: center + + **Random colors per points per streamline**. + +In summary, we showed that there are many useful ways for visualizing maps +on bundles. + +""" From cb67e3770b874a1bf2862d7e491603513b90db6e Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 15 Jul 2015 18:06:51 -0400 Subject: [PATCH 146/242] DOC: minor change for rendering the tutorial --- doc/examples/viz_bundles.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index a5bcd62e79..5ed6860818 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -190,8 +190,8 @@ """ .. figure:: bundle5.png :align: center + **Color every streamline by the length of the streamline ** - **Color by length of streamline **. Show every point of every streamline with a different color ============================================================ @@ -205,7 +205,7 @@ colors = [np.random.rand(*streamline.shape) for streamline in bundle_native] -stream_actor6 = actor.line(bundle_native, colors, linewidth=0.2, opacity=1) +stream_actor6 = actor.line(bundle_native, colors, linewidth=0.2) renderer.add(stream_actor6) From 951efa63efed845c7c27a4c04ffeb9579e699d8c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 17 Jul 2015 11:50:06 -0400 Subject: [PATCH 147/242] BF: support for VTK 5 in reslicing --- dipy/viz/actor.py | 2 +- dipy/viz/utils.py | 25 +++++++++++++++++-------- doc/examples/viz_advanced.py | 4 ++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index a091308dd2..90db867d64 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -91,7 +91,7 @@ def slice(data, affine=None, value_range=None, opacity=1., # Set the reslicing image_resliced = vtk.vtkImageReslice() - image_resliced.SetInputData(im) + set_input(image_resliced, im) image_resliced.SetResliceTransform(transform) image_resliced.AutoCropOutputOn() image_resliced.SetInterpolationModeToLinear() diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 4f2ba30615..afabac19bb 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -36,21 +36,30 @@ def numpy_to_vtk_colors(colors): return vtk_colors -def set_input(vtk_object, input): - """ Generic input for vtk data, - depending of the type of input and vtk version +def set_input(vtk_object, inp): + """ Generic input function which takes into account VTK 5 or 6 + + Parameters + ---------- + vtk_object: vtk object + inp: vtkPolyData or vtkImageData or vtkAlgorithmOutput + + Returns + ------- + vtk_object Example ---------- >>> poly_mapper = set_input(vtk.vtkPolyDataMapper(), poly_data) """ - if isinstance(input, vtk.vtkPolyData): + if isinstance(inp, vtk.vtkPolyData) \ + or isinstance(inp, vtk.vtkImageData): if vtk.VTK_MAJOR_VERSION <= 5: - vtk_object.SetInput(input) + vtk_object.SetInput(inp) else: - vtk_object.SetInputData(input) - elif isinstance(input, vtk.vtkAlgorithmOutput): - vtk_object.SetInputConnection(input) + vtk_object.SetInputData(inp) + elif isinstance(inp, vtk.vtkAlgorithmOutput): + vtk_object.SetInputConnection(inp) vtk_object.Update() return vtk_object diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 904780a7fa..52cd3778a9 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -168,8 +168,8 @@ def win_callback(obj, event): the available 3D and 2D objects. """ -# show_m.render() -# show_m.start() +show_m.render() +show_m.start() window.snapshot(ren, 'bundles_and_a_slice.png', size=(1200, 900)) From 71b7152fdc46273b176238b6d3c5494c8849bd98 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 17 Jul 2015 11:51:02 -0400 Subject: [PATCH 148/242] Added minor comment --- doc/examples/viz_advanced.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 52cd3778a9..904780a7fa 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -168,8 +168,8 @@ def win_callback(obj, event): the available 3D and 2D objects. """ -show_m.render() -show_m.start() +# show_m.render() +# show_m.start() window.snapshot(ren, 'bundles_and_a_slice.png', size=(1200, 900)) From 502e42897993ed96d4cb96ad6de44ce3f188c32f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 17 Jul 2015 13:19:15 -0400 Subject: [PATCH 149/242] BF: another VTK 5 to 6 resolution --- dipy/viz/actor.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 90db867d64..42ace48d1a 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -113,9 +113,12 @@ def slice(data, affine=None, value_range=None, opacity=1., class ImageActor(vtk.vtkImageActor): - def input_connection(self, output_port): - self.GetMapper().SetInputConnection(output_port) - self.output_port = output_port + def input_connection(self, output): + if vtk.VTK_MAJOR_VERSION <= 5: + self.GetMapper().SetInput(output.GetOutput()) + else: + self.GetMapper().SetInputConnection(output.GetOutputPort()) + self.output = output self.shape = (ex2 + 1, ey2 + 1, ez2 + 1) def display_extent(self, x1, x2, y1, y2, z1, z2): @@ -137,13 +140,13 @@ def opacity(self, value): def copy(self): im_actor = ImageActor() - im_actor.input_connection(self.output_port) + im_actor.input_connection(self.output) im_actor.SetDisplayExtent(*self.GetDisplayExtent()) im_actor.opacity(opacity) return im_actor image_actor = ImageActor() - image_actor.input_connection(plane_colors.GetOutputPort()) + image_actor.input_connection(plane_colors) image_actor.display() image_actor.opacity(opacity) From 6cc5268be59e6009ec4608026d1bce26455eb7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Alexandre=20C=C3=B4t=C3=A9?= Date: Fri, 17 Jul 2015 14:50:02 -0400 Subject: [PATCH 150/242] BF: vtkImageActor has no mapper in VTK 5 --- dipy/viz/actor.py | 10 +++++++--- doc/examples/viz_slice.py | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 42ace48d1a..f0b9e0a748 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -115,7 +115,7 @@ class ImageActor(vtk.vtkImageActor): def input_connection(self, output): if vtk.VTK_MAJOR_VERSION <= 5: - self.GetMapper().SetInput(output.GetOutput()) + self.SetInput(output.GetOutput()) else: self.GetMapper().SetInputConnection(output.GetOutputPort()) self.output = output @@ -123,7 +123,8 @@ def input_connection(self, output): def display_extent(self, x1, x2, y1, y2, z1, z2): self.SetDisplayExtent(x1, x2, y1, y2, z1, z2) - self.Update() + if vtk.VTK_MAJOR_VERSION > 5: + self.Update() def display(self, x=None, y=None, z=None): if x is None and y is None and z is None: @@ -136,7 +137,10 @@ def display(self, x=None, y=None, z=None): self.display_extent(ex1, ex2, ey1, ey2, z, z) def opacity(self, value): - self.GetProperty().SetOpacity(value) + if vtk.VTK_MAJOR_VERSION <= 5: + self.SetOpacity(value) + else: + self.GetProperty().SetOpacity(value) def copy(self): im_actor = ImageActor() diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 19a5560fe6..9c01bcfb9e 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -78,7 +78,7 @@ In order to interact with the data you will need to uncomment the line below. """ -# window.show(renderer, size=(600, 600)) +window.show(renderer, size=(600, 600)) """ Otherwise, you can save a screenshot using the following command. @@ -123,7 +123,7 @@ renderer.clear() renderer.add(fa_actor) -# window.show(renderer, size=(600, 600)) +window.show(renderer, size=(600, 600)) window.snapshot(renderer, 'slices_lut.png', size=(600, 600)) From c971b6a2b40df25f654ff41a71567d646fba2da3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 17 Jul 2015 17:22:56 -0400 Subject: [PATCH 151/242] Raising error for using snapshot with older VTK versions --- dipy/viz/window.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index bb3c0252fb..e3367f936d 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -484,8 +484,8 @@ def snapshot(ren, fname=None, size=(300, 300)): ----------- ren : vtkRenderer as returned from function renderer() - fname : str - Save PNG file. + fname : str or None + Save PNG file. If None return only an array without saving PNG. size : (int, int) ``(width, height)`` of the window @@ -496,6 +496,9 @@ def snapshot(ren, fname=None, size=(300, 300)): holds the RGB values. """ + if vtk.VTK_MAJOR_VERSION <= 5: + raise ImportError('Snapshot is available only for VTK 6+') + width, height = size graphics_factory = vtk.vtkGraphicsFactory() From 2c70116784836aac3f01ea05b943bf12626f9c51 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 18 Jul 2015 14:30:24 -0400 Subject: [PATCH 152/242] NF: included much faster loading of volumes using numpy_support --- dipy/viz/actor.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index f0b9e0a748..4607820179 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -71,9 +71,13 @@ def slice(data, affine=None, value_range=None, opacity=1., im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) # copy data - for index in ndindex(vol.shape): - i, j, k = index - im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) + # what I do below is the same as what is commented here but much faster + # for index in ndindex(vol.shape): + # i, j, k = index + # im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) + vol = np.swapaxes(vol, 0, 2) + uchar_array = numpy_support.numpy_to_vtk(vol.ravel(), deep=0) + im.GetPointData().SetScalars(uchar_array) if affine is None: affine = np.eye(4) From c461aabb9a49e831d50346a9d4de47338c379952 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 18 Jul 2015 20:05:14 -0400 Subject: [PATCH 153/242] Added very simple initial mosaic function --- doc/examples/viz_slice.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 9c01bcfb9e..21cdec4b58 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -78,7 +78,7 @@ In order to interact with the data you will need to uncomment the line below. """ -window.show(renderer, size=(600, 600)) +# window.show(renderer, size=(600, 600)) """ Otherwise, you can save a screenshot using the following command. @@ -123,7 +123,7 @@ renderer.clear() renderer.add(fa_actor) -window.show(renderer, size=(600, 600)) +# window.show(renderer, size=(600, 600)) window.snapshot(renderer, 'slices_lut.png', size=(600, 600)) @@ -133,3 +133,28 @@ **Simple slice viewer with an HSV colormap**. """ + +renderer.clear() + +X, Y, Z = slice_actor.shape + +renderer.projection('parallel') + +cnt = 0 + +z = slice_mosaic.shape[-1] + +for i in range(20): + for j in range(9): + slice_mosaic = slice_actor.copy() + slice_mosaic.display(None, None, cnt) + slice_mosaic.SetPosition(256 * i - 256 * 10 + 2 , 256 * j - 256 * 4.5 + 2, 0) + renderer.add(slice_mosaic) + cnt += 1 + if cnt>z: break + +from dipy.viz import fvtk +renderer.add(fvtk.axes((100, 100, 100))) +renderer.zoom(2.) + +window.show(renderer) From b0f60e642b698e72703401ae5ac0a016ace47f75 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 18 Jul 2015 21:43:30 -0400 Subject: [PATCH 154/242] DOC: added simple mosaic example in tutorial viz_slice.py --- doc/examples/viz_slice.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 21cdec4b58..994e568599 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -142,19 +142,16 @@ cnt = 0 -z = slice_mosaic.shape[-1] +z = slice_actor.shape[-1] -for i in range(20): - for j in range(9): +for j in range(9): + for i in range(20): slice_mosaic = slice_actor.copy() slice_mosaic.display(None, None, cnt) - slice_mosaic.SetPosition(256 * i - 256 * 10 + 2 , 256 * j - 256 * 4.5 + 2, 0) + slice_mosaic.SetPosition(256 * i, 9 * 256 - 256 * j, 0) renderer.add(slice_mosaic) cnt += 1 if cnt>z: break -from dipy.viz import fvtk -renderer.add(fvtk.axes((100, 100, 100))) -renderer.zoom(2.) -window.show(renderer) +window.show(renderer, reset_camera=True) From f6ebf21b256c582303bc83ff4627d9f05f54871a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 19 Jul 2015 12:20:48 -0400 Subject: [PATCH 155/242] DOC: added mosaic creation example --- dipy/viz/actor.py | 6 ++++ doc/examples/viz_slice.py | 70 +++++++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 4607820179..77a49c49d1 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -153,6 +153,12 @@ def copy(self): im_actor.opacity(opacity) return im_actor + def set_position(self, wx, wy, wz): + self.SetPosition(wx, wy, wz) + + def get_position(self): + return self.GetPosition() + image_actor = ImageActor() image_actor.input_connection(plane_colors) image_actor.display() diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 994e568599..eeb6c3ff23 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -36,6 +36,9 @@ renderer.background((1, 1, 1)) """ +Render slices from T1 with a specific value range +================================================= + The T1 has usually a higher range of values than what can be visualized in an image. We can set the range that we would like to see. """ @@ -74,11 +77,14 @@ renderer.add(slice_actor2) +renderer.reset_camera() +renderer.zoom(1.4) + """ In order to interact with the data you will need to uncomment the line below. """ -# window.show(renderer, size=(600, 600)) +# window.show(renderer, size=(600, 600), reset_camera=False) """ Otherwise, you can save a screenshot using the following command. @@ -92,6 +98,9 @@ **Simple slice viewer**. +Render slices from FA with your colormap +======================================== + It is also possible to set the colormap of your preference. Here we are loading an FA image and showing it in a non-standard way using an HSV colormap. """ @@ -123,7 +132,10 @@ renderer.clear() renderer.add(fa_actor) -# window.show(renderer, size=(600, 600)) +renderer.reset_camera() +renderer.zoom(1.4) + +# window.show(renderer, size=(600, 600), reset_camera=False) window.snapshot(renderer, 'slices_lut.png', size=(600, 600)) @@ -132,26 +144,62 @@ :align: center **Simple slice viewer with an HSV colormap**. -""" -renderer.clear() -X, Y, Z = slice_actor.shape +Create a mosaic +================ +By using the ``copy`` and ``display`` method of the ``slice_actor`` becomes +easy and efficient to create a mosaic of all the slices. + +So, let's clear the renderer and change the projection from perspective to +parallel. +""" + +renderer.clear() renderer.projection('parallel') +""" +Now we need to create two nested for loops which will set the positions of +the grid of the mosaic and add the new actors to the renderer. +""" + cnt = 0 -z = slice_actor.shape[-1] +X, Y, Z = slice_actor.shape[:3] + +rows = 10 +cols = 15 +border = 10 -for j in range(9): - for i in range(20): +for j in range(rows): + for i in range(cols): slice_mosaic = slice_actor.copy() slice_mosaic.display(None, None, cnt) - slice_mosaic.SetPosition(256 * i, 9 * 256 - 256 * j, 0) + slice_mosaic.set_position((X + border) * i, + 0.5 * cols * (Y + border) - (Y + border) * j, + 0) renderer.add(slice_mosaic) cnt += 1 - if cnt>z: break + if cnt > Z: + break + if cnt > Z: + break + +renderer.reset_camera() +renderer.zoom(1.6) + +window.show(renderer, size=(900, 600), reset_camera=False) + +window.snapshot(renderer, 'mosaic.png', size=(900, 600)) +""" +You can now move the mosaic up/down and left/right using the middle mouse +button pressed. And zoom in/out using the scroll wheel. + +.. figure:: mosaic.png + :align: center + + **Create your own mosaic**. +""" -window.show(renderer, reset_camera=True) From 58a4240c372033ef3f6ddc2558a29972626e6ba1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 19 Jul 2015 12:37:41 -0400 Subject: [PATCH 156/242] BF: force array to be contiguous --- dipy/viz/actor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 77a49c49d1..fea2a86632 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -76,6 +76,7 @@ def slice(data, affine=None, value_range=None, opacity=1., # i, j, k = index # im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) vol = np.swapaxes(vol, 0, 2) + vol = np.ascontiguousarray(vol) uchar_array = numpy_support.numpy_to_vtk(vol.ravel(), deep=0) im.GetPointData().SetScalars(uchar_array) From 9aef74d6525b011df69088f6e1300b4b2e0e335c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 19 Jul 2015 12:41:54 -0400 Subject: [PATCH 157/242] DOC: updated example with mosaic creation --- doc/examples/viz_slice.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index eeb6c3ff23..b263e38bd0 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -1,8 +1,8 @@ """ -============================ +===================== Simple volume slicing -============================ +===================== Here we present an example for visualizing slices from 3D images. @@ -189,17 +189,20 @@ renderer.reset_camera() renderer.zoom(1.6) -window.show(renderer, size=(900, 600), reset_camera=False) +# window.show(renderer, size=(900, 600), reset_camera=False) + +""" +If you uncomment the ``window.show`` line above. You will be able to move the +mosaic up/down and left/right using the middle mouse button pressed. And zoom +in/out using the scroll wheel. +""" window.snapshot(renderer, 'mosaic.png', size=(900, 600)) """ -You can now move the mosaic up/down and left/right using the middle mouse -button pressed. And zoom in/out using the scroll wheel. - .. figure:: mosaic.png :align: center - **Create your own mosaic**. + **A mosaic**. """ From f8e95571a11c725563675873a96e65664b5fb7f5 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 19 Jul 2015 13:36:48 -0400 Subject: [PATCH 158/242] DOC: added some more wording in viz_slice.py --- doc/examples/viz_slice.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index b263e38bd0..9e7df600da 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -161,7 +161,8 @@ """ Now we need to create two nested for loops which will set the positions of -the grid of the mosaic and add the new actors to the renderer. +the grid of the mosaic and add the new actors to the renderer. We are going +to use 15 columns and 10 rows but you can adjust those with your datasets. """ cnt = 0 @@ -192,7 +193,7 @@ # window.show(renderer, size=(900, 600), reset_camera=False) """ -If you uncomment the ``window.show`` line above. You will be able to move the +If you uncomment the ``window.show`` line above, you will be able to move the mosaic up/down and left/right using the middle mouse button pressed. And zoom in/out using the scroll wheel. """ @@ -203,6 +204,5 @@ .. figure:: mosaic.png :align: center - **A mosaic**. + **A mosaic of all the slices in the T1 volume**. """ - From 447a36d6b99545b137585db450cb2bc27c17e587 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 23 Jul 2015 19:30:55 -0400 Subject: [PATCH 159/242] BF: needed to reset the camera's clipping range after every set. Done! --- dipy/viz/window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index e3367f936d..1c6849f97f 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -113,6 +113,7 @@ def set_camera(self, position=None, focal_point=None, view_up=None): self.GetActiveCamera().SetFocalPoint(*focal_point) if view_up is not None: self.GetActiveCamera().SetViewUp(*view_up) + self.ResetCameraClippingRange() @property def size(self): From 91e92445c6b9aff0d420d606d160616b4ade7b5a Mon Sep 17 00:00:00 2001 From: Alexandre Gauvin Date: Mon, 27 Jul 2015 17:38:31 -0400 Subject: [PATCH 160/242] Hardcoded support for color 3D data --- dipy/viz/actor.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index fea2a86632..c98efb79c9 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -48,8 +48,8 @@ def slice(data, affine=None, value_range=None, opacity=1., coordinates as calculated by the affine parameter. """ - if data.ndim != 3: - raise ValueError('Only 3D arrays are currently supported.') +# if data.ndim != 3: +# raise ValueError('Only 3D arrays are currently supported.') if value_range is None: vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) @@ -67,6 +67,7 @@ def slice(data, affine=None, value_range=None, opacity=1., im.SetSpacing(voxsz[2], voxsz[0], voxsz[1]) if major_version <= 5: im.AllocateScalars() + im.SetNumberOfScalarComponents(3) else: im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) @@ -77,7 +78,13 @@ def slice(data, affine=None, value_range=None, opacity=1., # im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) vol = np.swapaxes(vol, 0, 2) vol = np.ascontiguousarray(vol) - uchar_array = numpy_support.numpy_to_vtk(vol.ravel(), deep=0) + + print(vol.shape) + vol = np.reshape(vol, [vol.shape[0]*vol.shape[1]*vol.shape[2], vol.shape[3]]) + print(vol.shape) + uchar_array = numpy_support.numpy_to_vtk(vol, deep=0) + +# uchar_array = numpy_support.numpy_to_vtk(vol.ravel(), deep=0) im.GetPointData().SetScalars(uchar_array) if affine is None: @@ -112,7 +119,7 @@ def slice(data, affine=None, value_range=None, opacity=1., ex1, ex2, ey1, ey2, ez1, ez2 = image_resliced.GetOutput().GetExtent() plane_colors = vtk.vtkImageMapToColors() - plane_colors.SetLookupTable(lut) +# plane_colors.SetLookupTable(lut) plane_colors.SetInputConnection(image_resliced.GetOutputPort()) plane_colors.Update() From 1c97b41a6462be5782fe6dbfea9fe1ce069dd95c Mon Sep 17 00:00:00 2001 From: Alexandre Gauvin Date: Mon, 27 Jul 2015 18:58:00 -0400 Subject: [PATCH 161/242] Implemented color 3D support --- dipy/viz/actor.py | 57 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index c98efb79c9..4543b28864 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -27,8 +27,8 @@ def slice(data, affine=None, value_range=None, opacity=1., Parameters ---------- - data : array, shape (X, Y, Z) - A 3D volume as a numpy array. + data : array, shape (X, Y, Z) or (X, Y, Z, 3) + A grayscale or rgb 3D volume as a numpy array. affine : array, shape (3, 3) Grid to space (usually RAS 1mm) transformation matrix value_range : None or tuple (2,) @@ -48,8 +48,16 @@ def slice(data, affine=None, value_range=None, opacity=1., coordinates as calculated by the affine parameter. """ -# if data.ndim != 3: -# raise ValueError('Only 3D arrays are currently supported.') + if data.ndim != 3: + if data.ndim == 4: + if data.shape[3] != 3: + raise ValueError('Only RGB 3D arrays are currently supported.') + else: + nb_components = 3 + else: + raise ValueError('Only 3D arrays are currently supported.') + else: + nb_components = 1 if value_range is None: vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) @@ -62,14 +70,14 @@ def slice(data, affine=None, value_range=None, opacity=1., im.SetScalarTypeToUnsignedChar() I, J, K = vol.shape[:3] im.SetDimensions(I, J, K) - voxsz = (1., 1., 1) + voxsz = (1., 1., 1.) # im.SetOrigin(0,0,0) im.SetSpacing(voxsz[2], voxsz[0], voxsz[1]) if major_version <= 5: im.AllocateScalars() - im.SetNumberOfScalarComponents(3) + im.SetNumberOfScalarComponents(nb_components) else: - im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) + im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, nb_components) # copy data # what I do below is the same as what is commented here but much faster @@ -79,12 +87,12 @@ def slice(data, affine=None, value_range=None, opacity=1., vol = np.swapaxes(vol, 0, 2) vol = np.ascontiguousarray(vol) - print(vol.shape) - vol = np.reshape(vol, [vol.shape[0]*vol.shape[1]*vol.shape[2], vol.shape[3]]) - print(vol.shape) + if nb_components == 1: + vol = vol.ravel() + else: + vol = np.reshape(vol, [vol.shape[0]*vol.shape[1]*vol.shape[2], vol.shape[3]]) + uchar_array = numpy_support.numpy_to_vtk(vol, deep=0) - -# uchar_array = numpy_support.numpy_to_vtk(vol.ravel(), deep=0) im.GetPointData().SetScalars(uchar_array) if affine is None: @@ -109,20 +117,16 @@ def slice(data, affine=None, value_range=None, opacity=1., image_resliced.SetInterpolationModeToLinear() image_resliced.Update() - if lookup_colormap is None: - # Create a black/white lookup table. - lut = colormap_lookup_table((0, 255), (0, 0), (0, 0), (0, 1)) - else: - lut = lookup_colormap + if nb_components == 1: + if lookup_colormap is None: + # Create a black/white lookup table. + lut = colormap_lookup_table((0, 255), (0, 0), (0, 0), (0, 1)) + else: + lut = lookup_colormap x1, x2, y1, y2, z1, z2 = im.GetExtent() ex1, ex2, ey1, ey2, ez1, ez2 = image_resliced.GetOutput().GetExtent() - plane_colors = vtk.vtkImageMapToColors() -# plane_colors.SetLookupTable(lut) - plane_colors.SetInputConnection(image_resliced.GetOutputPort()) - plane_colors.Update() - class ImageActor(vtk.vtkImageActor): def input_connection(self, output): @@ -168,7 +172,14 @@ def get_position(self): return self.GetPosition() image_actor = ImageActor() - image_actor.input_connection(plane_colors) + if nb_components == 1: + plane_colors = vtk.vtkImageMapToColors() + plane_colors.SetLookupTable(lut) + plane_colors.SetInputConnection(image_resliced.GetOutputPort()) + plane_colors.Update() + image_actor.input_connection(plane_colors) + else: + image_actor.input_connection(image_resliced) image_actor.display() image_actor.opacity(opacity) From 6fc5546cbd5b17d5c516612e0266851f5625c79b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 10:58:53 -0400 Subject: [PATCH 162/242] Corrected typos --- doc/examples/viz_advanced.py | 4 ++-- doc/examples/viz_bundles.py | 4 ++-- doc/examples/viz_slice.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 904780a7fa..caa6e9f4ae 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -50,7 +50,7 @@ """ We will use 3 bundles, FA and the affine transformation that brings the voxel -cordinates to world coordinates (RAS 1mm). +coordinates to world coordinates (RAS 1mm). """ streamlines = res['af.left'] + res['cst.right'] + res['cc_1'] @@ -146,7 +146,7 @@ def change_slice(obj, event): """ However, if you change the window size, the slider will not update its position properly. The solution to this issue is to update the position of the slider -using its ``place`` method everytime the window size changes. +using its ``place`` method every time the window size changes. """ global size diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 5ed6860818..e798f39706 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -3,7 +3,7 @@ Visualize bundles and metrics on bundles ======================================== -Frist, let's download some available datasets. Here we are using a dataset +First, let's download some available datasets. Here we are using a dataset which provides metrics and bundles. """ @@ -17,7 +17,7 @@ bundles=['cg.left', 'cst.right']) """ -Store franctional anisotropy. +Store fractional anisotropy. """ fa = dix['fa'] diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 9e7df600da..6524d6fb49 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -49,7 +49,7 @@ """ The ``slice`` function will read data and resample the data using an affine transformation matrix. The default behavior of this function is to show the -the middle slice of the last dimension of the resampled data. +middle slice of the last dimension of the resampled data. """ slice_actor = actor.slice(data, affine, value_range) From b706ba3d54604a161c1f607b4caf440c851cf4d4 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 11:04:47 -0400 Subject: [PATCH 163/242] Changed snapshot with record in examples --- doc/examples/viz_advanced.py | 2 +- doc/examples/viz_bundles.py | 12 ++++++------ doc/examples/viz_hud.py | 2 +- doc/examples/viz_slice.py | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index caa6e9f4ae..0c4faf75b8 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -171,7 +171,7 @@ def win_callback(obj, event): # show_m.render() # show_m.start() -window.snapshot(ren, 'bundles_and_a_slice.png', size=(1200, 900)) +window.record(ren, out_path='bundles_and_a_slice.png', size=(1200, 900)) """ .. figure:: bundles_and_a_slice.png diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index e798f39706..6d43046919 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -60,7 +60,7 @@ renderer.add(stream_actor) # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'bundle1.png', size=(600, 600)) +window.record(renderer, out_path='bundle1.png', size=(600, 600)) """ .. figure:: bundle1.png @@ -96,7 +96,7 @@ renderer.add(bar) # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'bundle2.png', size=(600, 600)) +window.record(renderer, out_path='bundle2.png', size=(600, 600)) """ .. figure:: bundle2.png @@ -126,7 +126,7 @@ renderer.add(bar2) # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'bundle3.png', size=(600, 600)) +window.record(renderer, out_path='bundle3.png', size=(600, 600)) """ .. figure:: bundle3.png @@ -147,7 +147,7 @@ renderer.add(stream_actor4) # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'bundle4.png', size=(600, 600)) +window.record(renderer, out_path='bundle4.png', size=(600, 600)) """ .. figure:: bundle4.png @@ -185,7 +185,7 @@ renderer.add(bar3) # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'bundle5.png', size=(600, 600)) +window.record(renderer, out_path='bundle5.png', size=(600, 600)) """ .. figure:: bundle5.png @@ -210,7 +210,7 @@ renderer.add(stream_actor6) # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'bundle6.png', size=(600, 600)) +window.record(renderer, out_path='bundle6.png', size=(600, 600)) """ .. figure:: bundle6.png diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index a5a8b2e8fe..2b6b8e184c 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -130,7 +130,7 @@ def win_callback(obj, event): # show_manager.start() -window.snapshot(renderer, 'mini_ui.png', size=(800, 800)) +window.record(renderer, out_path='mini_ui.png', size=(800, 800)) del show_manager diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 6524d6fb49..b1e4027a81 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -90,7 +90,7 @@ Otherwise, you can save a screenshot using the following command. """ -window.snapshot(renderer, 'slices.png', size=(600, 600)) +window.record(renderer, out_path='slices.png', size=(600, 600)) """ .. figure:: slices.png @@ -137,7 +137,7 @@ # window.show(renderer, size=(600, 600), reset_camera=False) -window.snapshot(renderer, 'slices_lut.png', size=(600, 600)) +window.record(renderer, out_path='slices_lut.png', size=(600, 600)) """ .. figure:: slices_lut.png @@ -198,7 +198,7 @@ in/out using the scroll wheel. """ -window.snapshot(renderer, 'mosaic.png', size=(900, 600)) +window.record(renderer, out_path='mosaic.png', size=(900, 600)) """ .. figure:: mosaic.png From da86cba4e37419d3703fff77a43cdb576cae66c3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 11:14:13 -0400 Subject: [PATCH 164/242] BF: Removed raise error excluding snapshot for VTK 5. The problem was GPU specific and not related to VTK5/6 issue --- dipy/viz/window.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 1c6849f97f..3d98836eae 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -497,9 +497,6 @@ def snapshot(ren, fname=None, size=(300, 300)): holds the RGB values. """ - if vtk.VTK_MAJOR_VERSION <= 5: - raise ImportError('Snapshot is available only for VTK 6+') - width, height = size graphics_factory = vtk.vtkGraphicsFactory() From 39045b8d73e9f4ac79c6e1f3034eddc7eabeec60 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 14:50:05 -0400 Subject: [PATCH 165/242] Commented window callback by default in tutorial --- doc/examples/viz_advanced.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 0c4faf75b8..7cba8b2091 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -119,6 +119,7 @@ callback which will be given to the ``slider`` function. """ + def change_slice(obj, event): z = int(np.round(obj.get_value())) image_actor.display_extent(0, shape[0] - 1, @@ -161,16 +162,19 @@ def win_callback(obj, event): size = obj.GetSize() show_m.initialize() -show_m.add_window_callback(win_callback) """ Finally, please uncomment the following lines so that you can interact with the available 3D and 2D objects. """ +# show_m.add_window_callback(win_callback) # show_m.render() # show_m.start() +ren.zoom(1.5) +ren.reset_clipping_range() + window.record(ren, out_path='bundles_and_a_slice.png', size=(1200, 900)) """ @@ -180,3 +184,4 @@ def win_callback(obj, event): **A few bundles with interactive slicing**. """ +del show_m From b6a0f3bda34128f24c32ca50ae3f9c9878e57f83 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 14:51:33 -0400 Subject: [PATCH 166/242] Added many more options for handling the camera in renderer. --- dipy/viz/window.py | 57 +++++++++++++++++++++++++++++++++++++++++ doc/examples/viz_hud.py | 10 +++++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 3d98836eae..412f588410 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -97,6 +97,9 @@ def reset_camera(self): """ self.ResetCamera() + def reset_clipping_range(self): + self.ResetCameraClippingRange() + def get_camera(self): return self.GetActiveCamera() @@ -117,17 +120,71 @@ def set_camera(self, position=None, focal_point=None, view_up=None): @property def size(self): + """ Renderer size""" return self.GetSize() def zoom(self, value): + """ In perspective mode, decrease the view angle by the specified + factor. In parallel mode, decrease the parallel scale by the specified + factor. A value greater than 1 is a zoom-in, a value less than 1 is a + zoom-out. + """ self.GetActiveCamera().Zoom(value) def azimuth(self, angle): + """ Rotate the camera about the view up vector centered at the focal + point. Note that the view up vector is whatever was set via SetViewUp, + and is not necessarily perpendicular to the direction of projection. + The result is a horizontal rotation of the camera. + """ self.GetActiveCamera().Azimuth(angle) + def yaw(self, angle): + """ Rotate the focal point about the view up vector, using the camera's + position as the center of rotation. Note that the view up vector is + whatever was set via SetViewUp, and is not necessarily perpendicular + to the direction of projection. The result is a horizontal rotation of + the scene. + """ + self.GetActiveCamera().Yaw(angle) + + def elevation(self, angle): + """ Rotate the camera about the cross product of the negative of the + direction of projection and the view up vector, using the focal point + as the center of rotation. The result is a vertical rotation of the + scene. + """ + self.GetActiveCamera().Elevation(angle) + + def pitch(self, angle): + """ Rotate the focal point about the cross product of the view up + vector and the direction of projection, using the camera's position as + the center of rotation. The result is a vertical rotation of the + camera. + """ + self.GetActiveCamera().Pitch(angle) + def roll(self, angle): + """ Rotate the camera about the direction of projection. This will + spin the camera about its axis. + """ self.GetActiveCamera().Roll(angle) + def dolly(self, value): + """ Divide the camera's distance from the focal point by the given + dolly value. Use a value greater than one to dolly-in toward the focal + point, and use a value less than one to dolly-out away from the focal + point. + """ + self.GetActiveCamera().Dolly(value) + + def camera_direction(self): + """ Get the vector in the direction from the camera position to the + focal point. This is usually the opposite of the ViewPlaneNormal, the + vector perpendicular to the screen, unless the view is oblique. + """ + return self.GetActiveCamera().GetDirectionOfProjection() + def renderer(background=None): """ Create a renderer. diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index 2b6b8e184c..972089dca9 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -77,6 +77,7 @@ def button_minus_callback(obj, event): button_minus_callback, button_png_minus, (.98, .9), (50, 50)) + def move_lines(obj, event): stream_actor.SetPosition((obj.get_value(), 0, 0)) @@ -104,6 +105,7 @@ def move_lines(obj, event): on the correct side of the window when the window is being resized. """ + def win_callback(obj, event): global size if size != obj.GetSize(): @@ -113,8 +115,6 @@ def win_callback(obj, event): slider.place(renderer) size = obj.GetSize() - -show_manager.add_window_callback(win_callback) # you can also register any callback in a vtk way like this # show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, # win_callback) @@ -122,14 +122,16 @@ def win_callback(obj, event): renderer.zoom(0.7) renderer.roll(10.) -show_manager.render() - """ Uncomment the following line to start the interaction. """ +# show_manager.add_window_callback(win_callback) +# show_manager.render() # show_manager.start() +renderer.reset_clipping_range() + window.record(renderer, out_path='mini_ui.png', size=(800, 800)) del show_manager From efd19bf71cb8dad0cd4b515439e7aceef8b6dbf1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 15:03:56 -0400 Subject: [PATCH 167/242] Added more meat in camera --- dipy/viz/window.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 412f588410..ec6a723ccb 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -40,14 +40,13 @@ class Renderer(vtkRenderer): - """ The key rendering preparation object + """ Your scene class This is an important object that is responsible for preparing objects e.g. actors and volumes for rendering. This is a more pythonic version of ``vtkRenderer`` proving simple methods for adding and removing actors but also it provides access to all the functionality - available in ``vtkRenderer``. - + available in ``vtkRenderer`` if necessary. """ def background(self, color): @@ -93,16 +92,21 @@ def projection(self, proj_type='perspective'): self.GetActiveCamera().ParallelProjectionOff() def reset_camera(self): - """ Allow the renderer to reset the camera + """ Reset the camera to an automatic position given by the engine. """ self.ResetCamera() def reset_clipping_range(self): self.ResetCameraClippingRange() - def get_camera(self): + @property + def camera(self): return self.GetActiveCamera() + def get_camera(self): + cam = self.GetActiveCamera() + return cam.GetPosition(), cam.GetFocalPoint(), cam.GetViewUp() + def camera_info(self): cam = self.get_camera() print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) From 444b8d49d56116f841fb78e5ddbbdc7ab18c6691 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 15:14:36 -0400 Subject: [PATCH 168/242] Removed property objects from Renderer because multiple inheritance with the object class is not allowed --- dipy/viz/window.py | 9 ++++----- doc/examples/viz_bundles.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index ec6a723ccb..d0166ce793 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -99,7 +99,6 @@ def reset_camera(self): def reset_clipping_range(self): self.ResetCameraClippingRange() - @property def camera(self): return self.GetActiveCamera() @@ -109,9 +108,10 @@ def get_camera(self): def camera_info(self): cam = self.get_camera() - print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) - print('Camera Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) - print('Camera View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) + print('# Camera info') + print('\tPosition (%.2f, %.2f, %.2f)' % cam.GetPosition()) + print('\tFocal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) + print('\tView Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) def set_camera(self, position=None, focal_point=None, view_up=None): if position is not None: @@ -122,7 +122,6 @@ def set_camera(self, position=None, focal_point=None, view_up=None): self.GetActiveCamera().SetViewUp(*view_up) self.ResetCameraClippingRange() - @property def size(self): """ Renderer size""" return self.GetSize() diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 6d43046919..bf71b809b2 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -74,7 +74,7 @@ focal point and view up vectors of the camera. """ -renderer.camera_info() +renderer.camera_info """ Show every point with a value from a volume with default colormap From 6bae7697f460ba1799834efb64b1f6d3dbaefb28 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 15:19:58 -0400 Subject: [PATCH 169/242] RF: minor corrections after the removal of property decorators from renderer --- dipy/viz/window.py | 2 +- doc/examples/viz_bundles.py | 2 +- doc/examples/viz_hud.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index d0166ce793..0cb814b712 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -107,7 +107,7 @@ def get_camera(self): return cam.GetPosition(), cam.GetFocalPoint(), cam.GetViewUp() def camera_info(self): - cam = self.get_camera() + cam = self.camera() print('# Camera info') print('\tPosition (%.2f, %.2f, %.2f)' % cam.GetPosition()) print('\tFocal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index bf71b809b2..6d43046919 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -74,7 +74,7 @@ focal point and view up vectors of the camera. """ -renderer.camera_info +renderer.camera_info() """ Show every point with a value from a volume with default colormap diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index 972089dca9..a362fccd26 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -98,7 +98,7 @@ def move_lines(obj, event): selected_color=(0.2, 0.2, 0.2)) global size -size = renderer.GetSize() +size = renderer.size() """ This callback is used to update the buttons/sliders' position so they can stay From 5835257265689fca136279899105c64a98390c10 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 15:40:35 -0400 Subject: [PATCH 170/242] RF: changed actor.slice to actor.slicer sounds better --- dipy/viz/actor.py | 8 ++++---- dipy/viz/tests/test_fvtk_actors.py | 4 ++-- doc/examples/viz_advanced.py | 4 ++-- doc/examples/viz_slice.py | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 4543b28864..1555cead2b 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,14 +21,14 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() -def slice(data, affine=None, value_range=None, opacity=1., +def slicer(data, affine=None, value_range=None, opacity=1., lookup_colormap=None): - """ Cuts 3D volumes into images + """ Cuts 3D scalar or rgb volumes into images Parameters ---------- data : array, shape (X, Y, Z) or (X, Y, Z, 3) - A grayscale or rgb 3D volume as a numpy array. + A grayscale or rgb 4D volume as a numpy array. affine : array, shape (3, 3) Grid to space (usually RAS 1mm) transformation matrix value_range : None or tuple (2,) @@ -86,7 +86,7 @@ def slice(data, affine=None, value_range=None, opacity=1., # im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) vol = np.swapaxes(vol, 0, 2) vol = np.ascontiguousarray(vol) - + if nb_components == 1: vol = vol.ravel() else: diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 4918057196..e374e989d0 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -12,13 +12,13 @@ @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) @npt.dec.skipif(not window.have_imread) -def test_slice(): +def test_slicer(): renderer = window.renderer() data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) - slicer = actor.slice(data, affine) + slicer = actor.slicer(data, affine) window.add(renderer, slicer) # window.show(renderer) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 7cba8b2091..4fc6725097 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -85,9 +85,9 @@ stream_actor = actor.line(streamlines) if not world_coords: - image_actor = actor.slice(data, affine=np.eye(4)) + image_actor = actor.slicer(data, affine=np.eye(4)) else: - image_actor = actor.slice(data, affine) + image_actor = actor.slicer(data, affine) """ For fun let's change also the opacity of the slicer diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index b1e4027a81..c4a2a79451 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -52,7 +52,7 @@ middle slice of the last dimension of the resampled data. """ -slice_actor = actor.slice(data, affine, value_range) +slice_actor = actor.slicer(data, affine, value_range) """ The ``slice_actor`` contains an axial slice. @@ -127,7 +127,7 @@ to (0, 255). """ -fa_actor = actor.slice(fa, affine, lookup_colormap=lut) +fa_actor = actor.slicer(fa, affine, lookup_colormap=lut) renderer.clear() renderer.add(fa_actor) From deaa0580237123feb541e0148c7b37efa3018903 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 15:49:34 -0400 Subject: [PATCH 171/242] RF: minor change in printing camera info --- dipy/viz/window.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 0cb814b712..8b8984ad11 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -108,10 +108,10 @@ def get_camera(self): def camera_info(self): cam = self.camera() - print('# Camera info') - print('\tPosition (%.2f, %.2f, %.2f)' % cam.GetPosition()) - print('\tFocal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) - print('\tView Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) + print('# Active Camera') + print(' Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) + print(' Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) + print(' View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) def set_camera(self, position=None, focal_point=None, view_up=None): if position is not None: From 5e5c46a4450795dd019948aaaacb0bcbccb298bb Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 15:57:39 -0400 Subject: [PATCH 172/242] Cleaning up lame old buggy slicer with new more powerful one --- dipy/viz/fvtk.py | 160 +------------------------------------------- doc/api_changes.rst | 16 ++++- 2 files changed, 14 insertions(+), 162 deletions(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 7bf22c7027..839dda1cfe 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -66,7 +66,7 @@ from dipy.viz.window import (ren, renderer, add, clear, rm, rm_all, show, record, snapshot) - from dipy.viz.actor import line, streamtube + from dipy.viz.actor import line, streamtube, slicer def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): @@ -1089,164 +1089,6 @@ def tensor(evals, evecs, scalar_colors=None, sphere=None, scale=2.2, norm=True): return actor -def slicer(vol, voxsz=(1.0, 1.0, 1.0), plane_i=[0], plane_j=None, - plane_k=None, outline=True): - """ Slice a 3D volume - - Parameters - ---------- - vol : array, shape (N, M, K) - An array representing the volumetric dataset that we want to slice - voxsz : sequence of 3 floats - Voxel size. - plane_i : sequence of ints - show plane or planes along the first dimension - plane_j : sequence of ints - show plane or planes along the second dimension - plane_k : sequence of ints - show plane or planes along the third(last) dimension - outline : bool - if True (default) a small outline is drawn around the slices - - Examples - -------- - >>> import numpy as np - >>> from dipy.viz import fvtk - >>> x, y, z = np.ogrid[-10:10:80j, -10:10:80j, -10:10:80j] - >>> s = np.sin(x * y * z) / (x * y * z) - >>> r = fvtk.ren() - >>> fvtk.add(r, fvtk.slicer(s, plane_i=[0, 5])) - >>> #fvtk.show(r) - """ - - if plane_i is None: - plane_i = [] - if plane_j is None: - plane_j = [] - if plane_k is None: - plane_k = [] - - if vol.ndim != 3: - raise ValueError("vol has to be a 3d array") - - vol = np.interp(vol, xp=[vol.min(), vol.max()], fp=[0, 255]) - vol = vol.astype('uint8') - - im = vtk.vtkImageData() - if major_version <= 5: - im.SetScalarTypeToUnsignedChar() - I, J, K = vol.shape[:3] - im.SetDimensions(I, J, K) - # im.SetOrigin(0,0,0) - im.SetSpacing(voxsz[2], voxsz[0], voxsz[1]) - if major_version <= 5: - im.AllocateScalars() - else: - im.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) - - # copy data - for i in range(vol.shape[0]): - for j in range(vol.shape[1]): - for k in range(vol.shape[2]): - im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) - - #from dipy.viz.utils import ndarray_to_vtkimagedata - #im = ndarray_to_vtkimagedata(vol) - - # An outline provides context around the data. - outlineData = vtk.vtkOutlineFilter() - if major_version <= 5: - outlineData.SetInput(im) - else: - outlineData.SetInputData(im) - - mapOutline = vtk.vtkPolyDataMapper() - mapOutline.SetInputConnection(outlineData.GetOutputPort()) - outline_ = vtk.vtkActor() - outline_.SetMapper(mapOutline) - outline_.GetProperty().SetColor(1, 0, 0) - - # Now we are creating three orthogonal planes passing through the - # volume. Each plane uses a different texture map and therefore has - # diferent coloration. - - # Start by creatin a black/white lookup table. - lut = vtk.vtkLookupTable() - lut.SetTableRange(vol.min(), vol.max()) - lut.SetSaturationRange(0, 0) - lut.SetHueRange(0, 0) - lut.SetValueRange(0, 1) - lut.SetRampToLinear() - lut.Build() - - x1, x2, y1, y2, z1, z2 = im.GetExtent() - - # print x1,x2,y1,y2,z1,z2 - - # Create the first of the three planes. The filter vtkImageMapToColors - # maps the data through the corresponding lookup table created above. - # The vtkImageActor is a type of vtkProp and conveniently displays an - # image on a single quadrilateral plane. It does this using texture - # mapping and as a result is quite fast. (Note: the input image has to - # be unsigned char values, which the vtkImageMapToColors produces.) - # Note also that by specifying the DisplayExtent, the pipeline - # requests data of this extent and the vtkImageMapToColors only - # processes a slice of data. - planeColors = vtk.vtkImageMapToColors() - # saggitalColors.SetInputConnection(im.GetOutputPort()) - if major_version <= 5: - planeColors.SetInput(im) - else: - planeColors.SetInputData(im) - planeColors.SetLookupTable(lut) - planeColors.Update() - - saggitals = [] - for x in plane_i: - - saggital = vtk.vtkImageActor() - if major_version <= 5: - saggital.SetInput(planeColors.GetOutput()) - else: - saggital.SetInputData(planeColors.GetOutput()) - saggital.SetDisplayExtent(x, x, y1, y2, z1, z2) - saggitals.append(saggital) - - axials = [] - for z in plane_k: - axial = vtk.vtkImageActor() - if major_version <= 5: - axial.SetInput(planeColors.GetOutput()) - else: - axial.SetInputData(planeColors.GetOutput()) - axial.SetDisplayExtent(x1, x2, y1, y2, z, z) - axials.append(axial) - - coronals = [] - for y in plane_j: - coronal = vtk.vtkImageActor() - if major_version <= 5: - coronal.SetInput(planeColors.GetOutput()) - else: - coronal.SetInputData(planeColors.GetOutput()) - coronal.SetDisplayExtent(x1, x2, y, y, z1, z2) - coronals.append(coronal) - - assem = vtk.vtkAssembly() - - for sag in saggitals: - assem.AddPart(sag) - for ax in axials: - assem.AddPart(ax) - for cor in coronals: - assem.AddPart(cor) - - if outline: - assem.AddPart(outline_) - - return assem - - def camera(ren, pos=None, focal=None, viewup=None, verbose=True): """ Change the active camera diff --git a/doc/api_changes.rst b/doc/api_changes.rst index a9a8abe385..f33ceb3fcf 100644 --- a/doc/api_changes.rst +++ b/doc/api_changes.rst @@ -5,15 +5,25 @@ API changes Here we provide information about functions or classes that have been removed, renamed or are deprecated (not recommended) during different release circles. +Dipy 0.10 Changes +----------------- + +** New visualization module** + +``fvtk.slicer`` input parameters have changed. Now the slicer function is +more powerfull and supports RGB images too. See tutorial ``viz_slice.py`` for +more information. + + Dipy 0.9 Changes ---------------- **GQI integration length** -Calculation of integration length in GQI2 now matches the calculation in the -'standard' method. Using values of 1-1.3 for either is recommended (see +Calculation of integration length in GQI2 now matches the calculation in the +'standard' method. Using values of 1-1.3 for either is recommended (see docs and references therein). - + Dipy 0.8 Changes ---------------- From d484c290f904447ad37bc434d2ff184ae377a0c1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 16:02:25 -0400 Subject: [PATCH 173/242] Removed unused import --- dipy/viz/fvtk.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 839dda1cfe..db304bf05b 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -19,8 +19,6 @@ from dipy.utils.six.moves import xrange -import types - import numpy as np from dipy.core.ndindex import ndindex From fff45e9fa776e8c379d34dc84275c6323db061b9 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 14 Aug 2015 16:16:55 -0400 Subject: [PATCH 174/242] Updated old test to use the new slicer --- dipy/viz/tests/test_fvtk.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dipy/viz/tests/test_fvtk.py b/dipy/viz/tests/test_fvtk.py index 15b9802317..0e7cd751e1 100644 --- a/dipy/viz/tests/test_fvtk.py +++ b/dipy/viz/tests/test_fvtk.py @@ -1,4 +1,4 @@ -""" Testing vizualization with fvtk +""" Testing visualization with fvtk """ import numpy as np @@ -11,6 +11,8 @@ @npt.dec.skipif(not fvtk.have_vtk) @npt.dec.skipif(not fvtk.have_vtk_colors) def test_fvtk_functions(): + # This tests will fail if any of the given actors changed inputs or do + # not exist # Create a renderer r = fvtk.ren() @@ -41,7 +43,9 @@ def test_fvtk_functions(): fvtk.add(r, l) # Slice the volume - fvtk.add(r, fvtk.slicer(vol, plane_i=[50])) + slicer = fvtk.slicer(vol) + slicer.display(50, None, None) + fvtk.add(r, slicer) # Change the position of the active camera fvtk.camera(r, pos=(0.6, 0, 0), verbose=False) @@ -57,9 +61,6 @@ def test_fvtk_functions(): colors=(0, 1, 0)) fvtk.add(r, p2) - # Show everything - # fvtk.show(r) - @npt.dec.skipif(not fvtk.have_vtk) @npt.dec.skipif(not fvtk.have_vtk_colors) @@ -107,3 +108,8 @@ def test_colormaps_matplotlib(): rgba2 = data.get_cmap(name)(v) # dipy's colormaps are close to matplotlibs colormaps, but not perfect npt.assert_array_almost_equal(rgba1, rgba2, 1) + + +if __name__ == "__main__": + + npt.run_module_suite() From a372c7a0b54f94d400114438564b1457449def9b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 15 Aug 2015 14:57:07 -0400 Subject: [PATCH 175/242] Increasing test coverage for new slicer --- dipy/viz/actor.py | 2 +- dipy/viz/tests/test_fvtk_actors.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 1555cead2b..e838d14b0a 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -90,7 +90,7 @@ def slicer(data, affine=None, value_range=None, opacity=1., if nb_components == 1: vol = vol.ravel() else: - vol = np.reshape(vol, [vol.shape[0]*vol.shape[1]*vol.shape[2], vol.shape[3]]) + vol = np.reshape(vol, [np.prod(vol.shape[:3]), vol.shape[3]]) uchar_array = numpy_support.numpy_to_vtk(vol, deep=0) im.GetPointData().SetScalars(uchar_array) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index e374e989d0..fce4949df7 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -42,6 +42,24 @@ def test_slicer(): report = window.analyze_snapshot(fname, find_objects=True) npt.assert_equal(report.objects, 1) + npt.assert_raises(ValueError, actor.slicer, np.ones(10)) + + renderer.clear() + + rgb = np.zeros((30, 30, 30, 3)) + rgb[..., 0] = 1. + rgb_actor = actor.slicer(rgb) + + renderer.add(rgb_actor) + + renderer.reset_camera() + renderer.reset_clipping_range() + + arr = window.snapshot(renderer) + report = window.analyze_snapshot(arr, colors=[(255, 0, 0)]) + npt.assert_equal(report.objects, 1) + npt.assert_equal(report.colors_found, [True]) + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) From 5cb3b015fd87c0fe0088c73acf5cd419b91dbd22 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 15 Aug 2015 15:32:35 -0400 Subject: [PATCH 176/242] TEST: triggering spline subdivision --- dipy/viz/tests/test_fvtk_actors.py | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index fce4949df7..7dfb07a921 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -60,6 +60,27 @@ def test_slicer(): npt.assert_equal(report.objects, 1) npt.assert_equal(report.colors_found, [True]) + lut = actor.colormap_lookup_table(scale_range=(0, 255), + hue_range=(0.4, 1.), + saturation_range=(1, 1.), + value_range=(0., 1.)) + renderer.clear() + slicer_lut = actor.slicer(data, lookup_colormap=lut) + + slicer_lut.display(10, None, None) + slicer_lut.display(None, 10, None) + slicer_lut.display(None, None, 10) + + slicer_lut2 = slicer_lut.copy() + slicer_lut2.display(None, None, 10) + renderer.add(slicer_lut2) + + renderer.reset_clipping_range() + + arr = window.snapshot(renderer) + report = window.analyze_snapshot(arr, find_objects=True) + npt.assert_equal(report.objects, 1) + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) @@ -90,6 +111,20 @@ def test_streamtube_and_line_actors(): npt.assert_equal(report.objects, 4) npt.assert_equal(report.colors_found, [True, True]) + # as before with splines + c2 = actor.streamtube(lines, colors, spline_subdiv=5, linewidth=.1) + c2.SetPosition(2, 0, 0) + window.add(renderer, c2) + + arr = window.snapshot(renderer) + + report = window.analyze_snapshot(arr, + colors=[(255, 0, 0), (0, 0, 255)], + find_objects=True) + + npt.assert_equal(report.objects, 4) + npt.assert_equal(report.colors_found, [True, True]) + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) From 4c77eb9249cc56ce91ec5b608d595f2c003cad28 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 15 Aug 2015 15:34:27 -0400 Subject: [PATCH 177/242] TEST: triggering spline subdivision --- dipy/viz/tests/test_fvtk_actors.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 7dfb07a921..e53bc77d45 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -97,6 +97,10 @@ def test_streamtube_and_line_actors(): c = actor.line(lines, colors, linewidth=3) window.add(renderer, c) + c = actor.line(lines, colors, spline_subdiv=5, linewidth=3) + window.add(renderer, c) + + # create streamtubes of the same lines and shift them a bit c2 = actor.streamtube(lines, colors, linewidth=.1) c2.SetPosition(2, 0, 0) From 2a930dcf22e0dcb977af9ce1c8710504d893edb1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 15 Aug 2015 16:01:04 -0400 Subject: [PATCH 178/242] Up to 97% coverage for fdipy.viz.actor --- dipy/viz/tests/test_fvtk_actors.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index e53bc77d45..05d90c90a3 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -197,6 +197,14 @@ def test_bundle_maps(): report2 = window.analyze_snapshot(arr) npt.assert_equal(report2.objects, 1) + #try other input options for colors + renderer.clear() + actor.line(bundle, (1., 0.5, 0)) + actor.line(bundle, np.arange(len(bundle))) + actor.line(bundle) + colors=[np.random.rand(*b.shape) for b in bundle] + actor.line(bundle, colors=colors) + if __name__ == "__main__": From 3139aabea26bb931d72e1d2976b44e47e710fa48 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 17 Aug 2015 16:46:22 -0400 Subject: [PATCH 179/242] Increased coverage in viz.window --- dipy/viz/actor.py | 60 ++++++++++++++++++++++ dipy/viz/fvtk.py | 67 +++--------------------- dipy/viz/tests/test_fvtk_window.py | 81 +++++++++++++++++++++++++++--- 3 files changed, 141 insertions(+), 67 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index e838d14b0a..31a0b89359 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -586,3 +586,63 @@ def scalar_bar(lookup_table=None, title=" "): scalar_bar.SetNumberOfLabels(6) return scalar_bar + + +def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): + ''' Internal function for generating arrow actors. + ''' + arrow = vtk.vtkArrowSource() + # arrow.SetTipLength(length) + + arrowm = vtk.vtkPolyDataMapper() + + if major_version <= 5: + arrowm.SetInput(arrow.GetOutput()) + else: + arrowm.SetInputConnection(arrow.GetOutputPort()) + + arrowa = vtk.vtkActor() + arrowa.SetMapper(arrowm) + + arrowa.GetProperty().SetColor(color) + arrowa.GetProperty().SetOpacity(opacity) + arrowa.SetScale(scale) + + return arrowa + + +def axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), + opacity=1): + """ Create an actor with the coordinate's system axes where + red = x, green = y, blue = z. + + Parameters + ---------- + scale : tuple (3,) + axes size e.g. (100, 100, 100) + colorx : tuple (3,) + x-axis color. Default red. + colory : tuple (3,) + y-axis color. Default blue. + colorz : tuple (3,) + z-axis color. Default green. + + Returns + ------- + vtkAssembly + + """ + + arrowx = _arrow(color=colorx, scale=scale, opacity=opacity) + arrowy = _arrow(color=colory, scale=scale, opacity=opacity) + arrowz = _arrow(color=colorz, scale=scale, opacity=opacity) + + arrowy.RotateZ(90) + arrowz.RotateY(-90) + + ass = vtk.vtkAssembly() + ass.AddPart(arrowx) + ass.AddPart(arrowy) + ass.AddPart(arrowz) + + return ass \ No newline at end of file diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index db304bf05b..30ebed9e90 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -16,6 +16,7 @@ http://www.vtk.org/Wiki/VTK/Tutorials/External_Tutorials ''' from __future__ import division, print_function, absolute_import +from warnings import warn from dipy.utils.six.moves import xrange @@ -64,67 +65,7 @@ from dipy.viz.window import (ren, renderer, add, clear, rm, rm_all, show, record, snapshot) - from dipy.viz.actor import line, streamtube, slicer - - -def _arrow(pos=(0, 0, 0), color=(1, 0, 0), scale=(1, 1, 1), opacity=1): - ''' Internal function for generating arrow actors. - ''' - arrow = vtk.vtkArrowSource() - # arrow.SetTipLength(length) - - arrowm = vtk.vtkPolyDataMapper() - - if major_version <= 5: - arrowm.SetInput(arrow.GetOutput()) - else: - arrowm.SetInputConnection(arrow.GetOutputPort()) - - arrowa = vtk.vtkActor() - arrowa.SetMapper(arrowm) - - arrowa.GetProperty().SetColor(color) - arrowa.GetProperty().SetOpacity(opacity) - arrowa.SetScale(scale) - - return arrowa - - -def axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), - opacity=1): - """ Create an actor with the coordinate's system axes where - red = x, green = y, blue = z. - - Parameters - ---------- - scale : tuple (3,) - axes size e.g. (100, 100, 100) - colorx : tuple (3,) - x-axis color. Default red. - colory : tuple (3,) - y-axis color. Default blue. - colorz : tuple (3,) - z-axis color. Default green. - - Returns - ------- - vtkAssembly - - """ - - arrowx = _arrow(color=colorx, scale=scale, opacity=opacity) - arrowy = _arrow(color=colory, scale=scale, opacity=opacity) - arrowz = _arrow(color=colorz, scale=scale, opacity=opacity) - - arrowy.RotateZ(90) - arrowz.RotateY(-90) - - ass = vtk.vtkAssembly() - ass.AddPart(arrowx) - ass.AddPart(arrowy) - ass.AddPart(arrowz) - - return ass + from dipy.viz.actor import line, streamtube, slicer, axes def dots(points, color=(1, 0, 0), opacity=1, dot_size=5): @@ -1107,6 +1048,10 @@ def camera(ren, pos=None, focal=None, viewup=None, verbose=True): vtkCamera """ + msg = "This function is deprecated." + msg += "Please use the window.Renderer class to get/set the active camera." + warn(DeprecationWarning(msg)) + cam = ren.GetActiveCamera() if verbose: print('Camera Position (%.2f,%.2f,%.2f)' % cam.GetPosition()) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 56db8a7030..fbe98d0b97 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -1,5 +1,5 @@ import numpy as np -from dipy.viz import actor, window, fvtk +from dipy.viz import actor, window import numpy.testing as npt @@ -27,7 +27,7 @@ def test_renderer(): npt.assert_equal(report.objects, 0) npt.assert_equal(report.colors_found, [True, False]) - axes = fvtk.axes() + axes = actor.axes() ren.add(axes) # window.show(ren) @@ -66,22 +66,90 @@ def test_renderer(): npt.assert_equal(report.actors, 0) +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_active_camera(): + renderer = window.Renderer() + renderer.add(actor.axes(scale=(1, 1, 1))) + + renderer.reset_camera() + renderer.reset_clipping_range() + + direction = renderer.camera_direction() + position, focal_point, view_up = renderer.get_camera() + + renderer.set_camera((0., 0., 1.), (0., 0., 0), view_up) + + position, focal_point, view_up = renderer.get_camera() + npt.assert_almost_equal(np.dot(direction, position), -1) + + renderer.zoom(1.5) + + new_position, _, _ = renderer.get_camera() + + npt.assert_array_almost_equal(position, new_position) + + renderer.zoom(1) + + # rotate around focal point + renderer.azimuth(90) + + position, _, _ = renderer.get_camera() + + npt.assert_almost_equal(position, (1.0, 0.0, 0)) + + arr = window.snapshot(renderer) + report = window.analyze_snapshot(arr, colors=[(255, 0, 0)]) + npt.assert_equal(report.colors_found, [True]) + + # rotate around camera's center + renderer.yaw(90) + + arr = window.snapshot(renderer) + report = window.analyze_snapshot(arr, colors=[(0, 0, 0)]) + npt.assert_equal(report.colors_found, [True]) + + renderer.yaw(-90) + renderer.elevation(90) + + arr = window.snapshot(renderer) + report = window.analyze_snapshot(arr, colors=[(0, 255, 0)]) + npt.assert_equal(report.colors_found, [True]) + + renderer.set_camera((0., 0., 1.), (0., 0., 0), view_up) + + # vertical rotation of the camera around the focal point + renderer.pitch(10) + renderer.pitch(-10) + + # rotate around the direction of projection + renderer.roll(90) + + # inverted normalized distance from focal point along the direction + # of the camera + + position, _, _ = renderer.get_camera() + renderer.dolly(0.5) + new_position, _, _ = renderer.get_camera() + npt.assert_almost_equal(position[2], 0.5 * new_position[2]) + + @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_parallel_projection(): ren = window.Renderer() - axes = fvtk.axes() + axes = actor.axes() ren.add(axes) - axes2 = fvtk.axes() + axes2 = actor.axes() axes2.SetPosition((2, 0, 0)) ren.add(axes2) # Put the camera on a angle so that the # camera can show the difference between perspective # and parallel projection - fvtk.camera(ren, pos=(1.5, 1.5, 1.5)) + ren.set_camera((1.5, 1.5, 1.5)) ren.GetActiveCamera().Zoom(2) # window.show(ren, reset_camera=True) @@ -100,4 +168,5 @@ def test_parallel_projection(): if __name__ == '__main__': - npt.run_module_suite() + # npt.run_module_suite() + test_active_camera() From 2db31b6de348d853141c72f0bbc735a1803b1f86 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 17 Aug 2015 16:57:11 -0400 Subject: [PATCH 180/242] RF: Removed unused functions from dipy.viz.utils --- dipy/viz/tests/test_fvtk_window.py | 2 +- dipy/viz/utils.py | 54 ------------------------------ 2 files changed, 1 insertion(+), 55 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index fbe98d0b97..c9070b1cbc 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -113,7 +113,7 @@ def test_active_camera(): renderer.elevation(90) arr = window.snapshot(renderer) - report = window.analyze_snapshot(arr, colors=[(0, 255, 0)]) + report = window.analyze_snapshot(arr, colors=(0, 255, 0)) npt.assert_equal(report.colors_found, [True]) renderer.set_camera((0., 0., 1.), (0., 0., 0), view_up) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index afabac19bb..cecab02fc9 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -65,29 +65,6 @@ def set_input(vtk_object, inp): return vtk_object -def evec_from_lines(lines, use_line_dir=True): - """ Get eigen vectors from lines directions in a 3x3 array - - if use_line_dir is set to False - only use the points position information - - """ - - if use_line_dir: - lines_dir = [] - for line in lines: - lines_dir += [line[1:] - line[0:-1]] - directions = np.vstack(lines_dir) - else: - points = np.vstack(lines) - centered_points = points - np.mean(points, axis=0) - norm = np.sqrt(np.sum(centered_points**2, axis=1, keepdims=True)) - directions = centered_points/norm - - U, e_val, e_vec = np.linalg.svd(directions, full_matrices=False) - return e_vec - - def map_coordinates_3d_4d(input_array, indices): """ Evaluate the input_array data at the given indices using trilinear interpolation @@ -117,34 +94,3 @@ def map_coordinates_3d_4d(input_array, indices): indices.T, order=1) values_4d.append(values_tmp) return np.ascontiguousarray(np.array(values_4d).T) - - -def rescale_to_uint8(data): - """ Rescales value of a ndarray to 8 bits unsigned integer - - This function rescales the values of the input between 0 and 255, - then copies it to a new 8 bits unsigned integer array. - - Parameters - ---------- - data : ndarray - - Return - ------ - uint8 : ndarray - - Note - ---- - NANs are clipped to 0. If min equals max, result will be all 0. - - """ - - temp = np.array(data, dtype=np.float64) - temp[np.isnan(temp)] = 0 - temp -= np.min(temp) - if np.max(temp) != 0.0: - temp /= np.max(temp) - temp *= 255.0 - temp = np.array(np.round(temp), dtype=np.uint8) - - return temp From c32d6be7c99ffb0cd76cdc4cd40f7f2a8042f3b8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 18 Aug 2015 15:34:24 -0400 Subject: [PATCH 181/242] NF: add option for ordering transparent actors with the Z buffer and also added more documentation in the ShowManager --- dipy/viz/window.py | 131 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 24 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 8b8984ad11..860a9a3a7f 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -293,9 +293,61 @@ def save_file_dialog(initial_file='dipy.png', default_ext='.png', class ShowManager(object): + """ This class is the interface between the renderer, the window and the + interactor. + """ + + def __init__(self, ren, title='DIPY', size=(300, 300), + png_magnify=1, reset_camera=True, order_transparent=False): - def __init__(self, ren, title='Dipy', size=(300, 300), - png_magnify=1, reset_camera=True): + """ Manages the visualization pipeline + + Parameters + ---------- + ren : Renderer() or vtkRenderer() + The scene that holds all the actors. + title : string + A string for the window title bar. + size : (int, int) + ``(width, height)`` of the window + png_magnify : int + Number of times to magnify the screenshot. This can be used to save + high resolution screenshots when pressing 's' inside the window. + reset_camera : bool + Default is True. You can change this option to False if you want to + keep the camera as set before calling this function. + order_transparent : bool + True is useful when you want to order transparent + actors according to their relative position to the camera. The + default option which is False will order the actors according to + the order of their addition to the Renderer(). + + Methods + ------- + initialize() + render() + start() + add_window_callback() + + Notes + ----- + Default interaction keys for + + * 3d navigation are with left, middle and right mouse dragging + * resetting the camera press 'r' + * saving a screenshot press 's' + * for quiting press 'q' + + Examples + -------- + >>> from dipy.viz import actor, window + >>> renderer = window.Renderer() + >>> renderer.add(actor.axes()) + >>> showm = window.ShowManager(renderer) + >>> # showm.initialize() + >>> # showm.render() + >>> # start() + """ self.title = title self.size = size @@ -307,12 +359,33 @@ def __init__(self, ren, title='Dipy', size=(300, 300), window = vtk.vtkRenderWindow() window.AddRenderer(ren) # window.SetAAFrames(6) - if title == 'Dipy': + if title == 'DIPY': window.SetWindowName(title + ' ' + dipy_version) else: window.SetWindowName(title) window.SetSize(size[0], size[1]) + if order_transparent: + + # Use a render window with alpha bits + # as default is 0 (false)) + window.SetAlphaBitPlanes(True) + + # Force to not pick a framebuffer with a multisample buffer + # (default is 8) + window.SetMultiSamples(0) + + # Choose to use depth peeling (if supported) + # (default is 0 (false)): + ren.UseDepthPeelingOn() + + # Set depth peeling parameters + # Set the maximum number of rendering passes (default is 4) + ren.SetMaximumNumberOfPeels(4) + + # Set the occlusion ratio (initial value is 0.0, exact image): + ren.SetOcclusionRatio(0.0) + style = vtk.vtkInteractorStyleTrackballCamera() iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(window) @@ -349,17 +422,22 @@ def key_press_standard(obj, event): self.style = style self.iren.AddObserver('KeyPressEvent', key_press_standard) - self.iren.SetInteractorStyle(self.style) def initialize(self): + """ Initialize interaction + """ self.iren.Initialize() # picker.Pick(85, 126, 0, ren) def render(self): + """ Renders only once + """ self.window.Render() def start(self): + """ Starts interaction + """ self.iren.Start() # window.RemoveAllObservers() # ren.SetRenderWindow(None) @@ -369,39 +447,44 @@ def start(self): del self.window def add_window_callback(self, win_callback): + """ Add window callbacks + """ self.window.AddObserver(vtk.vtkCommand.ModifiedEvent, win_callback) self.window.Render() -def show(ren, title='Dipy', size=(300, 300), - png_magnify=1, reset_camera=True): +def show(ren, title='DIPY', size=(300, 300), + png_magnify=1, reset_camera=True, order_transparent=False): """ Show window with current renderer - Parameters ------------ - ren : vtkRenderer() object - As returned from function ``ren()``. + ren : Renderer() or vtkRenderer() + The scene that holds all the actors. title : string A string for the window title bar. size : (int, int) ``(width, height)`` of the window png_magnify : int - Number of times to magnify the screenshot. + Number of times to magnify the screenshot. This can be used to save + high resolution screenshots when pressing 's' inside the window. + reset_camera : bool + Default is True. You can change this option to False if you want to + keep the camera as set before calling this function. + order_transparent : bool + True is useful when you want to order transparent + actors according to their relative position to the camera. The default + option which is False will order the actors according to the order of + their addition to the Renderer(). Notes ----- - If you want to: + Default interaction keys for - * navigate in the the 3d world use the left - middle - right mouse buttons - * reset the screen press 'r' - * save a screenshot press 's' - * quit press 'q' - - See also - --------- - dipy.viz.window.record - dipy.viz.window.snapshot + * 3d navigation are with left, middle and right mouse dragging + * resetting the camera press 'r' + * saving a screenshot press 's' + * for quiting press 'q' Examples ---------- @@ -417,13 +500,13 @@ def show(ren, title='Dipy', size=(300, 300), >>> #fvtk.show(r) See also - ---------- - dipy.viz.fvtk.record - + --------- + dipy.viz.window.record + dipy.viz.window.snapshot """ show_manager = ShowManager(ren, title, size, - png_magnify, reset_camera) + png_magnify, reset_camera, order_transparent) show_manager.initialize() show_manager.render() show_manager.start() From b225c93046e52551d399b65e10c435c78ce03e6a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 18 Aug 2015 15:35:44 -0400 Subject: [PATCH 182/242] DOC: updated viz_hud to have orderered transparent actors --- doc/examples/viz_hud.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_hud.py index a362fccd26..a32d912a7b 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_hud.py @@ -22,7 +22,7 @@ lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), np.array([[-1, 1, 0.], [1, 1, 0.]])] -colors = np.array([[1., 0., 0.], [1., 0.5, 0.]]) +colors = np.array([[1., 0., 0.], [0., .5, 0.]]) stream_actor = actor.streamtube(lines, colors, linewidth=0.3) renderer.add(stream_actor) @@ -32,7 +32,8 @@ the widgets can be added and updated properly. """ -show_manager = window.ShowManager(renderer, size=(800, 800)) +show_manager = window.ShowManager(renderer, size=(800, 800), + order_transparent=True) show_manager.initialize() @@ -43,6 +44,7 @@ global opacity opacity = 1. + def button_plus_callback(obj, event): print('+ pressed') global opacity @@ -142,4 +144,3 @@ def win_callback(obj, event): **A minimalistic user interface**. """ - From 75a289314a40f91cd100e877926430ddb6ad6f52 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 18 Aug 2015 17:10:32 -0400 Subject: [PATCH 183/242] NF: for simple cases where no new callbacks are added you can start and re-start the interaction from the showmanager --- dipy/viz/window.py | 61 +++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 860a9a3a7f..ef05b509d1 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -2,6 +2,7 @@ import numpy as np from scipy import ndimage +from copy import copy try: import Tkinter as tkinter @@ -322,6 +323,13 @@ def __init__(self, ren, title='DIPY', size=(300, 300), default option which is False will order the actors according to the order of their addition to the Renderer(). + Attributes + ---------- + ren : vtkRenderer() + iren : vtkRenderWindowInteractor() + style : vtkInteractorStyle() + window : vtkRenderWindow() + Methods ------- initialize() @@ -349,35 +357,38 @@ def __init__(self, ren, title='DIPY', size=(300, 300), >>> # start() """ + self.ren = ren self.title = title self.size = size self.png_magnify = png_magnify + self.reset_camera = reset_camera + self.order_transparent = order_transparent + + if self.reset_camera: + self.ren.ResetCamera() - if reset_camera: - ren.ResetCamera() + self.window = vtk.vtkRenderWindow() + self.window.AddRenderer(ren) - window = vtk.vtkRenderWindow() - window.AddRenderer(ren) - # window.SetAAFrames(6) - if title == 'DIPY': - window.SetWindowName(title + ' ' + dipy_version) + if self.title == 'DIPY': + self.window.SetWindowName(title + ' ' + dipy_version) else: - window.SetWindowName(title) - window.SetSize(size[0], size[1]) + self.window.SetWindowName(title) + self.window.SetSize(size[0], size[1]) - if order_transparent: + if self.order_transparent: # Use a render window with alpha bits # as default is 0 (false)) - window.SetAlphaBitPlanes(True) + self.window.SetAlphaBitPlanes(True) # Force to not pick a framebuffer with a multisample buffer # (default is 8) - window.SetMultiSamples(0) + self.window.SetMultiSamples(0) # Choose to use depth peeling (if supported) # (default is 0 (false)): - ren.UseDepthPeelingOn() + self.ren.UseDepthPeelingOn() # Set depth peeling parameters # Set the maximum number of rendering passes (default is 4) @@ -386,9 +397,9 @@ def __init__(self, ren, title='DIPY', size=(300, 300), # Set the occlusion ratio (initial value is 0.0, exact image): ren.SetOcclusionRatio(0.0) - style = vtk.vtkInteractorStyleTrackballCamera() - iren = vtk.vtkRenderWindowInteractor() - iren.SetRenderWindow(window) + self.style = vtk.vtkInteractorStyleTrackballCamera() + self.iren = vtk.vtkRenderWindowInteractor() + self.iren.SetRenderWindow(self.window) def key_press_standard(obj, event): @@ -416,11 +427,6 @@ def key_press_standard(obj, event): writer.Write() print('File ' + filepath + ' is saved.') - self.window = window - self.ren = ren - self.iren = iren - self.style = style - self.iren.AddObserver('KeyPressEvent', key_press_standard) self.iren.SetInteractorStyle(self.style) @@ -438,9 +444,20 @@ def render(self): def start(self): """ Starts interaction """ - self.iren.Start() + try: + self.iren.Start() + except AttributeError: + self.__init__(self.ren, self.title, size=self.size, + png_magnify=self.png_magnify, + reset_camera=self.reset_camera, + order_transparent=self.order_transparent) + self.initialize() + self.render() + self.iren.Start() + # window.RemoveAllObservers() # ren.SetRenderWindow(None) + self.window.RemoveRenderer(self.ren) self.ren.SetRenderWindow(None) del self.iren From 3838a380899b0bf4329672f47f6ac25476cdf88c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 18 Aug 2015 17:37:42 -0400 Subject: [PATCH 184/242] NF: allowing new interactor style for images and allowing for non-default interactors --- dipy/viz/window.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index ef05b509d1..818363bf8b 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -299,7 +299,8 @@ class ShowManager(object): """ def __init__(self, ren, title='DIPY', size=(300, 300), - png_magnify=1, reset_camera=True, order_transparent=False): + png_magnify=1, reset_camera=True, order_transparent=False, + interactor_style='trackball'): """ Manages the visualization pipeline @@ -322,6 +323,10 @@ def __init__(self, ren, title='DIPY', size=(300, 300), actors according to their relative position to the camera. The default option which is False will order the actors according to the order of their addition to the Renderer(). + interactor_style : str or vtkInteractorStyle + If str then if 'trackball' then vtkInteractorStyleTrackballCamera() + is used or if 'image' then vtkInteractorStyleImage() is used (no + rotation). Otherwise you can input your own interactor style. Attributes ---------- @@ -363,6 +368,7 @@ def __init__(self, ren, title='DIPY', size=(300, 300), self.png_magnify = png_magnify self.reset_camera = reset_camera self.order_transparent = order_transparent + self.interactor_style = interactor_style if self.reset_camera: self.ren.ResetCamera() @@ -397,7 +403,13 @@ def __init__(self, ren, title='DIPY', size=(300, 300), # Set the occlusion ratio (initial value is 0.0, exact image): ren.SetOcclusionRatio(0.0) - self.style = vtk.vtkInteractorStyleTrackballCamera() + if self.interactor_style == 'image': + self.style = vtk.vtkInteractorStyleImage() + elif self.interactor_style == 'trackball': + self.style = vtk.vtkInteractorStyleTrackballCamera() + else: + self.style = interactor_style + self.iren = vtk.vtkRenderWindowInteractor() self.iren.SetRenderWindow(self.window) @@ -450,7 +462,8 @@ def start(self): self.__init__(self.ren, self.title, size=self.size, png_magnify=self.png_magnify, reset_camera=self.reset_camera, - order_transparent=self.order_transparent) + order_transparent=self.order_transparent, + interactor_style=self.interactor_style) self.initialize() self.render() self.iren.Start() From 4ade99a8674ae2dfd459651236fc76f47db8e88b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 18 Aug 2015 18:15:49 -0400 Subject: [PATCH 185/242] TEST: added test for checking transparent order --- dipy/viz/tests/test_fvtk_window.py | 39 ++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index c9070b1cbc..6c72a8385d 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -166,7 +166,42 @@ def test_parallel_projection(): npt.assert_equal(np.sum(arr2 > 0) > np.sum(arr > 0), True) +@npt.dec.skipif(not actor.have_vtk) +@npt.dec.skipif(not actor.have_vtk_colors) +def test_order_transparent(): + + renderer = window.Renderer() + + lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), + np.array([[-1, 1, 0.], [1, 1, 0.]])] + colors = np.array([[1., 0., 0.], [0., .5, 0.]]) + stream_actor = actor.streamtube(lines, colors, linewidth=0.3, opacity=0.5) + + renderer.add(stream_actor) + + renderer.UseDepthPeelingOn() + renderer.SetMaximumNumberOfPeels(4) + renderer.SetOcclusionRatio(0.0) + + renderer.reset_camera() + + # green in front + renderer.elevation(90) + renderer.reset_clipping_range() + arr = window.snapshot(renderer) + + # therefore the green component must have a higher value (in RGB terms) + npt.assert_equal(arr[150, 150][1] > arr[150, 150][0], True) + + # red in front + renderer.elevation(-180) + renderer.reset_clipping_range() + arr = window.snapshot(renderer) + + # therefore the red component must have a higher value (in RGB terms) + npt.assert_equal(arr[150, 150][0] > arr[150, 150][1], True) + + if __name__ == '__main__': - # npt.run_module_suite() - test_active_camera() + npt.run_module_suite() From e316cdb507f130b3cee7d630efaa9cd0234f4d26 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 9 Oct 2015 14:34:35 -0400 Subject: [PATCH 186/242] Updated 2 fetcher with the new fetch data scheme and corrected many pep8 issues in the same file. --- dipy/data/fetcher.py | 346 ++++++++++++++++++++----------------------- 1 file changed, 160 insertions(+), 186 deletions(-) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 3ed2931d54..72dc4d4536 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -16,6 +16,7 @@ import numpy as np import nibabel as nib +import tarfile import zipfile from dipy.core.gradients import gradient_table from dipy.io.gradients import read_bvals_bvecs @@ -132,8 +133,7 @@ def fetch_data(files, folder, data_size=None): def _make_fetcher(name, folder, baseurl, remote_fnames, local_fnames, md5_list=None, doc="", data_size=None, msg=None, unzip=False): - """ - Create a new fetcher + """ Create a new fetcher Parameters ---------- @@ -158,9 +158,10 @@ def _make_fetcher(name, folder, baseurl, remote_fnames, local_fnames, starts. msg : str, optional. A message to print to screen when fetching takes place. Default (None) - is not to print anything + is to print nothing unzip : bool, optional - Whether to unzip the file(s) after downloading them + Whether to unzip the file(s) after downloading them. Supports zip, gz, + and tar.gz files. returns ------- fetcher : function @@ -178,8 +179,21 @@ def fetcher(): print(msg) if unzip: for f in local_fnames: - z = zipfile.ZipFile(pjoin(folder, f), 'r') - z.extractall(dipy_home) + split_ext = os.path.splitext(f) + if split_ext[-1] == '.gz' or split_ext[-1] == '.bz2': + if os.path.splitext(split_ext[0])[-1] == '.tar': + ar = tarfile.open(pjoin(folder, f)) + ar.extractall(path=folder) + ar.close() + else: + raise ValueError('File extension is not recognized') + elif split_ext[-1] == '.zip': + z = zipfile.ZipFile(pjoin(folder, f), 'r') + z.extractall(folder) + z.close() + else: + raise ValueError('File extension is not recognized') + return files, folder fetcher.__name__ = name @@ -187,123 +201,146 @@ def fetcher(): return fetcher -fetch_isbi2013_2shell = _make_fetcher("fetch_isbi2013_2shell", - pjoin(dipy_home, 'isbi2013'), - 'https://dl.dropboxusercontent.com/u/2481924/isbi2013_merlet/', - ['2shells-1500-2500-N64-SNR-30.nii.gz', - '2shells-1500-2500-N64.bval', - '2shells-1500-2500-N64.bvec'], - ['phantom64.nii.gz', 'phantom64.bval', 'phantom64.bvec'], - ['42911a70f232321cf246315192d69c42', - '90e8cf66e0f4d9737a3b3c0da24df5ea', - '4b7aa2757a1ccab140667b76e8075cb1'], - doc="Download a 2-shell software phantom dataset", - data_size="") - -fetch_stanford_labels = _make_fetcher("fetch_stanford_labels", - pjoin(dipy_home, 'stanford_hardi'), - 'https://stacks.stanford.edu/file/druid:yx282xq2090/', - ["aparc-reduced.nii.gz", "label-info.txt"], - ["aparc-reduced.nii.gz", "label-info.txt"], - ['742de90090d06e687ce486f680f6d71a', - '39db9f0f5e173d7a2c2e51b07d5d711b'], - doc=\ - "Download reduced freesurfer aparc image from stanford web site") - - -fetch_sherbrooke_3shell = _make_fetcher("fetch_sherbrooke_3shell", - pjoin(dipy_home, 'sherbrooke_3shell'), - 'https://dl.dropboxusercontent.com/u/2481924/sherbrooke_data/', - ['3shells-1000-2000-3500-N193.nii.gz', - '3shells-1000-2000-3500-N193.bval', - '3shells-1000-2000-3500-N193.bvec'], - ['HARDI193.nii.gz', 'HARDI193.bval', 'HARDI193.bvec'], - ['0b735e8f16695a37bfbd66aab136eb66', - 'e9b9bb56252503ea49d31fb30a0ac637', - '0c83f7e8b917cd677ad58a078658ebb7'], - doc=\ - "Download a 3shell HARDI dataset with 192 gradient direction") - -fetch_stanford_hardi = _make_fetcher("fetch_stanford_hardi", - pjoin(dipy_home, 'stanford_hardi'), - 'https://stacks.stanford.edu/file/druid:yx282xq2090/', - ['dwi.nii.gz', 'dwi.bvals', 'dwi.bvecs'], - ['HARDI150.nii.gz', 'HARDI150.bval', 'HARDI150.bvec'], - ['0b18513b46132b4d1051ed3364f2acbc', - '4e08ee9e2b1d2ec3fddb68c70ae23c36', - '4c63a586f29afc6a48a5809524a76cb4'], - doc=\ - "Download a HARDI dataset with 160 gradient directions") - -fetch_stanford_t1 = _make_fetcher("fetch_stanford_t1", - pjoin(dipy_home, 'stanford_hardi'), - 'https://stacks.stanford.edu/file/druid:yx282xq2090/', - ['t1.nii.gz'], - ['t1.nii.gz'], - ['a6a140da6a947d4131b2368752951b0a']) - -fetch_stanford_pve_maps = _make_fetcher("fetch_stanford_pve_maps", - pjoin(dipy_home, 'stanford_hardi'), - 'https://stacks.stanford.edu/file/druid:yx282xq2090/', - ['pve_csf.nii.gz', 'pve_gm.nii.gz','pve_wm.nii.gz'], - ['pve_csf.nii.gz', 'pve_gm.nii.gz','pve_wm.nii.gz'], - ['2c498e4fed32bca7f726e28aa86e9c18', - '1654b20aeb35fc2734a0d7928b713874', - '2e244983cf92aaf9f9d37bc7716b37d5']) - -fetch_taiwan_ntu_dsi = _make_fetcher("fetch_taiwan_ntu_dsi", - pjoin(dipy_home, 'taiwan_ntu_dsi'), - "http://dl.dropbox.com/u/2481924/", - ['taiwan_ntu_dsi.nii.gz','tawian_ntu_dsi.bval', - 'taiwan_ntu_dsi.bvec', 'license_taiwan_ntu_dsi.txt'], - ['DSI203.nii.gz', 'DSI203.bval', 'DSI203.bvec', - 'DSI203_license.txt'], - ['950408c0980a7154cb188666a885a91f', - '602e5cb5fad2e7163e8025011d8a6755', - 'a95eb1be44748c20214dc7aa654f9e6b', - '7fa1d5e272533e832cc7453eeba23f44'], - doc=\ - "Download a DSI dataset with 203 gradient directions", - msg= "See DSI203_license.txt for LICENSE. For the complete datasets please visit : http://dsi-studio.labsolver.org", - data_size="91MB") - -fetch_syn_data = _make_fetcher("fetch_syn_data", - pjoin(dipy_home, 'syn_test'), - 'https://dl.dropboxusercontent.com/u/5918983/', - ['t1.nii.gz', 'b0.nii.gz'], - ['t1.nii.gz', 'b0.nii.gz'], - ['701bda02bb769655c7d4a9b1df2b73a6', - 'e4b741f0c77b6039e67abb2885c97a78'], - data_size = "12MB", - doc=\ - "Download t1 and b0 volumes from the same session") - -fetch_mni_template = _make_fetcher("fetch_mni_template", - pjoin(dipy_home, 'mni_template'), -'https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/33312/', - ['COPYING', - 'mni_icbm152_t2_tal_nlin_asym_09a.nii', - 'mni_icbm152_t1_tal_nlin_asym_09a.nii'], - ['COPYING', - 'mni_icbm152_t2_tal_nlin_asym_09a.nii', - 'mni_icbm152_t1_tal_nlin_asym_09a.nii'], - ['6e2168072e80aa4c0c20f1e6e52ec0c8', - 'f41f2e1516d880547fbf7d6a83884f0d', - '1ea8f4f1e41bc17a94602e48141fdbc8'], - doc = \ - "Fetch the MNI T2 and T1 template files (~35 MB)", - data_size="35MB") - -fetch_scil_b0 = _make_fetcher("fetch_scil_b0", - dipy_home, - 'http://scil.dinf.usherbrooke.ca/wp-content/data/', - ['datasets_multi-site_all_companies.zip'], - ['datasets_multi-site_all_companies.zip'], - None, - data_size="9.2MB", - doc=\ - "Download b=0 datasets from multiple MR systems (GE, Philips, Siemens) and different magnetic fields (1.5T and 3T)", - unzip=True) +fetch_isbi2013_2shell = _make_fetcher( + "fetch_isbi2013_2shell", + pjoin(dipy_home, 'isbi2013'), + 'https://dl.dropboxusercontent.com/u/2481924/isbi2013_merlet/', + ['2shells-1500-2500-N64-SNR-30.nii.gz', + '2shells-1500-2500-N64.bval', + '2shells-1500-2500-N64.bvec'], + ['phantom64.nii.gz', 'phantom64.bval', 'phantom64.bvec'], + ['42911a70f232321cf246315192d69c42', + '90e8cf66e0f4d9737a3b3c0da24df5ea', + '4b7aa2757a1ccab140667b76e8075cb1'], + doc="Download a 2-shell software phantom dataset", + data_size="") + +fetch_stanford_labels = _make_fetcher( + "fetch_stanford_labels", + pjoin(dipy_home, 'stanford_hardi'), + 'https://stacks.stanford.edu/file/druid:yx282xq2090/', + ["aparc-reduced.nii.gz", "label-info.txt"], + ["aparc-reduced.nii.gz", "label-info.txt"], + ['742de90090d06e687ce486f680f6d71a', + '39db9f0f5e173d7a2c2e51b07d5d711b'], + doc="Download reduced freesurfer aparc image from stanford web site") + +fetch_sherbrooke_3shell = _make_fetcher( + "fetch_sherbrooke_3shell", + pjoin(dipy_home, 'sherbrooke_3shell'), + 'https://dl.dropboxusercontent.com/u/2481924/sherbrooke_data/', + ['3shells-1000-2000-3500-N193.nii.gz', + '3shells-1000-2000-3500-N193.bval', + '3shells-1000-2000-3500-N193.bvec'], + ['HARDI193.nii.gz', 'HARDI193.bval', 'HARDI193.bvec'], + ['0b735e8f16695a37bfbd66aab136eb66', + 'e9b9bb56252503ea49d31fb30a0ac637', + '0c83f7e8b917cd677ad58a078658ebb7'], + doc="Download a 3shell HARDI dataset with 192 gradient direction") + + +fetch_stanford_hardi = _make_fetcher( + "fetch_stanford_hardi", + pjoin(dipy_home, 'stanford_hardi'), + 'https://stacks.stanford.edu/file/druid:yx282xq2090/', + ['dwi.nii.gz', 'dwi.bvals', 'dwi.bvecs'], + ['HARDI150.nii.gz', 'HARDI150.bval', 'HARDI150.bvec'], + ['0b18513b46132b4d1051ed3364f2acbc', + '4e08ee9e2b1d2ec3fddb68c70ae23c36', + '4c63a586f29afc6a48a5809524a76cb4'], + doc="Download a HARDI dataset with 160 gradient directions") + +fetch_stanford_t1 = _make_fetcher( + "fetch_stanford_t1", + pjoin(dipy_home, 'stanford_hardi'), + 'https://stacks.stanford.edu/file/druid:yx282xq2090/', + ['t1.nii.gz'], + ['t1.nii.gz'], + ['a6a140da6a947d4131b2368752951b0a']) + +fetch_stanford_pve_maps = _make_fetcher( + "fetch_stanford_pve_maps", + pjoin(dipy_home, 'stanford_hardi'), + 'https://stacks.stanford.edu/file/druid:yx282xq2090/', + ['pve_csf.nii.gz', 'pve_gm.nii.gz', 'pve_wm.nii.gz'], + ['pve_csf.nii.gz', 'pve_gm.nii.gz', 'pve_wm.nii.gz'], + ['2c498e4fed32bca7f726e28aa86e9c18', + '1654b20aeb35fc2734a0d7928b713874', + '2e244983cf92aaf9f9d37bc7716b37d5']) + +fetch_taiwan_ntu_dsi = _make_fetcher( + "fetch_taiwan_ntu_dsi", + pjoin(dipy_home, 'taiwan_ntu_dsi'), + "http://dl.dropbox.com/u/2481924/", + ['taiwan_ntu_dsi.nii.gz', 'tawian_ntu_dsi.bval', + 'taiwan_ntu_dsi.bvec', 'license_taiwan_ntu_dsi.txt'], + ['DSI203.nii.gz', 'DSI203.bval', 'DSI203.bvec', 'DSI203_license.txt'], + ['950408c0980a7154cb188666a885a91f', + '602e5cb5fad2e7163e8025011d8a6755', + 'a95eb1be44748c20214dc7aa654f9e6b', + '7fa1d5e272533e832cc7453eeba23f44'], + doc="Download a DSI dataset with 203 gradient directions", + msg="See DSI203_license.txt for LICENSE. For the complete datasets please visit : http://dsi-studio.labsolver.org", + data_size="91MB") + +fetch_syn_data = _make_fetcher( + "fetch_syn_data", + pjoin(dipy_home, 'syn_test'), + 'https://dl.dropboxusercontent.com/u/5918983/', + ['t1.nii.gz', 'b0.nii.gz'], + ['t1.nii.gz', 'b0.nii.gz'], + ['701bda02bb769655c7d4a9b1df2b73a6', + 'e4b741f0c77b6039e67abb2885c97a78'], + data_size="12MB", + doc="Download t1 and b0 volumes from the same session") + +fetch_mni_template = _make_fetcher( + "fetch_mni_template", + pjoin(dipy_home, 'mni_template'), + 'https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/33312/', + ['COPYING', + 'mni_icbm152_t2_tal_nlin_asym_09a.nii', + 'mni_icbm152_t1_tal_nlin_asym_09a.nii'], + ['COPYING', + 'mni_icbm152_t2_tal_nlin_asym_09a.nii', + 'mni_icbm152_t1_tal_nlin_asym_09a.nii'], + ['6e2168072e80aa4c0c20f1e6e52ec0c8', + 'f41f2e1516d880547fbf7d6a83884f0d', + '1ea8f4f1e41bc17a94602e48141fdbc8'], + doc = "Fetch the MNI T2 and T1 template files", + data_size="35MB") + +fetch_scil_b0 = _make_fetcher( + "fetch_scil_b0", + dipy_home, + 'http://scil.dinf.usherbrooke.ca/wp-content/data/', + ['datasets_multi-site_all_companies.zip'], + ['datasets_multi-site_all_companies.zip'], + None, + data_size="9.2MB", + doc="Download b=0 datasets from multiple MR systems (GE, Philips, Siemens) and different magnetic fields (1.5T and 3T)", + unzip=True) + +fetch_viz_icons = _make_fetcher("fetch_viz_icons", + pjoin(dipy_home, "icons"), + 'https://dl.dropboxusercontent.com/u/2481924/', + ['icomoon.tar.gz'], + ['icomoon.tar.gz'], + ['94a07cba06b4136b6687396426f1e380'], + data_size="12KB", + doc="Download icons for dipy.viz", + unzip=True) + +fetch_bundles_2_subjects = _make_fetcher( + "fetch_bundles_2_subjects", + pjoin(dipy_home, 'exp_bundles_and_maps'), + 'https://dl.dropboxusercontent.com/u/2481924/', + ['bundles_2_subjects.tar.gz'], + ['bundles_2_subjects.tar.gz'], + ['97756fbef11ce2df31f1bedf1fc7aac7'], + data_size="234MB", + doc="Download 2 subjects from the SNAIL dataset with their bundles", + unzip=True) def read_scil_b0(): @@ -667,37 +704,6 @@ def read_cenir_multib(bvals=None): fetch_cenir_multib.__doc__ += CENIR_notes read_cenir_multib.__doc__ += CENIR_notes -def fetch_viz_icons(): - """ Download icons for visualization - """ - url = 'https://dl.dropboxusercontent.com/u/2481924/' - fname = 'icomoon.tar.gz' - icomoon = url + fname - folder = pjoin(dipy_home, 'icons') - - url_list = [icomoon] - md5_list = ['94a07cba06b4136b6687396426f1e380'] - fname_list = [fname] - - if not os.path.exists(folder): - print('Creating new directory %s' % folder) - os.makedirs(folder) - print('Downloading icons ...') - for i in range(len(md5_list)): - _get_file_data(pjoin(folder, fname_list[i]), url_list[i]) - new_path = pjoin(folder, fname_list[i]) - check_md5(new_path, md5_list[i]) - ar = tarfile.open(new_path) - ar.extractall(path=folder) - ar.close() - - print('Done.') - print('Files copied in folder %s' % folder) - else: - msg = 'Dataset is already in place. If you want to fetch it again, ' - msg += 'please first remove the folder %s ' - print(msg % folder) - def read_viz_icons(style='icomoon', fname='infinity.png'): """ Read specific icon from specific style @@ -721,38 +727,6 @@ def read_viz_icons(style='icomoon', fname='infinity.png'): return pjoin(folder, fname) -def fetch_bundles_2_subjects(): - """ Download 2 subjects with their bundles - """ - url = 'https://dl.dropboxusercontent.com/u/2481924/' - fname = 'bundles_2_subjects.tar.gz' - url = url + fname - folder = pjoin(dipy_home, 'exp_bundles_and_maps') - - url_list = [url] - md5_list = ['97756fbef11ce2df31f1bedf1fc7aac7'] - fname_list = [fname] - - if not os.path.exists(folder): - print('Creating new directory %s' % folder) - os.makedirs(folder) - print('Downloading dataset ...') - for i in range(len(md5_list)): - _get_file_data(pjoin(folder, fname_list[i]), url_list[i]) - new_path = pjoin(folder, fname_list[i]) - check_md5(new_path, md5_list[i]) - ar = tarfile.open(new_path) - ar.extractall(path=folder) - ar.close() - - print('Done.') - print('Files copied in folder %s' % folder) - else: - msg = 'Dataset is already in place. If you want to fetch it again, ' - msg += 'please first remove the folder %s ' - print(msg % folder) - - def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], bundles=['af.left', 'cst.right', 'cc_1']): From a6b911b332103e2f23faf3b80f073a1d12fc25bf Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 9 Oct 2015 14:48:23 -0400 Subject: [PATCH 187/242] DOC: added documentation for read_bundles_2_subjects --- dipy/data/fetcher.py | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 72dc4d4536..b399c3006f 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -710,15 +710,15 @@ def read_viz_icons(style='icomoon', fname='infinity.png'): Parameters ---------- - style: str + style : str Current icon style. Default is icomoon. - fname: str + fname : str Filename of icon. This should be found in folder HOME/.dipy/style/. Default is infinity.png. Returns -------- - path: str + path : str Complete path of icon. """ @@ -729,6 +729,39 @@ def read_viz_icons(style='icomoon', fname='infinity.png'): def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], bundles=['af.left', 'cst.right', 'cc_1']): + r""" Read images and streamlines from 2 subjects of the SNAIL dataset + + Parameters + ---------- + subj_id : string + Either ``subj_1`` or ``subj_2``. + metrics : list + Either ['fa'] or ['t1'] or ['fa', 't1'] + bundles : list + Example ['af.left', 'cst.right', 'cc_1']. See all the available bundles + in the ``exp_bundles_maps/bundles_2_subjects`` directory of your + ``$HOME/.dipy`` folder. + + Returns + ------- + dix : dict + Dictionary with data of the metrics and the bundles as keys. + + Notes + ----- + If you are using these datasets please cite the following publications. + + References + ---------- + .. [1] Renaud, E. M. Descoteaux, M. Bernier, E. Garyfallidis, + K. Whittingstall, “Morphology of thalamus, LGN and optic radiation do not + influence EEG alpha waves”, Brain function and structure (submitted), 2015. + + .. [2] Garyfallidis, E., O. Ocegueda, D. Wassermann, + M. Descoteaux. Robust and efficient linear registration of fascicles in the + space of streamlines , Neuroimage, 117:124-140, 2015. + + """ dname = pjoin(dipy_home, 'exp_bundles_and_maps', 'bundles_2_subjects') From 2dd6f7dfba71d6e10f11e9761a5f40c00863a406 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 9 Oct 2015 16:25:49 -0400 Subject: [PATCH 188/242] DOC: more info in value_range of slicer --- dipy/data/fetcher.py | 2 +- dipy/viz/actor.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index b399c3006f..6d9f64831d 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -755,7 +755,7 @@ def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], ---------- .. [1] Renaud, E. M. Descoteaux, M. Bernier, E. Garyfallidis, K. Whittingstall, “Morphology of thalamus, LGN and optic radiation do not - influence EEG alpha waves”, Brain function and structure (submitted), 2015. + influence EEG alpha waves”, Under Submission, 2015. .. [2] Garyfallidis, E., O. Ocegueda, D. Wassermann, M. Descoteaux. Robust and efficient linear registration of fascicles in the diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 31a0b89359..47c397fdc2 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -22,18 +22,20 @@ def slicer(data, affine=None, value_range=None, opacity=1., - lookup_colormap=None): - """ Cuts 3D scalar or rgb volumes into images + lookup_colormap=None): + """ Cuts 3D scalar or rgb volumes into 2D images Parameters ---------- data : array, shape (X, Y, Z) or (X, Y, Z, 3) A grayscale or rgb 4D volume as a numpy array. - affine : array, shape (3, 3) - Grid to space (usually RAS 1mm) transformation matrix + affine : array, shape (4, 4) + Grid to space (usually RAS 1mm) transformation matrix. Default is None. + If None then the identity matrix is used. value_range : None or tuple (2,) - If None then the values will be interpolated to (0, 255) from - (min, max). Otherwise from (value_range[0], value_range[1]). + If None then the values will be interpolated from (data.min(), + data.max()) to (0, 255). Otherwise from (value_range[0], + value_range[1]) to (0, 255). opacity : float Opacity of 0 means completely transparent and 1 completely visible. lookup_colormap : vtkLookupTable From aa92ede636dc3a8e9fb7126a807e2f9d256dbc3a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 9 Oct 2015 16:55:46 -0400 Subject: [PATCH 189/242] RF: removed set/get_position from slicer --- dipy/viz/actor.py | 6 ------ doc/examples/viz_slice.py | 6 +++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 47c397fdc2..7303bedba0 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -167,12 +167,6 @@ def copy(self): im_actor.opacity(opacity) return im_actor - def set_position(self, wx, wy, wz): - self.SetPosition(wx, wy, wz) - - def get_position(self): - return self.GetPosition() - image_actor = ImageActor() if nb_components == 1: plane_colors = vtk.vtkImageMapToColors() diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index c4a2a79451..3af0ba49eb 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -177,9 +177,9 @@ for i in range(cols): slice_mosaic = slice_actor.copy() slice_mosaic.display(None, None, cnt) - slice_mosaic.set_position((X + border) * i, - 0.5 * cols * (Y + border) - (Y + border) * j, - 0) + slice_mosaic.SetPosition((X + border) * i, + 0.5 * cols * (Y + border) - (Y + border) * j, + 0) renderer.add(slice_mosaic) cnt += 1 if cnt > Z: From 098186aadc51b57927502082e06c4b9c9a042c5d Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 9 Oct 2015 17:13:04 -0400 Subject: [PATCH 190/242] DOC: updated docstrings of streamtube and line according to Ariel's suggestions --- dipy/viz/actor.py | 56 +++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 7303bedba0..009c54a7f1 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -210,28 +210,33 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, colormap are interpolated automatically using trilinear interpolation. opacity : float + Default is 1. linewidth : float + Default is 0.01. tube_sides : int + Default is 9. lod : bool - use vtkLODActor rather than vtkActor + Use vtkLODActor(level of detail) rather than vtkActor. Default is True. lod_points : int - number of points to be used when LOD is in effect + Number of points to be used when LOD is in effect. Default is 10000. lod_points_size : int - size of points when lod is in effect + Size of points when lod is in effect. Default is 3. spline_subdiv : int - number of splines subdivision to smooth streamtubes - lookup_colormap : bool - add a default lookup table to the colormap + Number of splines subdivision to smooth streamtubes. Default is None. + lookup_colormap : vtkLookupTable + Add a default lookup table to the colormap. Default is None which calls + :func:`dipy.viz.actor.colormap_lookup_table`. Examples -------- - >>> from dipy.viz import fvtk - >>> r=fvtk.ren() - >>> lines=[np.random.rand(10, 3), np.random.rand(20, 3)] - >>> colors=np.random.rand(2, 3) - >>> c=fvtk.streamtube(lines, colors) - >>> fvtk.add(r,c) - >>> #fvtk.show(r) + >>> import numpy as np + >>> from dipy.viz import actor, window + >>> ren = window.Renderer() + >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + >>> colors = np.random.rand(2, 3) + >>> c = actor.streamtube(lines, colors) + >>> ren.add(c) + >>> #window.show(ren) Notes ----- @@ -250,7 +255,7 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, See Also -------- - dipy.viz.actor.line + :func:`dipy.viz.actor.line` """ # Poly data with lines and colors poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) @@ -347,13 +352,16 @@ def line(lines, colors=None, opacity=1, linewidth=1, colormap are interpolated automatically using trilinear interpolation. opacity : float, optional + Default is 1. linewidth : float, optional - Line thickness. + Line thickness. Default is 1. spline_subdiv : int, optional - number of splines subdivision to smooth streamtubes + Number of splines subdivision to smooth streamtubes. Default is None + which means no subdivision. lookup_colormap : bool, optional - add a default lookup table to the colormap + Add a default lookup table to the colormap. Default is None which calls + :func:`dipy.viz.actor.colormap_lookup_table`. Returns ---------- @@ -362,13 +370,13 @@ def line(lines, colors=None, opacity=1, linewidth=1, Examples ---------- - >>> from dipy.viz import fvtk - >>> r=fvtk.ren() - >>> lines=[np.random.rand(10,3), np.random.rand(20,3)] - >>> colors=np.random.rand(2,3) - >>> c=fvtk.line(lines, colors) - >>> fvtk.add(r,c) - >>> #fvtk.show(r) + >>> from dipy.viz import actor, window + >>> ren = window.Renderer() + >>> lines = [np.random.rand(10,3), np.random.rand(20,3)] + >>> colors = np.random.rand(2,3) + >>> c = actor.line(lines, colors) + >>> actor.add(ren, c) + >>> #window.show(ren) """ # Poly data with lines and colors poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) From 7a48e2871a39967da3baf2d0057916a625fceccd Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 9 Oct 2015 18:05:54 -0400 Subject: [PATCH 191/242] DOC+RF: according to github reviews --- dipy/viz/actor.py | 109 +++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 009c54a7f1..760ac89599 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -21,6 +21,39 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() +def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), + saturation_range=(1, 1), value_range=(0.8, 0.8)): + """ Lookup table for the colormap + + Parameters + ---------- + scale_range : tuple + It can be anything e.g. (0, 1) or (0, 255). Usually it is the mininum + and maximum value of your data. Default is (0, 1). + hue_range : tuple of floats + HSV values (min 0 and max 1). Default is (0.8, 0). + saturation_range : tuple of floats + HSV values (min 0 and max 1). Default is (1, 1). + value_range : tuple of floats + HSV value (min 0 and max 1). Default is (0.8, 0.8). + + Returns + ------- + lookup_table : vtkLookupTable + + """ + lookup_table = vtk.vtkLookupTable() + lookup_table.SetRange(scale_range) + lookup_table.SetTableRange(scale_range) + + lookup_table.SetHueRange(hue_range) + lookup_table.SetSaturationRange(saturation_range) + lookup_table.SetValueRange(value_range) + + lookup_table.Build() + return lookup_table + + def slicer(data, affine=None, value_range=None, opacity=1., lookup_colormap=None): """ Cuts 3D scalar or rgb volumes into 2D images @@ -217,6 +250,8 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, Default is 9. lod : bool Use vtkLODActor(level of detail) rather than vtkActor. Default is True. + Level of detail actors do not render the full geometry when the + frame rate is low. lod_points : int Number of points to be used when LOD is in effect. Default is 10000. lod_points_size : int @@ -245,17 +280,17 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, A solution to this problem is to reduce the number of points in each streamline. In Dipy we provide an algorithm that will reduce the number of points on the straighter parts of the streamline but keep more points on - the curvier parts. This can be used in the following way + the curvier parts. This can be used in the following way:: - from dipy.tracking.distances import approx_polygon_track - lines = [approx_polygon_track(line, 0.2) for line in lines] + from dipy.tracking.distances import approx_polygon_track + lines = [approx_polygon_track(line, 0.2) for line in lines] Alternatively we suggest using the ``line`` actor which is much more efficient. See Also -------- - :func:`dipy.viz.actor.line` + :func:``dipy.viz.actor.line`` """ # Poly data with lines and colors poly_data, is_colormap = lines_to_vtk_polydata(lines, colors) @@ -282,6 +317,8 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, tube_filter = set_input(vtk.vtkTubeFilter(), next_input) tube_filter.SetNumberOfSides(tube_sides) tube_filter.SetRadius(linewidth) + # TODO using the line above we will be able to visualize + # streamtubes of varying radius # tube_filter.SetVaryRadiusToVaryRadiusByScalar() tube_filter.CappingOn() tube_filter.Update() @@ -293,7 +330,6 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, poly_mapper.SetScalarModeToUsePointFieldData() poly_mapper.SelectColorArray("Colors") poly_mapper.GlobalImmediateModeRenderingOn() - # poly_mapper.SetColorModeToMapScalars() poly_mapper.Update() # Color Scale with a lookup table @@ -313,11 +349,10 @@ def streamtube(lines, colors=None, opacity=1, linewidth=0.01, tube_sides=9, actor = vtk.vtkActor() actor.SetMapper(poly_mapper) - actor.GetProperty().SetAmbient(0.1) # .3 - actor.GetProperty().SetDiffuse(0.15) # .3 - actor.GetProperty().SetSpecular(0.05) # .3 + actor.GetProperty().SetAmbient(0.1) + actor.GetProperty().SetDiffuse(0.15) + actor.GetProperty().SetSpecular(0.05) actor.GetProperty().SetSpecularPower(6) - # actor.GetProperty().SetInterpolationToGouraud() actor.GetProperty().SetInterpolationToPhong() actor.GetProperty().BackfaceCullingOn() actor.GetProperty().SetOpacity(opacity) @@ -359,21 +394,29 @@ def line(lines, colors=None, opacity=1, linewidth=1, spline_subdiv : int, optional Number of splines subdivision to smooth streamtubes. Default is None which means no subdivision. + lod : bool + Use vtkLODActor(level of detail) rather than vtkActor. Default is True. + Level of detail actors do not render the full geometry when the + frame rate is low. + lod_points : int + Number of points to be used when LOD is in effect. Default is 10000. + lod_points_size : int + Size of points when lod is in effect. Default is 3. lookup_colormap : bool, optional Add a default lookup table to the colormap. Default is None which calls :func:`dipy.viz.actor.colormap_lookup_table`. Returns ---------- - v : vtkActor object + v : vtkActor or vtkLODActor object Line. Examples ---------- >>> from dipy.viz import actor, window >>> ren = window.Renderer() - >>> lines = [np.random.rand(10,3), np.random.rand(20,3)] - >>> colors = np.random.rand(2,3) + >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + >>> colors = np.random.rand(2, 3) >>> c = actor.line(lines, colors) >>> actor.add(ren, c) >>> #window.show(ren) @@ -394,7 +437,6 @@ def line(lines, colors=None, opacity=1, linewidth=1, poly_mapper.ScalarVisibilityOn() poly_mapper.SetScalarModeToUsePointFieldData() poly_mapper.SelectColorArray("Colors") - # poly_mapper.SetColorModeToMapScalars() poly_mapper.Update() # Color Scale with a lookup table @@ -438,10 +480,10 @@ def lines_to_vtk_polydata(lines, colors=None): Then every line is coloured with a different RGB color. If a list of RGB arrays is given then every point of every line takes a different color. - If an array (K, ) is given, where K is the number of points of all + If an array (K,) is given, where K is the number of points of all lines then these are considered as the values to be used by the colormap. - If an array (L, ) is given, where L is the number of streamlines then + If an array (L,) is given, where L is the number of streamlines then these are considered as the values to be used by the colormap per streamline. If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the @@ -449,7 +491,7 @@ def lines_to_vtk_polydata(lines, colors=None): Returns ------- - poly_data : vtkPolyData + poly_data : vtkPolyData is_colormap : bool, true if the input color array was a colormap """ @@ -482,7 +524,7 @@ def lines_to_vtk_polydata(lines, colors=None): # Set Lines to vtk array format vtk_lines = vtk.vtkCellArray() vtk_lines.GetData().DeepCopy(numpy_support.numpy_to_vtk(lines_array)) - vtk_lines.SetNumberOfCells(len(lines)) + vtk_lines.SetNumberOfCells(nb_lines) is_colormap = False # Get colors_array (reformat to have colors for each points) @@ -532,39 +574,6 @@ def lines_to_vtk_polydata(lines, colors=None): return poly_data, is_colormap -def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), - saturation_range=(1, 1), value_range=(0.8, 0.8)): - """ Lookup table for the colormap - - Parameters - ---------- - scale_range : tuple - It can be anything e.g. (0, 1) or (0, 255). Usually it is the mininum - and maximum value of your data. - hue_range : tuple of floats - HSV values (min 0 and max 1) - saturation_range : tuple of floats - HSV values (min 0 and max 1) - value_range : tuple of floats - HSV value (min 0 and max 1) - - Returns - ------- - lookup_table : vtkLookupTable - - """ - lookup_table = vtk.vtkLookupTable() - lookup_table.SetRange(scale_range) - lookup_table.SetTableRange(scale_range) - - lookup_table.SetHueRange(hue_range) - lookup_table.SetSaturationRange(saturation_range) - lookup_table.SetValueRange(value_range) - - lookup_table.Build() - return lookup_table - - def scalar_bar(lookup_table=None, title=" "): """ Default scalar bar actor for a given colormap From 88e0a2701256b0deb0ed4b6bf6577a69861da491 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 10 Oct 2015 13:31:30 -0400 Subject: [PATCH 192/242] Adding more corrections --- dipy/viz/actor.py | 17 ++++++++++------- dipy/viz/tests/test_fvtk_actors.py | 19 +++++++------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 760ac89599..d325a9c421 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -587,11 +587,15 @@ def scalar_bar(lookup_table=None, title=" "): ------- scalar_bar : vtkScalarBarActor + See Also + -------- + :func:`dipy.viz.actor.colormap_lookup_table` + """ lookup_table_copy = vtk.vtkLookupTable() - # Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it if lookup_table is None: lookup_table = colormap_lookup_table() + # Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it lookup_table_copy.DeepCopy(lookup_table) scalar_bar = vtk.vtkScalarBarActor() scalar_bar.SetTitle(title) @@ -632,18 +636,17 @@ def axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), Parameters ---------- scale : tuple (3,) - axes size e.g. (100, 100, 100) + Axes size e.g. (100, 100, 100). Default is (1, 1, 1). colorx : tuple (3,) - x-axis color. Default red. + x-axis color. Default red (1, 0, 0). colory : tuple (3,) - y-axis color. Default blue. + y-axis color. Default green (0, 1, 0). colorz : tuple (3,) - z-axis color. Default green. + z-axis color. Default blue (0, 0, 1). Returns ------- vtkAssembly - """ arrowx = _arrow(color=colorx, scale=scale, opacity=opacity) @@ -658,4 +661,4 @@ def axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), ass.AddPart(arrowy) ass.AddPart(arrowz) - return ass \ No newline at end of file + return ass diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 05d90c90a3..3635d48a11 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -8,10 +8,10 @@ from dipy.tracking.streamline import center_streamlines, transform_streamlines from dipy.align.tests.test_streamlinear import fornix_streamlines +run_test = actor.have_vtk and actor.have_vtk_colors and window.have_imread -@npt.dec.skipif(not actor.have_vtk) -@npt.dec.skipif(not actor.have_vtk_colors) -@npt.dec.skipif(not window.have_imread) + +@npt.dec.skipif(not run_test) def test_slicer(): renderer = window.renderer() @@ -82,9 +82,7 @@ def test_slicer(): npt.assert_equal(report.objects, 1) -@npt.dec.skipif(not actor.have_vtk) -@npt.dec.skipif(not actor.have_vtk_colors) -@npt.dec.skipif(not window.have_imread) +@npt.dec.skipif(not run_test) def test_streamtube_and_line_actors(): renderer = window.renderer() @@ -100,7 +98,6 @@ def test_streamtube_and_line_actors(): c = actor.line(lines, colors, spline_subdiv=5, linewidth=3) window.add(renderer, c) - # create streamtubes of the same lines and shift them a bit c2 = actor.streamtube(lines, colors, linewidth=.1) c2.SetPosition(2, 0, 0) @@ -130,9 +127,7 @@ def test_streamtube_and_line_actors(): npt.assert_equal(report.colors_found, [True, True]) -@npt.dec.skipif(not actor.have_vtk) -@npt.dec.skipif(not actor.have_vtk_colors) -@npt.dec.skipif(not window.have_imread) +@npt.dec.skipif(not run_test) def test_bundle_maps(): renderer = window.renderer() @@ -197,12 +192,12 @@ def test_bundle_maps(): report2 = window.analyze_snapshot(arr) npt.assert_equal(report2.objects, 1) - #try other input options for colors + # try other input options for colors renderer.clear() actor.line(bundle, (1., 0.5, 0)) actor.line(bundle, np.arange(len(bundle))) actor.line(bundle) - colors=[np.random.rand(*b.shape) for b in bundle] + colors = [np.random.rand(*b.shape) for b in bundle] actor.line(bundle, colors=colors) From f590a7d4214ec2074481ffe5f4dede374d18ae03 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 10 Oct 2015 13:44:46 -0400 Subject: [PATCH 193/242] DOC: added commas after e.g. in viz_advanced --- doc/examples/viz_advanced.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 4fc6725097..cbde5f7f04 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -16,20 +16,20 @@ """ In ``window`` we have all the objects that connect what needs to be rendered -to the display or the disk e.g. for saving screenshots. So, there you will find +to the display or the disk e.g., for saving screenshots. So, there you will find key objects and functions like the ``Renderer`` class which holds and provides access to all the actors and the ``show`` function which displays what is in the renderer on a window. Also, this module provides access to functions for opening/saving dialogs and printing screenshots (see ``snapshot``). -In the ``actor`` module we can find all the different primitives e.g. -streamtubes, lines, image slices etc. +In the ``actor`` module we can find all the different primitives e.g., +streamtubes, lines, image slices, etc. In the ``widget`` we have some other objects which allow to add buttons and sliders and these interact both with windows and actors. Because of this they need input from the operating system so they can process events. -So, let's get started. In this tutorial, we will visualize some bundles +Let's get started. In this tutorial, we will visualize some bundles together with FA or T1. We will be able to change the slices using a ``slider`` widget. @@ -41,8 +41,8 @@ fetch_bundles_2_subjects() """ -The following function outputs a dictionary with the required bundles e.g. af -left and maps, e.g. FA for a specific subject. +The following function outputs a dictionary with the required bundles e.g., af +left and maps, e.g., FA for a specific subject. """ res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], From 839b3533d1870db347c5357e7c33f369d21b79a1 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 10 Oct 2015 18:34:11 -0400 Subject: [PATCH 194/242] DOC: updates in viz advanced --- dipy/data/fetcher.py | 7 ++++--- doc/examples/viz_advanced.py | 12 ++++-------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dipy/data/fetcher.py b/dipy/data/fetcher.py index 6d9f64831d..2f14463eaa 100644 --- a/dipy/data/fetcher.py +++ b/dipy/data/fetcher.py @@ -753,9 +753,10 @@ def read_bundles_2_subjects(subj_id='subj_1', metrics=['fa'], References ---------- - .. [1] Renaud, E. M. Descoteaux, M. Bernier, E. Garyfallidis, - K. Whittingstall, “Morphology of thalamus, LGN and optic radiation do not - influence EEG alpha waves”, Under Submission, 2015. + + .. [1] Renaud, E., M. Descoteaux, M. Bernier, E. Garyfallidis, + K. Whittingstall, "Morphology of thalamus, LGN and optic radiation do not + influence EEG alpha waves", Plos One (under submission), 2015. .. [2] Garyfallidis, E., O. Ocegueda, D. Wassermann, M. Descoteaux. Robust and efficient linear registration of fascicles in the diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index cbde5f7f04..269c70a575 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -42,7 +42,7 @@ """ The following function outputs a dictionary with the required bundles e.g., af -left and maps, e.g., FA for a specific subject. +left (left arcuate fasciculus) and maps, e.g., FA for a specific subject. """ res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], @@ -90,7 +90,7 @@ image_actor = actor.slicer(data, affine) """ -For fun let's change also the opacity of the slicer +We can also change also the opacity of the slicer """ slicer_opacity = .6 @@ -137,14 +137,10 @@ def change_slice(obj, event): selected_color=(0.86, 0.33, 1.)) """ -Then, we can render all the widget and everything else in the screen and +Then, we can render all the widgets and everything else in the screen and start the interaction using ``show_m.start()``. -""" -# show_m.render() -# show_m.start() -""" However, if you change the window size, the slider will not update its position properly. The solution to this issue is to update the position of the slider using its ``place`` method every time the window size changes. @@ -164,7 +160,7 @@ def win_callback(obj, event): show_m.initialize() """ -Finally, please uncomment the following lines so that you can interact with +Finally, please uncomment the following 3 lines so that you can interact with the available 3D and 2D objects. """ From 5fbcdf71d2c30a9604868fc888a45d3449a07e88 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 10 Oct 2015 18:39:48 -0400 Subject: [PATCH 195/242] DOC: corrected english --- doc/examples/viz_bundles.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 6d43046919..be54c3bc30 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -36,8 +36,8 @@ """ It happened that this bundle is in world coordinates and therefore we need to -transform in native image coordinates so that it is in the same coordinate -space as the ``fa``. +transform it into native image coordinates so that it is in the same coordinate +space as the ``fa`` image. """ bundle_native = transform_streamlines(bundle, np.linalg.inv(affine)) From cf8aef0692e62134b2264e46637e1cb136611b85 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 10 Oct 2015 18:57:32 -0400 Subject: [PATCH 196/242] DOC: uncomment to show --- doc/examples/viz_bundles.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index be54c3bc30..54b278abce 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -59,6 +59,7 @@ renderer.add(stream_actor) +# Uncomment the line below to show to display the window # window.show(renderer, size=(600, 600), reset_camera=False) window.record(renderer, out_path='bundle1.png', size=(600, 600)) From 4606991a9db45fd4fd56a714a22e333a9e611749 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 10 Oct 2015 19:14:14 -0400 Subject: [PATCH 197/242] RF: viz_hud is now viz_widgets --- doc/examples/{viz_hud.py => viz_widgets.py} | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) rename doc/examples/{viz_hud.py => viz_widgets.py} (92%) diff --git a/doc/examples/viz_hud.py b/doc/examples/viz_widgets.py similarity index 92% rename from doc/examples/viz_hud.py rename to doc/examples/viz_widgets.py index a32d912a7b..540e8d957b 100644 --- a/doc/examples/viz_hud.py +++ b/doc/examples/viz_widgets.py @@ -15,7 +15,7 @@ from dipy.data import fetch_viz_icons, read_viz_icons """ -First, we add the streamtubes to the +First, we add a couple of streamtubes to the Renderer """ renderer = window.Renderer() @@ -62,7 +62,9 @@ def button_minus_callback(obj, event): """ -We need to download some icons to create a face for our buttons ... +We need to download some icons to create a face for our buttons. We provide +some simple icons in this tutorial. But you of course you can use any PNG icon +you may want. """ fetch_viz_icons() @@ -81,7 +83,6 @@ def button_minus_callback(obj, event): def move_lines(obj, event): - stream_actor.SetPosition((obj.get_value(), 0, 0)) """ @@ -125,7 +126,7 @@ def win_callback(obj, event): renderer.roll(10.) """ -Uncomment the following line to start the interaction. +Uncomment the following lines to start the interaction. """ # show_manager.add_window_callback(win_callback) From 6645cee36530780f731ec9bc6ff3ba12b1b796f3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 11 Oct 2015 18:25:50 -0400 Subject: [PATCH 198/242] More minor corrections --- doc/examples/viz_bundles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/viz_bundles.py b/doc/examples/viz_bundles.py index 54b278abce..99dc64ef83 100644 --- a/doc/examples/viz_bundles.py +++ b/doc/examples/viz_bundles.py @@ -29,7 +29,7 @@ affine = dix['affine'] """ -Store the cingulum bundle. A bundle is a set of streamlines. +Store the cingulum bundle. A bundle is a list of streamlines. """ bundle = dix['cg.left'] From 1167f5a8adaabefaf8399abd9005c9636a552ee8 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 11 Oct 2015 18:53:44 -0400 Subject: [PATCH 199/242] RF: colormap_lookup_table moved to colormap.py --- dipy/viz/actor.py | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index d325a9c421..04f48a15b1 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -2,10 +2,9 @@ import numpy as np -from dipy.viz.colormap import line_colors +from dipy.viz.colormap import line_colors, colormap_lookup_table from dipy.viz.utils import numpy_to_vtk_points, numpy_to_vtk_colors from dipy.viz.utils import set_input, map_coordinates_3d_4d -from dipy.core.ndindex import ndindex # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -21,39 +20,6 @@ major_version = vtk.vtkVersion.GetVTKMajorVersion() -def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), - saturation_range=(1, 1), value_range=(0.8, 0.8)): - """ Lookup table for the colormap - - Parameters - ---------- - scale_range : tuple - It can be anything e.g. (0, 1) or (0, 255). Usually it is the mininum - and maximum value of your data. Default is (0, 1). - hue_range : tuple of floats - HSV values (min 0 and max 1). Default is (0.8, 0). - saturation_range : tuple of floats - HSV values (min 0 and max 1). Default is (1, 1). - value_range : tuple of floats - HSV value (min 0 and max 1). Default is (0.8, 0.8). - - Returns - ------- - lookup_table : vtkLookupTable - - """ - lookup_table = vtk.vtkLookupTable() - lookup_table.SetRange(scale_range) - lookup_table.SetTableRange(scale_range) - - lookup_table.SetHueRange(hue_range) - lookup_table.SetSaturationRange(saturation_range) - lookup_table.SetValueRange(value_range) - - lookup_table.Build() - return lookup_table - - def slicer(data, affine=None, value_range=None, opacity=1., lookup_colormap=None): """ Cuts 3D scalar or rgb volumes into 2D images From ccb73b15fce2de894679f320480f2feb3e971554 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 11 Oct 2015 18:53:58 -0400 Subject: [PATCH 200/242] Pep8 --- dipy/viz/colormap.py | 354 ++++++++++++++++++++----------------------- 1 file changed, 168 insertions(+), 186 deletions(-) diff --git a/dipy/viz/colormap.py b/dipy/viz/colormap.py index 57dd4bb281..fcb85378c7 100644 --- a/dipy/viz/colormap.py +++ b/dipy/viz/colormap.py @@ -1,252 +1,235 @@ import numpy as np +# Conditional import machinery for vtk +from dipy.utils.optpkg import optional_package -def cc(na,nd): - return ( na * np.cos( nd * np.pi/180.0 ) ); +# Allow import, but disable doctests if we don't have vtk +vtk, have_vtk, setup_module = optional_package('vtk') -def ss(na,nd): - return na * np.sin( nd * np.pi/180.0 ) ; -def boys2rgb(v): - - """ boys 2 rgb cool colormap - - Maps a given field of undirected lines (line field) to rgb - colors using Boy's Surface immersion of the real projective - plane. - Boy's Surface is one of the three possible surfaces - obtained by gluing a Mobius strip to the edge of a disk. - The other two are the crosscap and Roman surface, - Steiner surfaces that are homeomorphic to the real - projective plane (Pinkall 1986). The Boy's surface - is the only 3D immersion of the projective plane without - singularities. - Visit http://www.cs.brown.edu/~cad/rp2coloring for further details. - Cagatay Demiralp, 9/7/2008. - - Code was initially in matlab and was rewritten in Python for dipy by - the Dipy Team. Thank you Cagatay for putting this online. +def colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), + saturation_range=(1, 1), value_range=(0.8, 0.8)): + """ Lookup table for the colormap Parameters - ------------ - - v : array, shape (N, 3) of unit vectors (e.g., principal eigenvectors of - tensor data) representing one of the two directions of the - undirected lines in a line field. - - Returns - --------- - - c : array, shape (N, 3) matrix of rgb colors corresponding to the vectors - given in V. - - Examples ---------- + scale_range : tuple + It can be anything e.g. (0, 1) or (0, 255). Usually it is the mininum + and maximum value of your data. Default is (0, 1). + hue_range : tuple of floats + HSV values (min 0 and max 1). Default is (0.8, 0). + saturation_range : tuple of floats + HSV values (min 0 and max 1). Default is (1, 1). + value_range : tuple of floats + HSV value (min 0 and max 1). Default is (0.8, 0.8). - >>> from dipy.viz import colormap - >>> v=np.array([[1,0,0],[0,1,0],[0,0,1]]) - >>> c=colormap.boys2rgb(v) + Returns + ------- + lookup_table : vtkLookupTable """ - - if v.ndim==1: - - x=v[0] - y=v[1] - z=v[2] - - - if v.ndim==2: - - x=v[:,0] - y=v[:,1] - z=v[:,2] - + lookup_table = vtk.vtkLookupTable() + lookup_table.SetRange(scale_range) + lookup_table.SetTableRange(scale_range) + lookup_table.SetHueRange(hue_range) + lookup_table.SetSaturationRange(saturation_range) + lookup_table.SetValueRange(value_range) - #return x,y,z + lookup_table.Build() + return lookup_table - x2 = x**2 - y2 = y**2 - z2 = z**2 - x3 = x*x2 - y3 = y*y2 - z3 = z*z2 +def cc(na, nd): + return (na * np.cos(nd * np.pi / 180.0)) - z4 = z*z2 - xy = x*y - xz = x*z - yz = y*z - +def ss(na, nd): + return na * np.sin(nd * np.pi / 180.0) - hh1 = .5 * (3 * z2 - 1)/1.58 - hh2 = 3 * xz/2.745 - - hh3 = 3 * yz/2.745 - - hh4 = 1.5 * (x2 - y2)/2.745 - - hh5 = 6 * xy/5.5 +def boys2rgb(v): + """ boys 2 rgb cool colormap - hh6 = (1/1.176) * .125 * (35 * z4 - 30 * z2 + 3) + Maps a given field of undirected lines (line field) to rgb + colors using Boy's Surface immersion of the real projective + plane. + Boy's Surface is one of the three possible surfaces + obtained by gluing a Mobius strip to the edge of a disk. + The other two are the crosscap and Roman surface, + Steiner surfaces that are homeomorphic to the real + projective plane (Pinkall 1986). The Boy's surface + is the only 3D immersion of the projective plane without + singularities. + Visit http://www.cs.brown.edu/~cad/rp2coloring for further details. + Cagatay Demiralp, 9/7/2008. - hh7 = 2.5 * x * (7 * z3 - 3*z)/3.737 + Code was initially in matlab and was rewritten in Python for dipy by + the Dipy Team. Thank you Cagatay for putting this online. - hh8 = 2.5 * y * (7 * z3 - 3*z)/3.737 + Parameters + ------------ + v : array, shape (N, 3) of unit vectors (e.g., principal eigenvectors of + tensor data) representing one of the two directions of the + undirected lines in a line field. - hh9 = ((x2 - y2) * 7.5 * (7 * z2 - 1))/15.85 + Returns + --------- + c : array, shape (N, 3) matrix of rgb colors corresponding to the vectors + given in V. - hh10 = ((2 * xy) * (7.5 * (7 * z2 - 1)))/15.85 + Examples + ---------- - hh11 = 105 * ( 4 * x3 * z - 3 * xz * (1 - z2))/59.32 + >>> from dipy.viz import colormap + >>> v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + >>> c = colormap.boys2rgb(v) + """ - hh12 = 105 * (-4 * y3 * z + 3 * yz * (1 - z2))/59.32 - + if v.ndim == 1: + x = v[0] + y = v[1] + z = v[2] + + if v.ndim == 2: + x = v[:, 0] + y = v[:, 1] + z = v[:, 2] + + x2 = x ** 2 + y2 = y ** 2 + z2 = z ** 2 + + x3 = x * x2 + y3 = y * y2 + z3 = z * z2 + + z4 = z * z2 + + xy = x * y + xz = x * z + yz = y * z + + hh1 = .5 * (3 * z2 - 1) / 1.58 + hh2 = 3 * xz / 2.745 + hh3 = 3 * yz / 2.745 + hh4 = 1.5 * (x2 - y2) / 2.745 + hh5 = 6 * xy / 5.5 + hh6 = (1 / 1.176) * .125 * (35 * z4 - 30 * z2 + 3) + hh7 = 2.5 * x * (7 * z3 - 3 * z) / 3.737 + hh8 = 2.5 * y * (7 * z3 - 3 * z)/3.737 + hh9 = ((x2 - y2) * 7.5 * (7 * z2 - 1)) / 15.85 + hh10 = ((2 * xy) * (7.5 * (7 * z2 - 1))) / 15.85 + hh11 = 105 * (4 * x3 * z - 3 * xz * (1 - z2)) / 59.32 + hh12 = 105 * (-4 * y3 * z + 3 * yz * (1 - z2)) / 59.32 s0 = -23.0 - s1 = 227.9 - s2 = 251.0 - s3 = 125.0 - ss23 = ss(2.71,s0); cc23 = cc(2.71, s0) - - ss45 = ss(2.12, s1); cc45 = cc(2.12, s1); - - ss67 = ss(.972, s2); cc67 = cc(.972, s2); - - ss89 = ss(.868, s3); cc89 = cc(.868, s3); + ss23 = ss(2.71, s0) + cc23 = cc(2.71, s0) + ss45 = ss(2.12, s1) + cc45 = cc(2.12, s1) + ss67 = ss(.972, s2) + cc67 = cc(.972, s2) + ss89 = ss(.868, s3) + cc89 = cc(.868, s3) X = 0.0 - X =X+ hh2 * cc23 - - X =X+ hh3 * ss23 - - - X =X+ hh5 * cc45 - - X =X+ hh4 * ss45 - - - X =X+ hh7 * cc67 + X = X + hh2 * cc23 + X = X + hh3 * ss23 - X =X+ hh8 * ss67 + X = X + hh5 * cc45 + X = X + hh4 * ss45 + X = X + hh7 * cc67 + X = X + hh8 * ss67 - X =X+ hh10 * cc89 - - X =X+ hh9 * ss89 - + X = X + hh10 * cc89 + X = X + hh9 * ss89 Y = 0.0 - Y =Y+ hh2 * -ss23 - - Y =Y+ hh3 * cc23 - - - Y =Y+ hh5 * -ss45 - - Y =Y+ hh4 * cc45 - - - Y =Y+ hh7 * -ss67 - - Y =Y+ hh8 * cc67 + Y = Y + hh2 * -ss23 + Y = Y + hh3 * cc23 + Y = Y + hh5 * -ss45 + Y = Y + hh4 * cc45 - Y =Y+ hh10 * -ss89 + Y = Y + hh7 * -ss67 + Y = Y + hh8 * cc67 - Y =Y+ hh9 * cc89 + Y = Y + hh10 * -ss89 + Y = Y + hh9 * cc89 Z = 0.0 - Z =Z+ hh1 * -2.8 - - Z =Z+ hh6 * -0.5 - - Z =Z+ hh11 * 0.3 - - Z =Z+ hh12 * -2.5 - + Z = Z + hh1 * -2.8 + Z = Z + hh6 * -0.5 + Z = Z + hh11 * 0.3 + Z = Z + hh12 * -2.5 # scale and normalize to fit # in the rgb space w_x = 4.1925 - - trl_x = -2.0425 - - w_y = 4.0217 + trl_x = -2.0425 + w_y = 4.0217 + trl_y = -1.8541 + w_z = 4.0694 + trl_z = -2.1899 - trl_y = -1.8541 + if v.ndim == 2: - w_z = 4.0694 + N = len(x) + C = np.zeros((N, 3)) - trl_z = -2.1899 + C[:, 0] = 0.9 * np.abs(((X - trl_x) / w_x)) + 0.05 + C[:, 1] = 0.9 * np.abs(((Y - trl_y) / w_y)) + 0.05 + C[:, 2] = 0.9 * np.abs(((Z - trl_z) / w_z)) + 0.05 - - - if v.ndim==2: - - N = len(x) + if v.ndim == 1: - C = np.zeros((N, 3)) - - C[:,0] = 0.9 * np.abs(((X-trl_x)/w_x)) + 0.05 - - C[:,1] = 0.9 * np.abs(((Y-trl_y)/w_y)) + 0.05 - - C[:,2] = 0.9 * np.abs(((Z-trl_z)/w_z)) + 0.05 - - if v.ndim==1: - - C = np.zeros((3,)) - - C[0] = 0.9 * np.abs(((X-trl_x)/w_x)) + 0.05 - - C[1] = 0.9 * np.abs(((Y-trl_y)/w_y)) + 0.05 - - C[2] = 0.9 * np.abs(((Z-trl_z)/w_z)) + 0.05 - + C = np.zeros((3,)) + C[0] = 0.9 * np.abs(((X - trl_x) / w_x)) + 0.05 + C[1] = 0.9 * np.abs(((Y - trl_y) / w_y)) + 0.05 + C[2] = 0.9 * np.abs(((Z - trl_z) / w_z)) + 0.05 return C + def orient2rgb(v): """ standard orientation 2 rgb colormap - - v : array, shape (N, 3) of vectors not necessarily normalized - + + v : array, shape (N, 3) of vectors not necessarily normalized + Returns - --------- - - c : array, shape (N, 3) matrix of rgb colors corresponding to the vectors + ------- + + c : array, shape (N, 3) matrix of rgb colors corresponding to the vectors given in V. Examples - ---------- + -------- >>> from dipy.viz import colormap - >>> v=np.array([[1,0,0],[0,1,0],[0,0,1]]) - >>> c=colormap.orient2rgb(v) - - """ - - if v.ndim==1: - orient=v - orient=np.abs(orient/np.linalg.norm(orient)) - - if v.ndim==2: - orientn=np.sqrt(v[:,0]**2+v[:,1]**2+v[:,2]**2) - orientn.shape=orientn.shape+(1,) - orient=np.abs(v/orientn) - + >>> v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + >>> c = colormap.orient2rgb(v) + + """ + + if v.ndim == 1: + orient = v + orient = np.abs(orient / np.linalg.norm(orient)) + + if v.ndim == 2: + orientn = np.sqrt(v[:, 0] ** 2 + v[:, 1] ** 2 + v[:, 2] ** 2) + orientn.shape = orientn.shape+(1,) + orient = np.abs(v / orientn) + return orient @@ -263,13 +246,12 @@ def line_colors(streamlines, cmap='rgb_standard'): colors : ndarray """ - if cmap=='rgb_standard': - col_list = [orient2rgb(streamline[-1] - streamline[0]) \ + if cmap == 'rgb_standard': + col_list = [orient2rgb(streamline[-1] - streamline[0]) for streamline in streamlines] - if cmap=='boys_standard': - col_list = [boys2rgb(streamline[-1] - streamline[0]) \ + if cmap == 'boys_standard': + col_list = [boys2rgb(streamline[-1] - streamline[0]) for streamline in streamlines] return np.vstack(col_list) - From f247df0b854485a5a74dc69650a85bf24dab8bf3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 11 Oct 2015 19:04:09 -0400 Subject: [PATCH 201/242] RF: moved lines_to_vtk_polydata to utils.py --- dipy/viz/actor.py | 117 ++-------------------------------------------- dipy/viz/utils.py | 109 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 113 deletions(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 04f48a15b1..67612d4e8b 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -2,9 +2,9 @@ import numpy as np -from dipy.viz.colormap import line_colors, colormap_lookup_table -from dipy.viz.utils import numpy_to_vtk_points, numpy_to_vtk_colors -from dipy.viz.utils import set_input, map_coordinates_3d_4d +from dipy.viz.colormap import colormap_lookup_table +from dipy.viz.utils import lines_to_vtk_polydata +from dipy.viz.utils import set_input # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -431,117 +431,8 @@ def line(lines, colors=None, opacity=1, linewidth=1, return actor -def lines_to_vtk_polydata(lines, colors=None): - """ Create a vtkPolyData with lines and colors - - Parameters - ---------- - lines : list - list of N curves represented as 2D ndarrays - colors : array (N, 3), list of arrays, tuple (3,), array (K,), None - If None then a standard orientation colormap is used for every line. - If one tuple of color is used. Then all streamlines will have the same - colour. - If an array (N, 3) is given, where N is equal to the number of lines. - Then every line is coloured with a different RGB color. - If a list of RGB arrays is given then every point of every line takes - a different color. - If an array (K,) is given, where K is the number of points of all - lines then these are considered as the values to be used by the - colormap. - If an array (L,) is given, where L is the number of streamlines then - these are considered as the values to be used by the colormap per - streamline. - If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the - colormap are interpolated automatically using trilinear interpolation. - - Returns - ------- - poly_data : vtkPolyData - is_colormap : bool, true if the input color array was a colormap - """ - - # Get the 3d points_array - points_array = np.vstack(lines) - - nb_lines = len(lines) - nb_points = len(points_array) - - lines_range = range(nb_lines) - - # Get lines_array in vtk input format - lines_array = [] - points_per_line = np.zeros([nb_lines], np.int64) - current_position = 0 - for i in lines_range: - current_len = len(lines[i]) - points_per_line[i] = current_len - - end_position = current_position + current_len - lines_array += [current_len] - lines_array += range(current_position, end_position) - current_position = end_position - - lines_array = np.array(lines_array) - - # Set Points to vtk array format - vtk_points = numpy_to_vtk_points(points_array) - - # Set Lines to vtk array format - vtk_lines = vtk.vtkCellArray() - vtk_lines.GetData().DeepCopy(numpy_support.numpy_to_vtk(lines_array)) - vtk_lines.SetNumberOfCells(nb_lines) - - is_colormap = False - # Get colors_array (reformat to have colors for each points) - # - if/else tested and work in normal simple case - if colors is None: # set automatic rgb colors - cols_arr = line_colors(lines) - colors_mapper = np.repeat(lines_range, points_per_line, axis=0) - vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) - else: - cols_arr = np.asarray(colors) - if cols_arr.dtype == np.object: # colors is a list of colors - vtk_colors = numpy_to_vtk_colors(255 * np.vstack(colors)) - else: - if len(cols_arr) == nb_points: - vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) - is_colormap = True - - elif cols_arr.ndim == 1: - if len(cols_arr) == nb_lines: # values for every streamline - cols_arrx = [] - for (i, value) in enumerate(colors): - cols_arrx += lines[i].shape[0]*[value] - cols_arrx = np.array(cols_arrx) - vtk_colors = numpy_support.numpy_to_vtk(cols_arrx, - deep=True) - is_colormap = True - else: # the same colors for all points - vtk_colors = numpy_to_vtk_colors( - np.tile(255 * cols_arr, (nb_points, 1))) - - elif cols_arr.ndim == 2: # map color to each line - colors_mapper = np.repeat(lines_range, points_per_line, axis=0) - vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) - else: # colormap - # get colors for each vertex - cols_arr = map_coordinates_3d_4d(cols_arr, points_array) - vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) - is_colormap = True - - vtk_colors.SetName("Colors") - - # Create the poly_data - poly_data = vtk.vtkPolyData() - poly_data.SetPoints(vtk_points) - poly_data.SetLines(vtk_lines) - poly_data.GetPointData().SetScalars(vtk_colors) - return poly_data, is_colormap - - def scalar_bar(lookup_table=None, title=" "): - """ Default scalar bar actor for a given colormap + """ Default scalar bar actor for a given colormap (colorbar) Parameters ---------- diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index cecab02fc9..7490e4bb8d 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -3,6 +3,7 @@ import numpy as np from scipy.ndimage import map_coordinates +from dipy.viz.colormap import line_colors # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -94,3 +95,111 @@ def map_coordinates_3d_4d(input_array, indices): indices.T, order=1) values_4d.append(values_tmp) return np.ascontiguousarray(np.array(values_4d).T) + + +def lines_to_vtk_polydata(lines, colors=None): + """ Create a vtkPolyData with lines and colors + + Parameters + ---------- + lines : list + list of N curves represented as 2D ndarrays + colors : array (N, 3), list of arrays, tuple (3,), array (K,), None + If None then a standard orientation colormap is used for every line. + If one tuple of color is used. Then all streamlines will have the same + colour. + If an array (N, 3) is given, where N is equal to the number of lines. + Then every line is coloured with a different RGB color. + If a list of RGB arrays is given then every point of every line takes + a different color. + If an array (K,) is given, where K is the number of points of all + lines then these are considered as the values to be used by the + colormap. + If an array (L,) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. + If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the + colormap are interpolated automatically using trilinear interpolation. + + Returns + ------- + poly_data : vtkPolyData + is_colormap : bool, true if the input color array was a colormap + """ + + # Get the 3d points_array + points_array = np.vstack(lines) + + nb_lines = len(lines) + nb_points = len(points_array) + + lines_range = range(nb_lines) + + # Get lines_array in vtk input format + lines_array = [] + points_per_line = np.zeros([nb_lines], np.int64) + current_position = 0 + for i in lines_range: + current_len = len(lines[i]) + points_per_line[i] = current_len + + end_position = current_position + current_len + lines_array += [current_len] + lines_array += range(current_position, end_position) + current_position = end_position + + lines_array = np.array(lines_array) + + # Set Points to vtk array format + vtk_points = numpy_to_vtk_points(points_array) + + # Set Lines to vtk array format + vtk_lines = vtk.vtkCellArray() + vtk_lines.GetData().DeepCopy(ns.numpy_to_vtk(lines_array)) + vtk_lines.SetNumberOfCells(nb_lines) + + is_colormap = False + # Get colors_array (reformat to have colors for each points) + # - if/else tested and work in normal simple case + if colors is None: # set automatic rgb colors + cols_arr = line_colors(lines) + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) + else: + cols_arr = np.asarray(colors) + if cols_arr.dtype == np.object: # colors is a list of colors + vtk_colors = numpy_to_vtk_colors(255 * np.vstack(colors)) + else: + if len(cols_arr) == nb_points: + vtk_colors = ns.numpy_to_vtk(cols_arr, deep=True) + is_colormap = True + + elif cols_arr.ndim == 1: + if len(cols_arr) == nb_lines: # values for every streamline + cols_arrx = [] + for (i, value) in enumerate(colors): + cols_arrx += lines[i].shape[0]*[value] + cols_arrx = np.array(cols_arrx) + vtk_colors = ns.numpy_to_vtk(cols_arrx, deep=True) + is_colormap = True + else: # the same colors for all points + vtk_colors = numpy_to_vtk_colors( + np.tile(255 * cols_arr, (nb_points, 1))) + + elif cols_arr.ndim == 2: # map color to each line + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) + else: # colormap + # get colors for each vertex + cols_arr = map_coordinates_3d_4d(cols_arr, points_array) + vtk_colors = ns.numpy_to_vtk(cols_arr, deep=True) + is_colormap = True + + vtk_colors.SetName("Colors") + + # Create the poly_data + poly_data = vtk.vtkPolyData() + poly_data.SetPoints(vtk_points) + poly_data.SetLines(vtk_lines) + poly_data.GetPointData().SetScalars(vtk_colors) + return poly_data, is_colormap From 95937936861fcac8745431d6585e0715e5ab1461 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 11 Oct 2015 19:25:48 -0400 Subject: [PATCH 202/242] DOC: corrected doctest --- dipy/viz/actor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/viz/actor.py b/dipy/viz/actor.py index 67612d4e8b..79bba7f26f 100644 --- a/dipy/viz/actor.py +++ b/dipy/viz/actor.py @@ -384,7 +384,7 @@ def line(lines, colors=None, opacity=1, linewidth=1, >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] >>> colors = np.random.rand(2, 3) >>> c = actor.line(lines, colors) - >>> actor.add(ren, c) + >>> ren.add(c) >>> #window.show(ren) """ # Poly data with lines and colors From f4ae554fa78a3cad2ee0f96ab6891f6813f0118b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 11:54:36 -0400 Subject: [PATCH 203/242] Debugging a few issues with transparent order --- dipy/viz/tests/test_fvtk_window.py | 19 +++++++++++++++++-- dipy/viz/window.py | 5 +++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 6c72a8385d..4fb2ab7556 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -183,12 +183,25 @@ def test_order_transparent(): renderer.SetMaximumNumberOfPeels(4) renderer.SetOcclusionRatio(0.0) + + renderer.reset_camera() # green in front renderer.elevation(90) renderer.reset_clipping_range() - arr = window.snapshot(renderer) + renderer.reset_camera() + + #showm = window.ShowManager(renderer, order_transparent=True) + #showm.initialize() + #showm.render() + #showm.iren.Start() + + #show.initialize() + window.show(renderer, reset_camera=False, order_transparent=True) + #from ipdb import set_trace + #set_trace() + arr = window.snapshot(renderer, 'test.png') # therefore the green component must have a higher value (in RGB terms) npt.assert_equal(arr[150, 150][1] > arr[150, 150][0], True) @@ -196,6 +209,7 @@ def test_order_transparent(): # red in front renderer.elevation(-180) renderer.reset_clipping_range() + #window.show(renderer, reset_camera=False, order_transparent=True) arr = window.snapshot(renderer) # therefore the red component must have a higher value (in RGB terms) @@ -204,4 +218,5 @@ def test_order_transparent(): if __name__ == '__main__': - npt.run_module_suite() + # npt.run_module_suite() + test_order_transparent() diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 818363bf8b..996f4f959f 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -678,8 +678,13 @@ def snapshot(ren, fname=None, size=(300, 300)): render_window = vtk.vtkRenderWindow() render_window.SetOffScreenRendering(1) + + render_window.SetAlphaBitPlanes(True) + render_window.SetMultiSamples(True) + render_window.AddRenderer(ren) render_window.SetSize(width, height) + render_window.Render() window_to_image_filter = vtk.vtkWindowToImageFilter() From 8b4c8688f1f43395eff17e5a90d969563778abb2 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 12:02:36 -0400 Subject: [PATCH 204/242] RF: test_order_transparent --- dipy/viz/tests/test_fvtk_window.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 4fb2ab7556..abec6d995a 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -183,25 +183,13 @@ def test_order_transparent(): renderer.SetMaximumNumberOfPeels(4) renderer.SetOcclusionRatio(0.0) - - renderer.reset_camera() # green in front renderer.elevation(90) renderer.reset_clipping_range() - renderer.reset_camera() - #showm = window.ShowManager(renderer, order_transparent=True) - #showm.initialize() - #showm.render() - #showm.iren.Start() - - #show.initialize() - window.show(renderer, reset_camera=False, order_transparent=True) - #from ipdb import set_trace - #set_trace() - arr = window.snapshot(renderer, 'test.png') + arr = window.snapshot(renderer) # therefore the green component must have a higher value (in RGB terms) npt.assert_equal(arr[150, 150][1] > arr[150, 150][0], True) @@ -209,7 +197,7 @@ def test_order_transparent(): # red in front renderer.elevation(-180) renderer.reset_clipping_range() - #window.show(renderer, reset_camera=False, order_transparent=True) + arr = window.snapshot(renderer) # therefore the red component must have a higher value (in RGB terms) @@ -218,5 +206,4 @@ def test_order_transparent(): if __name__ == '__main__': - # npt.run_module_suite() - test_order_transparent() + npt.run_module_suite() From 6f74387c6de480bd9584202892e54d2b78a14b36 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 13:53:42 -0400 Subject: [PATCH 205/242] Removed order related issues from snapshot --- dipy/viz/window.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 996f4f959f..24627c98f9 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -678,10 +678,6 @@ def snapshot(ren, fname=None, size=(300, 300)): render_window = vtk.vtkRenderWindow() render_window.SetOffScreenRendering(1) - - render_window.SetAlphaBitPlanes(True) - render_window.SetMultiSamples(True) - render_window.AddRenderer(ren) render_window.SetSize(width, height) From e84b5666d37f311714893568227dcd9dcd524c03 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 13:53:42 -0400 Subject: [PATCH 206/242] Removed order related calls from snapshot --- dipy/viz/window.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 996f4f959f..24627c98f9 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -678,10 +678,6 @@ def snapshot(ren, fname=None, size=(300, 300)): render_window = vtk.vtkRenderWindow() render_window.SetOffScreenRendering(1) - - render_window.SetAlphaBitPlanes(True) - render_window.SetMultiSamples(True) - render_window.AddRenderer(ren) render_window.SetSize(width, height) From 826e08da8463ca2463c6301ba8fabccf10eea775 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 14:19:57 -0400 Subject: [PATCH 207/242] TEST: checked nosetests with-doctests. All viz tests are passing on NVIDIA GeForce GTX 295 --- dipy/viz/utils.py | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/dipy/viz/utils.py b/dipy/viz/utils.py index 7490e4bb8d..520bfdc1e0 100644 --- a/dipy/viz/utils.py +++ b/dipy/viz/utils.py @@ -15,7 +15,15 @@ def numpy_to_vtk_points(points): - """ numpy points array to a vtk points array + """ Numpy points array to a vtk points array + + Parameters + ---------- + points : ndarray + + Returns + ------- + vtk_points : vtkPoints() """ vtk_points = vtk.vtkPoints() vtk_points.SetData(ns.numpy_to_vtk(np.asarray(points), deep=True)) @@ -23,14 +31,26 @@ def numpy_to_vtk_points(points): def numpy_to_vtk_colors(colors): - """ numpy color array to a vtk color array - - if colors are not already in UNSIGNED_CHAR - you may need to multiply by 255. + """ Numpy color array to a vtk color array - Example + Parameters ---------- - >>> vtk_colors = numpy_to_vtk_colors(255 * float_array) + colors: ndarray + + Returns + ------- + vtk_colors : vtkDataArray + + Notes + ----- + If colors are not already in UNSIGNED_CHAR you may need to multiply by 255. + + Examples + -------- + >>> import numpy as np + >>> from dipy.viz.utils import numpy_to_vtk_colors + >>> rgb_array = np.random.rand(100, 3) + >>> vtk_colors = numpy_to_vtk_colors(255 * rgb_array) """ vtk_colors = ns.numpy_to_vtk(np.asarray(colors), deep=True, array_type=vtk.VTK_UNSIGNED_CHAR) @@ -49,9 +69,11 @@ def set_input(vtk_object, inp): ------- vtk_object - Example - ---------- - >>> poly_mapper = set_input(vtk.vtkPolyDataMapper(), poly_data) + Notes + ------- + This can be used in the following way:: + from dipy.viz.utils import set_input + poly_mapper = set_input(vtk.vtkPolyDataMapper(), poly_data) """ if isinstance(inp, vtk.vtkPolyData) \ or isinstance(inp, vtk.vtkImageData): From beb2e505347f537222463ae3f0d4b5f0887e664f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 17:07:30 -0400 Subject: [PATCH 208/242] Added reset_camera parameter in fvtk.record to get the same behaviour like fvtk.show --- dipy/viz/window.py | 4 +- doc/examples/reconst_dti.py | 3 +- doc/examples/valid_examples.txt | 86 ++++++++++++++++----------------- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 24627c98f9..48eb6ea3e2 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -544,7 +544,7 @@ def show(ren, title='DIPY', size=(300, 300), def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, out_path=None, path_numbering=False, n_frames=1, az_ang=10, - magnification=1, size=(300, 300), verbose=False): + magnification=1, size=(300, 300), reset_camera=True, verbose=False): """ This will record a video of your scene Records a video as a series of ``.png`` files of your scene by rotating the @@ -600,7 +600,7 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, # ren.GetActiveCamera().Azimuth(180) - if ren is None: + if reset_camera: ren.ResetCamera() renderLarge = vtk.vtkRenderLargeImage() diff --git a/doc/examples/reconst_dti.py b/doc/examples/reconst_dti.py index f5c74cd90e..c17f10e1cf 100644 --- a/doc/examples/reconst_dti.py +++ b/doc/examples/reconst_dti.py @@ -223,7 +223,8 @@ """ We can color the ellipsoids using the ``color_fa`` values that we calculated -above. In this example we additionally normalize the values to increase the contrast. +above. In this example we additionally normalize the values to increase the +contrast. """ cfa = RGB[13:43, 44:74, 28:29] diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index c017d8aa88..79acf03966 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -1,44 +1,44 @@ - quick_start.py - tracking_quick_start.py - brain_extraction_dwi.py - reconst_csa_parallel.py - reconst_csa.py - reconst_csd_parallel.py - reconst_csd.py - reconst_dsi_metrics.py - reconst_dsi.py +# quick_start.py +# tracking_quick_start.py +# brain_extraction_dwi.py +# reconst_csa_parallel.py +# reconst_csa.py +# reconst_csd_parallel.py +# reconst_csd.py +# reconst_dsi_metrics.py +# reconst_dsi.py reconst_dti.py - reconst_gqi.py - reconst_dsid.py - kfold_xval.py - reslice_datasets.py - segment_quickbundles.py - segment_extending_clustering_framework.py - snr_in_cc.py - streamline_formats.py - tracking_eudx_odf.py - tracking_eudx_tensor.py - sfm_tracking.py - sfm_reconst.py - gradients_spheres.py - simulate_multi_tensor.py - restore_dti.py - streamline_length.py - reconst_shore.py - reconst_shore_metrics.py - streamline_tools.py - linear_fascicle_evaluation.py - denoise_nlmeans.py - introduction_to_basic_tracking.py - probabilistic_fiber_tracking.py - deterministic_fiber_tracking.py - affine_registration_3d.py - syn_registration_2d.py - syn_registration_3d.py - bundle_registration.py - tracking_tissue_classifier.py - piesno.py - viz_advanced.py - viz_slice.py - viz_bundles.py - viz_hud.py +# reconst_gqi.py +# reconst_dsid.py +# kfold_xval.py +# reslice_datasets.py +# segment_quickbundles.py +# segment_extending_clustering_framework.py +# snr_in_cc.py +# streamline_formats.py +# tracking_eudx_odf.py +# tracking_eudx_tensor.py +# sfm_tracking.py +# sfm_reconst.py +# gradients_spheres.py +# simulate_multi_tensor.py +# restore_dti.py +# streamline_length.py +# reconst_shore.py +# reconst_shore_metrics.py +# streamline_tools.py +# linear_fascicle_evaluation.py +# denoise_nlmeans.py +# introduction_to_basic_tracking.py +# probabilistic_fiber_tracking.py +# deterministic_fiber_tracking.py +# affine_registration_3d.py +# syn_registration_2d.py +# syn_registration_3d.py +# bundle_registration.py +# tracking_tissue_classifier.py +# piesno.py +# viz_advanced.py +# viz_slice.py +# viz_bundles.py +# viz_hud.py From b99b77f7af78202e57676b0d4ceccb2fcdbd848f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 18:11:04 -0400 Subject: [PATCH 209/242] Updated valid examples --- doc/examples/valid_examples.txt | 86 ++++++++++++++++----------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index 79acf03966..c017d8aa88 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -1,44 +1,44 @@ -# quick_start.py -# tracking_quick_start.py -# brain_extraction_dwi.py -# reconst_csa_parallel.py -# reconst_csa.py -# reconst_csd_parallel.py -# reconst_csd.py -# reconst_dsi_metrics.py -# reconst_dsi.py + quick_start.py + tracking_quick_start.py + brain_extraction_dwi.py + reconst_csa_parallel.py + reconst_csa.py + reconst_csd_parallel.py + reconst_csd.py + reconst_dsi_metrics.py + reconst_dsi.py reconst_dti.py -# reconst_gqi.py -# reconst_dsid.py -# kfold_xval.py -# reslice_datasets.py -# segment_quickbundles.py -# segment_extending_clustering_framework.py -# snr_in_cc.py -# streamline_formats.py -# tracking_eudx_odf.py -# tracking_eudx_tensor.py -# sfm_tracking.py -# sfm_reconst.py -# gradients_spheres.py -# simulate_multi_tensor.py -# restore_dti.py -# streamline_length.py -# reconst_shore.py -# reconst_shore_metrics.py -# streamline_tools.py -# linear_fascicle_evaluation.py -# denoise_nlmeans.py -# introduction_to_basic_tracking.py -# probabilistic_fiber_tracking.py -# deterministic_fiber_tracking.py -# affine_registration_3d.py -# syn_registration_2d.py -# syn_registration_3d.py -# bundle_registration.py -# tracking_tissue_classifier.py -# piesno.py -# viz_advanced.py -# viz_slice.py -# viz_bundles.py -# viz_hud.py + reconst_gqi.py + reconst_dsid.py + kfold_xval.py + reslice_datasets.py + segment_quickbundles.py + segment_extending_clustering_framework.py + snr_in_cc.py + streamline_formats.py + tracking_eudx_odf.py + tracking_eudx_tensor.py + sfm_tracking.py + sfm_reconst.py + gradients_spheres.py + simulate_multi_tensor.py + restore_dti.py + streamline_length.py + reconst_shore.py + reconst_shore_metrics.py + streamline_tools.py + linear_fascicle_evaluation.py + denoise_nlmeans.py + introduction_to_basic_tracking.py + probabilistic_fiber_tracking.py + deterministic_fiber_tracking.py + affine_registration_3d.py + syn_registration_2d.py + syn_registration_3d.py + bundle_registration.py + tracking_tissue_classifier.py + piesno.py + viz_advanced.py + viz_slice.py + viz_bundles.py + viz_hud.py From 6c854d4ccf577b5c34c6a27c2e50c0798ede18c4 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Mon, 12 Oct 2015 19:44:35 -0400 Subject: [PATCH 210/242] BF: Missing update call in vtkGlyph3D --- dipy/viz/fvtk.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dipy/viz/fvtk.py b/dipy/viz/fvtk.py index 30ebed9e90..79deab4b5e 100644 --- a/dipy/viz/fvtk.py +++ b/dipy/viz/fvtk.py @@ -168,7 +168,9 @@ def point(points, colors, opacity=1, point_radius=0.1, theta=8, phi=8): pts.InsertNextPoint(p[0], p[1], p[2]) scalars.InsertNextTuple3( - round(255 * colors[cnt_colors][0]), round(255 * colors[cnt_colors][1]), round(255 * colors[cnt_colors][2])) + round(255 * colors[cnt_colors][0]), + round(255 * colors[cnt_colors][1]), + round(255 * colors[cnt_colors][2])) cnt_colors += 1 src = vtk.vtkSphereSource() @@ -188,6 +190,7 @@ def point(points, colors, opacity=1, point_radius=0.1, theta=8, phi=8): glyph.SetInputData(polyData) glyph.SetColorModeToColorByScalar() glyph.SetScaleModeToDataScalingOff() + glyph.Update() mapper = vtk.vtkPolyDataMapper() if major_version <= 5: From e6612ffe86f8377c47f3910a0f1c68a8c67bcbf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Alexandre=20C=C3=B4t=C3=A9?= Date: Tue, 13 Oct 2015 10:30:49 -0400 Subject: [PATCH 211/242] Widgets are placed automatically --- dipy/viz/widget.py | 76 +++++++++++++++++++++---------------- doc/examples/viz_widgets.py | 54 +++++++++++--------------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/dipy/viz/widget.py b/dipy/viz/widget.py index dfdc2973cf..d91724d71d 100644 --- a/dipy/viz/widget.py +++ b/dipy/viz/widget.py @@ -1,6 +1,8 @@ # Widgets are different than actors in that they can interact with events # To do so they need as input a vtkRenderWindowInteractor also known as iren. +import numpy as np + # Conditional import machinery for vtk from dipy.utils.optpkg import optional_package @@ -127,6 +129,13 @@ def get_value(self): slider.AddObserver("InteractionEvent", callback) slider.SetEnabled(True) + # Place widget after window resizing. + def _place_widget(obj, event): + slider.place(ren) + + iren.GetRenderWindow().AddObserver(vtk.vtkCommand.StartEvent, _place_widget) + iren.GetRenderWindow().AddObserver(vtk.vtkCommand.ModifiedEvent, _place_widget) + return slider @@ -204,7 +213,13 @@ def place(self, renderer): button.SetInteractor(iren) button.SetRepresentation(button_rep) button.AddObserver(vtk.vtkCommand.StateChangedEvent, callback) - button.place(ren) + + # Place widget after window resizing. + def _place_widget(obj, event): + button.place(ren) + + iren.GetRenderWindow().AddObserver(vtk.vtkCommand.StartEvent, _place_widget) + iren.GetRenderWindow().AddObserver(vtk.vtkCommand.ModifiedEvent, _place_widget) return button @@ -228,11 +243,13 @@ def text(iren, ren, callback, message="DIPY", message : str Message to be shown in the text widget left_down_pos : tuple - Normalized coordinates for left down corner of text. Default is - (0.8, 0.5). + Coordinates for left down corner of text. If float are provided, + the normalized coordinate system is used, otherwise the coordinates + represent pixel positions. Default is (0.8, 0.5). right_top_pos : tuple - Normalized coordinates for left down corner of text. Default is - (0.9, 0.5). + Coordinates for right top corner of text. If float are provided, + the normalized coordinate system is used, otherwise the coordinates + represent pixel positions. Default is (0.9, 0.5). color : tuple Foreground RGB color of text. Default is (1., .5, .0). opacity : float @@ -256,13 +273,7 @@ def text(iren, ren, callback, message="DIPY", # Create the text representation. Used for positioning the text_actor text_rep = vtk.vtkTextRepresentation() - text_rep.SetPlaceFactor(1) - - text_rep.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() - text_rep.GetPositionCoordinate().SetValue(*left_down_pos) - - text_rep.GetPosition2Coordinate().SetCoordinateSystemToNormalizedDisplay() - text_rep.GetPosition2Coordinate().SetValue(*right_top_pos) + text_rep.SetTextActor(text_actor) if border: text_rep.SetShowBorderToOn() @@ -272,40 +283,41 @@ def text(iren, ren, callback, message="DIPY", class TextWidget(vtk.vtkTextWidget): def place(self, renderer): - text_rep = self.GetRepresentation() position = text_rep.GetPositionCoordinate() - position.SetCoordinateSystemToNormalizedDisplay() - position.SetValue(*left_down_pos) - position2 = text_rep.GetPosition2Coordinate() - position2.SetCoordinateSystemToNormalizedDisplay() - position2.SetValue(*right_top_pos) - self.SelectableOn() - self.ResizableOff() - text_rep.ProportionalResizeOn() + # The dtype of `left_down_pos` determines coordinate system type. + if np.issubdtype(np.asarray(left_down_pos).dtype, np.integer): + position.SetCoordinateSystemToDisplay() + else: + position.SetCoordinateSystemToNormalizedDisplay() - self.On() + # The dtype of `right_top_pos` determines coordinate system type. + if np.issubdtype(np.asarray(right_top_pos).dtype, np.integer): + position2.SetCoordinateSystemToDisplay() + else: + position2.SetCoordinateSystemToNormalizedDisplay() + + position.SetValue(*left_down_pos) + position2.SetValue(*right_top_pos) text_widget = TextWidget() text_widget.SetRepresentation(text_rep) text_widget.SetInteractor(iren) - text_widget.SetTextActor(text_actor) text_widget.SelectableOn() text_widget.ResizableOff() - text_widget.GetRepresentation().ProportionalResizeOn() text_widget.AddObserver(vtk.vtkCommand.WidgetActivateEvent, callback) - text_widget.On() - # This is a hack for avoiding not plotting the text widget when - # backface culling in On on a different actor - ss = vtk.vtkSphereSource() - mapper = vtk.vtkPolyDataMapper() - mapper.SetInputConnection(ss.GetOutputPort()) - actor = vtk.vtkActor() - actor.GetProperty().BackfaceCullingOff() + # Place widget after window resizing. + def _place_widget(obj, event): + text_widget.place(ren) + + iren.GetRenderWindow().AddObserver(vtk.vtkCommand.StartEvent, _place_widget) + iren.GetRenderWindow().AddObserver(vtk.vtkCommand.ModifiedEvent, _place_widget) + + text_widget.On() return text_widget diff --git a/doc/examples/viz_widgets.py b/doc/examples/viz_widgets.py index 540e8d957b..50875a54b7 100644 --- a/doc/examples/viz_widgets.py +++ b/doc/examples/viz_widgets.py @@ -23,8 +23,7 @@ lines = [np.array([[-1, 0, 0.], [1, 0, 0.]]), np.array([[-1, 1, 0.], [1, 1, 0.]])] colors = np.array([[1., 0., 0.], [0., .5, 0.]]) -stream_actor = actor.streamtube(lines, colors, linewidth=0.3) - +stream_actor = actor.streamtube(lines, colors, linewidth=0.3, lod=False) renderer.add(stream_actor) """ @@ -35,30 +34,24 @@ show_manager = window.ShowManager(renderer, size=(800, 800), order_transparent=True) -show_manager.initialize() - """ Next we add the widgets and their callbacks. """ -global opacity -opacity = 1. - def button_plus_callback(obj, event): print('+ pressed') - global opacity + opacity = stream_actor.GetProperty().GetOpacity() if opacity < 1: - opacity += 0.1 - stream_actor.GetProperty().SetOpacity(opacity) + stream_actor.GetProperty().SetOpacity(opacity + 0.1) def button_minus_callback(obj, event): print('- pressed') - global opacity + + opacity = stream_actor.GetProperty().GetOpacity() if opacity > 0: - opacity -= 0.1 - stream_actor.GetProperty().SetOpacity(opacity) + stream_actor.GetProperty().SetOpacity(opacity - 0.1) """ @@ -86,7 +79,7 @@ def move_lines(obj, event): stream_actor.SetPosition((obj.get_value(), 0, 0)) """ -And then we create the slider. +Then we create the slider. """ slider = widget.slider(show_manager.iren, show_manager.ren, @@ -100,27 +93,24 @@ def move_lines(obj, event): color=(0.4, 0.4, 0.4), selected_color=(0.2, 0.2, 0.2)) -global size -size = renderer.size() - """ -This callback is used to update the buttons/sliders' position so they can stay -on the correct side of the window when the window is being resized. +And a simple overlay text. """ -def win_callback(obj, event): - global size - if size != obj.GetSize(): +def text_clicked(obj, event): + print "Awesome!" - button_plus.place(renderer) - button_minus.place(renderer) - slider.place(renderer) - size = obj.GetSize() +text = widget.text(show_manager.iren, show_manager.ren, + message="Powered by DIPY", + callback=text_clicked, + color=(1., .5, .0), + left_down_pos=(10, 5), + right_top_pos=(200, 35)) -# you can also register any callback in a vtk way like this -# show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, -# win_callback) +""" +Position the camera. +""" renderer.zoom(0.7) renderer.roll(10.) @@ -129,9 +119,9 @@ def win_callback(obj, event): Uncomment the following lines to start the interaction. """ -# show_manager.add_window_callback(win_callback) -# show_manager.render() -# show_manager.start() +show_manager.initialize() +show_manager.render() +show_manager.start() renderer.reset_clipping_range() From a13be6b2e2f141dcecd0f59cd95ce5e91cdac279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Alexandre=20C=C3=B4t=C3=A9?= Date: Tue, 13 Oct 2015 10:42:36 -0400 Subject: [PATCH 212/242] Fixed typos --- doc/examples/viz_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/viz_widgets.py b/doc/examples/viz_widgets.py index 50875a54b7..1e794d297a 100644 --- a/doc/examples/viz_widgets.py +++ b/doc/examples/viz_widgets.py @@ -94,7 +94,7 @@ def move_lines(obj, event): selected_color=(0.2, 0.2, 0.2)) """ -And a simple overlay text. +And we add a simple clickable text overlay at the bottom left corner. """ From ac0be600e184a91d7ebbf4b2ed1fc57b0b1dfb19 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 13 Oct 2015 13:32:47 -0400 Subject: [PATCH 213/242] DOC: updated the new viz tutorials with resetting the camera when the camera has previously change --- doc/examples/viz_advanced.py | 3 ++- doc/examples/viz_slice.py | 9 ++++++--- doc/examples/viz_widgets.py | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/examples/viz_advanced.py b/doc/examples/viz_advanced.py index 269c70a575..a180b61583 100644 --- a/doc/examples/viz_advanced.py +++ b/doc/examples/viz_advanced.py @@ -171,7 +171,8 @@ def win_callback(obj, event): ren.zoom(1.5) ren.reset_clipping_range() -window.record(ren, out_path='bundles_and_a_slice.png', size=(1200, 900)) +window.record(ren, out_path='bundles_and_a_slice.png', size=(1200, 900), + reset_camera=False) """ .. figure:: bundles_and_a_slice.png diff --git a/doc/examples/viz_slice.py b/doc/examples/viz_slice.py index 3af0ba49eb..093933b8f4 100644 --- a/doc/examples/viz_slice.py +++ b/doc/examples/viz_slice.py @@ -90,7 +90,8 @@ Otherwise, you can save a screenshot using the following command. """ -window.record(renderer, out_path='slices.png', size=(600, 600)) +window.record(renderer, out_path='slices.png', size=(600, 600), + reset_camera=False) """ .. figure:: slices.png @@ -137,7 +138,8 @@ # window.show(renderer, size=(600, 600), reset_camera=False) -window.record(renderer, out_path='slices_lut.png', size=(600, 600)) +window.record(renderer, out_path='slices_lut.png', size=(600, 600), + reset_camera=False) """ .. figure:: slices_lut.png @@ -198,7 +200,8 @@ in/out using the scroll wheel. """ -window.record(renderer, out_path='mosaic.png', size=(900, 600)) +window.record(renderer, out_path='mosaic.png', size=(900, 600), + reset_camera=False) """ .. figure:: mosaic.png diff --git a/doc/examples/viz_widgets.py b/doc/examples/viz_widgets.py index 540e8d957b..85fb9012cd 100644 --- a/doc/examples/viz_widgets.py +++ b/doc/examples/viz_widgets.py @@ -135,7 +135,8 @@ def win_callback(obj, event): renderer.reset_clipping_range() -window.record(renderer, out_path='mini_ui.png', size=(800, 800)) +window.record(renderer, out_path='mini_ui.png', size=(800, 800), + reset_camera=False) del show_manager From aa9810a87a4d16383cfb86531854a3cf11c2cca2 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 13 Oct 2015 15:38:46 -0400 Subject: [PATCH 214/242] Updated sfm_tracking example with new slicer --- dipy/viz/tests/test_fvtk_widgets.py | 15 ++++++--------- doc/examples/sfm_tracking.py | 13 +++++++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 9cf0b72df1..276dc0d047 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -87,7 +87,7 @@ def win_callback(obj, event): size = obj.GetSize() if interactive: - show_manager.add_window_callback(win_callback) + # show_manager.add_window_callback(win_callback) # you can also register any callback in a vtk way like this # show_manager.window.AddObserver(vtk.vtkCommand.ModifiedEvent, # win_callback) @@ -98,10 +98,13 @@ def win_callback(obj, event): if not interactive: button.Off() slider.Off() + # Uncomment below to test the slider and button with analyze + # button.place(renderer) + # slider.place(renderer) arr = window.snapshot(renderer, size=(800, 800)) report = window.analyze_snapshot(arr) - npt.assert_equal(report.objects, 4) + npt.assert_equal(report.objects, 2) # imshow(report.labels, origin='lower') report = window.analyze_renderer(renderer) @@ -166,13 +169,7 @@ def text_callback(obj, event): if interactive: show_manager.render() - def win_callback(obj, event): - print('Window modified') - button.place(renderer) - text.place(renderer) - if interactive: - show_manager.add_window_callback(win_callback) show_manager.render() show_manager.start() @@ -186,4 +183,4 @@ def win_callback(obj, event): if __name__ == '__main__': - npt.run_module_suite() \ No newline at end of file + npt.run_module_suite() diff --git a/doc/examples/sfm_tracking.py b/doc/examples/sfm_tracking.py index 8b673d46b3..d55122ae3a 100644 --- a/doc/examples/sfm_tracking.py +++ b/doc/examples/sfm_tracking.py @@ -126,15 +126,20 @@ plot_streamlines = select_random_set_of_streamlines(streamlines, 900) streamlines_actor = fvtk.streamtube( - list(move_streamlines(plot_streamlines, inv(t1_aff))), - line_colors(streamlines)) + list(move_streamlines(plot_streamlines, inv(t1_aff))), + line_colors(streamlines), linewidth=0.1) -vol_actor = fvtk.slicer(t1_data, voxsz=(1.0, 1.0, 1.0), plane_i=[40], - plane_j=None, plane_k=[35], outline=False) +vol_actor = fvtk.slicer(t1_data) + +vol_actor.display(40, None, None) +vol_actor2 = vol_actor.copy() +vol_actor2.display(None, None, 35) ren = fvtk.ren() fvtk.add(ren, streamlines_actor) fvtk.add(ren, vol_actor) +fvtk.add(ren, vol_actor2) +fvtk.show(ren) fvtk.record(ren, n_frames=1, out_path='sfm_streamlines.png', size=(800, 800)) From 232aeb2c0e06e642b6f0af65d9bddcf6ae16d5ce Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 13 Oct 2015 15:46:12 -0400 Subject: [PATCH 215/242] RF: updated the rest of examples that are using the slicer --- doc/examples/linear_fascicle_evaluation.py | 10 ++++++++-- doc/examples/sfm_tracking.py | 2 +- doc/examples/streamline_tools.py | 8 ++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/examples/linear_fascicle_evaluation.py b/doc/examples/linear_fascicle_evaluation.py index ed8216a328..3e9736c816 100644 --- a/doc/examples/linear_fascicle_evaluation.py +++ b/doc/examples/linear_fascicle_evaluation.py @@ -63,13 +63,19 @@ line_colors(candidate_sl)) cc_ROI_actor = fvtk.contour(cc_slice, levels=[1], colors=[(1., 1., 0.)], opacities=[1.]) -vol_actor = fvtk.slicer(t1_data, voxsz=(1.0, 1.0, 1.0), plane_i=[40], - plane_j=None, plane_k=[35], outline=False) + +vol_actor = fvtk.slicer(t1_data) + +vol_actor.display(40, None, None) +vol_actor2 = vol_actor.copy() +vol_actor2.display(None, None, 35) + # Add display objects to canvas ren = fvtk.ren() fvtk.add(ren, candidate_streamlines_actor) fvtk.add(ren, cc_ROI_actor) fvtk.add(ren, vol_actor) +fvtk.add(ren, vol_actor2) fvtk.record(ren, n_frames=1, out_path='life_candidates.png', size=(800, 800)) diff --git a/doc/examples/sfm_tracking.py b/doc/examples/sfm_tracking.py index d55122ae3a..15d794e345 100644 --- a/doc/examples/sfm_tracking.py +++ b/doc/examples/sfm_tracking.py @@ -139,7 +139,7 @@ fvtk.add(ren, streamlines_actor) fvtk.add(ren, vol_actor) fvtk.add(ren, vol_actor2) -fvtk.show(ren) + fvtk.record(ren, n_frames=1, out_path='sfm_streamlines.png', size=(800, 800)) diff --git a/doc/examples/streamline_tools.py b/doc/examples/streamline_tools.py index 1bcc620b48..da999d2480 100644 --- a/doc/examples/streamline_tools.py +++ b/doc/examples/streamline_tools.py @@ -102,12 +102,16 @@ cc_ROI_actor = fvtk.contour(cc_slice, levels=[1], colors=[(1., 1., 0.)], opacities=[1.]) -vol_actor = fvtk.slicer(t1_data, voxsz=(1.0, 1.0, 1.0), plane_i=[40], - plane_j=None, plane_k=[35], outline=False) +vol_actor = fvtk.slicer(t1_data) + +vol_actor.display(40, None, None) +vol_actor2 = vol_actor.copy() +vol_actor2.display(None, None, 35) # Add display objects to canvas r = fvtk.ren() fvtk.add(r, vol_actor) +fvtk.add(r, vol_actor2) fvtk.add(r, cc_streamlines_actor) fvtk.add(r, cc_ROI_actor) From 917118b330b909116da11ac3075d189e5316ae27 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 13 Oct 2015 16:46:26 -0400 Subject: [PATCH 216/242] Made simulated bundle contiguous --- doc/examples/streamline_length.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/examples/streamline_length.py b/doc/examples/streamline_length.py index 42aba0d2b3..f8e2a9343d 100644 --- a/doc/examples/streamline_length.py +++ b/doc/examples/streamline_length.py @@ -14,6 +14,7 @@ number of streamlines in the set. """ +import numpy as np from dipy.tracking.utils import length from dipy.tracking.metrics import downsample from dipy.tracking.distances import approx_polygon_track @@ -34,7 +35,9 @@ def simulated_bundles(no_streamlines=50, n_pts=100): start = np.random.randint(10, 30, no_streamlines) end = np.random.randint(60, 100, no_streamlines) - bundle = [10 * streamline[start[i]:end[i]] for (i, streamline) in enumerate(bundle)] + bundle = [10 * streamline[start[i]:end[i]] + for (i, streamline) in enumerate(bundle)] + bundle = [np.ascontiguousarray(streamline) for streamline in bundle] return bundle From 7d44cd6db00148e0fa91d2043950f74ef1f8bef3 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Tue, 13 Oct 2015 18:07:48 -0400 Subject: [PATCH 217/242] DOC: updated examples index and valid examples --- doc/examples/valid_examples.txt | 2 +- doc/examples_index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/valid_examples.txt b/doc/examples/valid_examples.txt index c017d8aa88..870cf1936d 100644 --- a/doc/examples/valid_examples.txt +++ b/doc/examples/valid_examples.txt @@ -41,4 +41,4 @@ viz_advanced.py viz_slice.py viz_bundles.py - viz_hud.py + viz_widgets.py diff --git a/doc/examples_index.rst b/doc/examples_index.rst index 32e506d5be..715e627f6e 100644 --- a/doc/examples_index.rst +++ b/doc/examples_index.rst @@ -198,7 +198,7 @@ Visualization - :ref:`example_viz_advanced` - :ref:`example_viz_slice` - :ref:`example_viz_bundles` -- :ref:`example_viz_hud` +- :ref:`example_viz_widgets` .. In order to build the examples, you'll need (on Debian) sudo apt-get install python-tables python-matplotib python-vtk From 2e5fbc1dd2803be16c48bdbc4473e221afdb6dbe Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 14 Oct 2015 10:12:22 -0400 Subject: [PATCH 218/242] RF: it's now VectorOfEndpointsFeature --- doc/examples/segment_extending_clustering_framework.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/segment_extending_clustering_framework.py b/doc/examples/segment_extending_clustering_framework.py index b7a3f3f538..e1ef799ad4 100644 --- a/doc/examples/segment_extending_clustering_framework.py +++ b/doc/examples/segment_extending_clustering_framework.py @@ -155,7 +155,7 @@ def extract(self, streamline): """ from dipy.segment.metric import Metric -from dipy.segment.metric import VectorBetweenEndpointsFeature +from dipy.segment.metric import VectorOfEndpointsFeature """ We now define the class `CosineMetric` that will perform the desired @@ -170,7 +170,7 @@ class CosineMetric(Metric): """ Computes the cosine distance between two streamlines. """ def __init__(self): # For simplicity, features will be the vector between endpoints of a streamline. - super(CosineMetric, self).__init__(feature=VectorBetweenEndpointsFeature()) + super(CosineMetric, self).__init__(feature=VectorOfEndpointsFeature()) def are_compatible(self, shape1, shape2): """ Checks if two features are vectors of same dimension. From 1f62772d1a532485994e23d6b3a6b90611820e45 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 14 Oct 2015 13:50:36 -0400 Subject: [PATCH 219/242] DOC: Commented updated example --- doc/examples/viz_widgets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/examples/viz_widgets.py b/doc/examples/viz_widgets.py index 3bc1e6baa2..32b2c3f696 100644 --- a/doc/examples/viz_widgets.py +++ b/doc/examples/viz_widgets.py @@ -114,16 +114,16 @@ def text_clicked(obj, event): renderer.zoom(0.7) renderer.roll(10.) +renderer.reset_clipping_range() """ Uncomment the following lines to start the interaction. """ -show_manager.initialize() -show_manager.render() -show_manager.start() +# show_manager.initialize() +# show_manager.render() +# show_manager.start() -renderer.reset_clipping_range() window.record(renderer, out_path='mini_ui.png', size=(800, 800), reset_camera=False) From 275715a8a5588af98a42bd44ade6f88f04e77e7b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 14 Oct 2015 18:19:32 -0400 Subject: [PATCH 220/242] DOC: conflict diff text removed --- doc/api_changes.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/api_changes.rst b/doc/api_changes.rst index 8b558d8cbe..ea84108646 100644 --- a/doc/api_changes.rst +++ b/doc/api_changes.rst @@ -6,7 +6,6 @@ Here we provide information about functions or classes that have been removed, renamed or are deprecated (not recommended) during different release circles. Dipy 0.10 Changes -<<<<<<< HEAD ----------------- ** New visualization module** @@ -14,8 +13,6 @@ Dipy 0.10 Changes ``fvtk.slicer`` input parameters have changed. Now the slicer function is more powerfull and supports RGB images too. See tutorial ``viz_slice.py`` for more information. -======= ----------------- **Interpolation** The default behavior of the function `core.sphere.interp_rbf` has changed. From bdb243c0ce8ac303527482e7b30657056fbd655b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 14 Oct 2015 18:38:12 -0400 Subject: [PATCH 221/242] Relaxed strict viz test --- dipy/viz/tests/test_fvtk_widgets.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 276dc0d047..4608024fab 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -163,11 +163,10 @@ def text_callback(obj, event): opacity=1., border=False) - button.place(renderer) - text.place(renderer) - - if interactive: - show_manager.render() + if not interactive: + button.Off() + text.Off() + pass if interactive: show_manager.render() @@ -175,7 +174,7 @@ def text_callback(obj, event): arr = window.snapshot(renderer, size=(1200, 1200)) report = window.analyze_snapshot(arr) - npt.assert_equal(report.objects, 30) + npt.assert_equal(report.objects, 3) # If you want to see the segmented objects after the analysis is finished # you can use imshow(report.labels, origin='lower') From dadca09bfdb4f7745ca8513e48a33244f5058feb Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 14 Oct 2015 18:59:23 -0400 Subject: [PATCH 222/242] DOC: added default values --- dipy/viz/window.py | 49 ++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 48eb6ea3e2..c0f2263a87 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -311,7 +311,7 @@ def __init__(self, ren, title='DIPY', size=(300, 300), title : string A string for the window title bar. size : (int, int) - ``(width, height)`` of the window + ``(width, height)`` of the window. Default is (300, 300). png_magnify : int Number of times to magnify the screenshot. This can be used to save high resolution screenshots when pressing 's' inside the window. @@ -492,12 +492,13 @@ def show(ren, title='DIPY', size=(300, 300), ren : Renderer() or vtkRenderer() The scene that holds all the actors. title : string - A string for the window title bar. + A string for the window title bar. Default is DIPY and current version. size : (int, int) - ``(width, height)`` of the window + ``(width, height)`` of the window. Default is (300, 300). png_magnify : int - Number of times to magnify the screenshot. This can be used to save - high resolution screenshots when pressing 's' inside the window. + Number of times to magnify the screenshot. Default is 1. This can be + used to save high resolution screenshots when pressing 's' inside the + window. reset_camera : bool Default is True. You can change this option to False if you want to keep the camera as set before calling this function. @@ -555,28 +556,31 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, ren : vtkRenderer() object as returned from function ren() cam_pos : None or sequence (3,), optional - camera position + Camera's position. If None then default camera's position is used. cam_focal : None or sequence (3,), optional - camera focal point + Camera's focal point. If None then default camera's focal point is + used. cam_view : None or sequence (3,), optional - camera view up + Camera's view up direction. If None then default camera's view up + vector is used. out_path : str, optional - output directory for the frames + Output path for the frames. If None a default dipy.png is created. path_numbering : bool - when recording it changes out_path ot out_path + str(frame number) + When recording it changes out_path to out_path + str(frame number) n_frames : int, optional - number of frames to save, default 1 + Number of frames to save, default 1 az_ang : float, optional - azimuthal angle of camera rotation. + Azimuthal angle of camera rotation. magnification : int, optional - how much to magnify the saved frame + How much to magnify the saved frame. Default is 1. size : (int, int) - ``(width, height)`` of the window + ``(width, height)`` of the window. Default is (300, 300). + reset_camera : bool + If True Call ``ren.reset_camera()``. Otherwise you need to set the + camera before calling this function. verbose : bool - print information about the camera - sleep_time : float - Creates a small delay in seconds so that the renderer has enough - time to save the figure correctly. + print information about the camera. Default is False. + Examples --------- @@ -644,7 +648,10 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, else: filename = out_path + str(i).zfill(6) + '.png' else: - filename = out_path + if out_path is None: + filename = 'dipy.png' + else: + filename = out_path writer.SetFileName(filename) writer.Write() @@ -661,11 +668,11 @@ def snapshot(ren, fname=None, size=(300, 300)): fname : str or None Save PNG file. If None return only an array without saving PNG. size : (int, int) - ``(width, height)`` of the window + ``(width, height)`` of the window. Default is (300, 300). Returns ------- - arr : array + arr : ndarray Color array of size (width, height, 3) where the last dimension holds the RGB values. """ From 0395cfe37d71a41a72102a2945ccb74e07ed1815 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Wed, 14 Oct 2015 20:07:31 -0400 Subject: [PATCH 223/242] Removed diff line --- doc/api_changes.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/api_changes.rst b/doc/api_changes.rst index ea84108646..cb04e3463b 100644 --- a/doc/api_changes.rst +++ b/doc/api_changes.rst @@ -29,7 +29,6 @@ The following utilty functions from ``vector_fields`` module were renamed: ``warp_2d_affine_nn`` is now ``transform_2d_affine_nn`` ``warp_3d_affine`` is now ``transform_3d_affine`` ``warp_3d_affine_nn`` is now ``transform_3d_affine_nn`` ->>>>>>> nipy-dipy-master Dipy 0.9 Changes From 2b404caae8d6424933f7888138bcf2bef90a06d7 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 15 Oct 2015 14:32:42 -0400 Subject: [PATCH 224/242] NF: disabling mesa offscreen by default --- dipy/viz/window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index c0f2263a87..3f0c7a017b 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -681,7 +681,7 @@ def snapshot(ren, fname=None, size=(300, 300)): graphics_factory = vtk.vtkGraphicsFactory() graphics_factory.SetOffScreenOnlyMode(1) - graphics_factory.SetUseMesaClasses(1) + # graphics_factory.SetUseMesaClasses(1) render_window = vtk.vtkRenderWindow() render_window.SetOffScreenRendering(1) From 298806ce3ef8ecb1a85f0255250838348148e1ab Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 15 Oct 2015 18:47:31 -0400 Subject: [PATCH 225/242] Minor comment added --- dipy/viz/window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index 3f0c7a017b..bae484bb8d 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -681,6 +681,7 @@ def snapshot(ren, fname=None, size=(300, 300)): graphics_factory = vtk.vtkGraphicsFactory() graphics_factory.SetOffScreenOnlyMode(1) + # TODO check if the line below helps in something # graphics_factory.SetUseMesaClasses(1) render_window = vtk.vtkRenderWindow() From 21c7888b4602875626e6be1a4a328c223d3e701a Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Thu, 15 Oct 2015 20:52:18 -0400 Subject: [PATCH 226/242] Installing missing python-tk in Travis bot --- .travis.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e84f59bcbe..b68f19cef2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ cache: env: global: - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt" + - VENV_ARGS="--python=python" python: - 2.6 - 3.2 @@ -30,9 +31,14 @@ matrix: - python: 2.7 env: - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt scikit_learn" + - python: 2.7 + sudo: true + env: + - VTK=1 + - VENV_ARGS="--system-site-packages --python=/usr/bin/python2.7" before_install: - source tools/travis_tools.sh - - virtualenv --python=python venv + - virtualenv $VENV_ARGS venv - source venv/bin/activate - python --version # just to check - retry pip install nose # always @@ -41,6 +47,13 @@ before_install: pip install coverage; pip install coveralls; fi + - if [ "${VTK}" == "1" ]; then + sudo apt-get update; + sudo apt-get install -y python-vtk; + sudo apt-get install -y python-tk; + sudo apt-get install -y xvfb; + python -c "import vtk"; + fi install: - python setup.py install # command to run tests, e.g. python setup.py test @@ -54,6 +67,9 @@ script: cp ../.coveragerc .; COVER_ARGS="--with-coverage --cover-package dipy"; fi - - nosetests --with-doctest --verbose $COVER_ARGS dipy + - if [ "${VTK}" == "1" ]; then + VIRT_BUFF="xvfb-run"; + fi + - $VIRT_BUFF nosetests --with-doctest --verbose $COVER_ARGS dipy after_success: - if [ "${COVERAGE}" == "1" ]; then coveralls; fi From 57498d03a5dc1da5488e3ae30d1da1fc4974d176 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Fri, 16 Oct 2015 09:58:04 -0400 Subject: [PATCH 227/242] Went to old travis.yml and making another PR for adding tk to travis.yml --- .travis.yml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index b68f19cef2..e84f59bcbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ cache: env: global: - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt" - - VENV_ARGS="--python=python" python: - 2.6 - 3.2 @@ -31,14 +30,9 @@ matrix: - python: 2.7 env: - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt scikit_learn" - - python: 2.7 - sudo: true - env: - - VTK=1 - - VENV_ARGS="--system-site-packages --python=/usr/bin/python2.7" before_install: - source tools/travis_tools.sh - - virtualenv $VENV_ARGS venv + - virtualenv --python=python venv - source venv/bin/activate - python --version # just to check - retry pip install nose # always @@ -47,13 +41,6 @@ before_install: pip install coverage; pip install coveralls; fi - - if [ "${VTK}" == "1" ]; then - sudo apt-get update; - sudo apt-get install -y python-vtk; - sudo apt-get install -y python-tk; - sudo apt-get install -y xvfb; - python -c "import vtk"; - fi install: - python setup.py install # command to run tests, e.g. python setup.py test @@ -67,9 +54,6 @@ script: cp ../.coveragerc .; COVER_ARGS="--with-coverage --cover-package dipy"; fi - - if [ "${VTK}" == "1" ]; then - VIRT_BUFF="xvfb-run"; - fi - - $VIRT_BUFF nosetests --with-doctest --verbose $COVER_ARGS dipy + - nosetests --with-doctest --verbose $COVER_ARGS dipy after_success: - if [ "${COVERAGE}" == "1" ]; then coveralls; fi From fb387795579e6f5ccf8abb4dd11aad8cc1f8189f Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 11:39:55 -0700 Subject: [PATCH 228/242] Run xvfb with screen server-arg --- .travis.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 89127abba1..fe3d87e4fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,28 +31,30 @@ matrix: - python: 2.7 env: - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt scikit_learn" + # To test vtk functionality - python: 2.7 - sudo: true + sudo: true # This is set to true for apt-get env: - VTK=1 + - LIBGL_ALWAYS_INDIRECT=y - VENV_ARGS="--system-site-packages --python=/usr/bin/python2.7" + - IS_TRAVIS=true before_install: - source tools/travis_tools.sh - virtualenv $VENV_ARGS venv - source venv/bin/activate - python --version # just to check - - retry pip install nose # always - - wheelhouse_pip_install $DEPENDS + - retry pip install nose; + - wheelhouse_pip_install $DEPENDS; - if [ "${COVERAGE}" == "1" ]; then pip install coverage; pip install coveralls; fi - if [ "${VTK}" == "1" ]; then - sudo apt-get update; - sudo apt-get install -y python-vtk; - sudo apt-get install -y xvfb; - sudo apt-get install -y python-tk; - python -c "import vtk"; + sudo apt-get update; + sudo apt-get install -y python-vtk; + sudo apt-get install -y xvfb; + sudo apt-get install -y python-tk; fi install: - python setup.py install @@ -68,8 +70,8 @@ script: COVER_ARGS="--with-coverage --cover-package dipy"; fi - if [ "${VTK}" == "1" ]; then - VIRT_BUFF="xvfb-run"; + VIRT_BUFF='xvfb-run --server-args="-screen 0 1024x768x24"'; fi - $VIRT_BUFF nosetests --with-doctest --verbose $COVER_ARGS dipy after_success: - - if [ "${COVERAGE}" == "1" ]; then coveralls; fi + - if [ "${COVERAGE}" == "1" ]; then coveralls; fi \ No newline at end of file From 267d8a1d8d10fa677ee5d90c0d7f60ed2797fd9b Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 12:20:00 -0700 Subject: [PATCH 229/242] Use xvfbwrapper on travis. Don't use xvfb in the call to nosetests. Only test the one we are interested in for now. I guess it needs to be included to actually run? Copy over this decorator to test_fvtk_widgets to get it running under xvfb. Are we there yet? --- .travis.yml | 20 ++------------------ dipy/viz/tests/test_fvtk_actors.py | 20 ++++++++++++++++---- dipy/viz/tests/test_fvtk_widgets.py | 15 ++++++++++++++- dipy/viz/tests/test_fvtk_window.py | 16 ++++++++++++++++ 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe3d87e4fe..6ce6c9b213 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,22 +15,8 @@ env: - VENV_ARGS="--python=python" python: - 2.6 - - 3.2 - - 3.3 - - 3.4 matrix: include: - - python: 2.7 - env: - - COVERAGE=1 - # To test minimum dependencies - - python: 2.7 - env: - - COVERAGE=1 - - DEPENDS="cython==0.18 numpy==1.7.1 scipy==0.9.0 nibabel==1.2.0" - - python: 2.7 - env: - - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt scikit_learn" # To test vtk functionality - python: 2.7 sudo: true # This is set to true for apt-get @@ -55,6 +41,7 @@ before_install: sudo apt-get install -y python-vtk; sudo apt-get install -y xvfb; sudo apt-get install -y python-tk; + retry pip install xvfbwrapper; fi install: - python setup.py install @@ -69,9 +56,6 @@ script: cp ../.coveragerc .; COVER_ARGS="--with-coverage --cover-package dipy"; fi - - if [ "${VTK}" == "1" ]; then - VIRT_BUFF='xvfb-run --server-args="-screen 0 1024x768x24"'; - fi - - $VIRT_BUFF nosetests --with-doctest --verbose $COVER_ARGS dipy + - nosetests --with-doctest --verbose $COVER_ARGS dipy after_success: - if [ "${COVERAGE}" == "1" ]; then coveralls; fi \ No newline at end of file diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 3635d48a11..0d6ddc7fba 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -9,13 +9,25 @@ from dipy.align.tests.test_streamlinear import fornix_streamlines run_test = actor.have_vtk and actor.have_vtk_colors and window.have_imread +is_travis = os.environ.get('IS_TRAVIS', False) + + +def xvfb_it(my_test): + def run_with_xvfb(): + if is_travis: + from xvfbwrapper import Xvfb + display = Xvfb() + display.start() + my_test() + if is_travis: + display.stop() + return run_with_xvfb @npt.dec.skipif(not run_test) +@xvfb_it def test_slicer(): - renderer = window.renderer() - data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) slicer = actor.slicer(data, affine) @@ -82,9 +94,9 @@ def test_slicer(): npt.assert_equal(report.objects, 1) +@xvfb_it @npt.dec.skipif(not run_test) def test_streamtube_and_line_actors(): - renderer = window.renderer() line1 = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2.]]) @@ -128,8 +140,8 @@ def test_streamtube_and_line_actors(): @npt.dec.skipif(not run_test) +@xvfb_it def test_bundle_maps(): - renderer = window.renderer() bundle = fornix_streamlines() bundle, shift = center_streamlines(bundle) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 4608024fab..169d0d34c2 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -3,7 +3,19 @@ from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt - +def xvfb_it(my_test): + def run_with_xvfb(): + if is_travis: + from xvfbwrapper import Xvfb + display = Xvfb() + display.start() + my_test() + if is_travis: + display.stop() + return run_with_xvfb + + +@xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_button_and_slider_widgets(): @@ -111,6 +123,7 @@ def win_callback(obj, event): npt.assert_equal(report.actors, 1) +@xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_text_widget(): diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index abec6d995a..0b1132d51b 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -3,6 +3,19 @@ import numpy.testing as npt +def xvfb_it(my_test): + def run_with_xvfb(): + if is_travis: + from xvfbwrapper import Xvfb + display = Xvfb() + display.start() + my_test() + if is_travis: + display.stop() + return run_with_xvfb + + +@xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_renderer(): @@ -66,6 +79,7 @@ def test_renderer(): npt.assert_equal(report.actors, 0) +@xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_active_camera(): @@ -134,6 +148,7 @@ def test_active_camera(): npt.assert_almost_equal(position[2], 0.5 * new_position[2]) +@xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_parallel_projection(): @@ -166,6 +181,7 @@ def test_parallel_projection(): npt.assert_equal(np.sum(arr2 > 0) > np.sum(arr > 0), True) +@xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) def test_order_transparent(): From 28eefd2222791071ced24a1b50a91472cc84a51a Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 15:50:11 -0700 Subject: [PATCH 230/242] Integrate the xvfb_it decorators into the testing module and use everywhere. --- dipy/testing/decorators.py | 14 ++++++++++++++ dipy/viz/tests/test_fvtk.py | 6 +++++- dipy/viz/tests/test_fvtk_actors.py | 14 +------------- dipy/viz/tests/test_fvtk_utils.py | 2 +- dipy/viz/tests/test_fvtk_widgets.py | 13 +------------ dipy/viz/tests/test_fvtk_window.py | 13 +------------ 6 files changed, 23 insertions(+), 39 deletions(-) diff --git a/dipy/testing/decorators.py b/dipy/testing/decorators.py index b50d47eb78..7175a72b95 100644 --- a/dipy/testing/decorators.py +++ b/dipy/testing/decorators.py @@ -5,6 +5,7 @@ """ import re +import os SKIP_RE = re.compile("(\s*>>>.*?)(\s*)#\s*skip\s+if\s+(.*)$") @@ -44,3 +45,16 @@ def doctest_skip_parser(func): new_lines.append(code) func.__doc__ = "\n".join(new_lines) return func + +# Travis testing with virtual frame-buffer +is_travis = os.environ.get('IS_TRAVIS', False) +def xvfb_it(my_test): + def test_with_xvfb(): + if is_travis: + from xvfbwrapper import Xvfb + display = Xvfb() + display.start() + my_test() + if is_travis: + display.stop() + return test_with_xvfb diff --git a/dipy/viz/tests/test_fvtk.py b/dipy/viz/tests/test_fvtk.py index 0e7cd751e1..5d87b9a566 100644 --- a/dipy/viz/tests/test_fvtk.py +++ b/dipy/viz/tests/test_fvtk.py @@ -6,8 +6,10 @@ from dipy import data import numpy.testing as npt +from dipy.testing.decorators import xvfb_it +@xvfb_it @npt.dec.skipif(not fvtk.have_vtk) @npt.dec.skipif(not fvtk.have_vtk_colors) def test_fvtk_functions(): @@ -62,6 +64,7 @@ def test_fvtk_functions(): fvtk.add(r, p2) +@xvfb_it @npt.dec.skipif(not fvtk.have_vtk) @npt.dec.skipif(not fvtk.have_vtk_colors) def test_fvtk_ellipsoid(): @@ -83,7 +86,8 @@ def test_fvtk_ellipsoid(): fvtk.add(ren, fvtk.tensor(mevals, mevecs, sphere=sphere)) - fvtk.add(ren, fvtk.tensor(mevals, mevecs, np.ones(mevals.shape), sphere=sphere)) + fvtk.add(ren, fvtk.tensor(mevals, mevecs, np.ones(mevals.shape), + sphere=sphere)) npt.assert_equal(ren.GetActors().GetNumberOfItems(), 2) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 0d6ddc7fba..4241ef1e06 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -7,21 +7,9 @@ from nibabel.tmpdirs import TemporaryDirectory from dipy.tracking.streamline import center_streamlines, transform_streamlines from dipy.align.tests.test_streamlinear import fornix_streamlines +from dipy.testing.decorators import xvfb_it run_test = actor.have_vtk and actor.have_vtk_colors and window.have_imread -is_travis = os.environ.get('IS_TRAVIS', False) - - -def xvfb_it(my_test): - def run_with_xvfb(): - if is_travis: - from xvfbwrapper import Xvfb - display = Xvfb() - display.start() - my_test() - if is_travis: - display.stop() - return run_with_xvfb @npt.dec.skipif(not run_test) diff --git a/dipy/viz/tests/test_fvtk_utils.py b/dipy/viz/tests/test_fvtk_utils.py index 91fd76b1ad..11873dace1 100644 --- a/dipy/viz/tests/test_fvtk_utils.py +++ b/dipy/viz/tests/test_fvtk_utils.py @@ -69,4 +69,4 @@ def test_trilinear_interp(): if __name__ == '__main__': - npt.run_module_suite() \ No newline at end of file + npt.run_module_suite() diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 169d0d34c2..3219302782 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -2,18 +2,7 @@ from dipy.viz import actor, window, widget, fvtk from dipy.data import fetch_viz_icons, read_viz_icons import numpy.testing as npt - -def xvfb_it(my_test): - def run_with_xvfb(): - if is_travis: - from xvfbwrapper import Xvfb - display = Xvfb() - display.start() - my_test() - if is_travis: - display.stop() - return run_with_xvfb - +from dipy.testing.decorators import xvfb_it @xvfb_it @npt.dec.skipif(not actor.have_vtk) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 0b1132d51b..2b130e9f39 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -1,18 +1,7 @@ import numpy as np from dipy.viz import actor, window import numpy.testing as npt - - -def xvfb_it(my_test): - def run_with_xvfb(): - if is_travis: - from xvfbwrapper import Xvfb - display = Xvfb() - display.start() - my_test() - if is_travis: - display.stop() - return run_with_xvfb +from dipy.testing.decorators import xvfb_it @xvfb_it From 13c8b7ac24e8e8a8f2c784237447c817ab724668 Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 16:27:15 -0700 Subject: [PATCH 231/242] TST: Insert back the function name when decorated with xvfb_it --- dipy/testing/decorators.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dipy/testing/decorators.py b/dipy/testing/decorators.py index 7175a72b95..0fedd9a551 100644 --- a/dipy/testing/decorators.py +++ b/dipy/testing/decorators.py @@ -49,6 +49,8 @@ def doctest_skip_parser(func): # Travis testing with virtual frame-buffer is_travis = os.environ.get('IS_TRAVIS', False) def xvfb_it(my_test): + # When we use verbose testing we want the name: + fname = my_test.__name__ def test_with_xvfb(): if is_travis: from xvfbwrapper import Xvfb @@ -57,4 +59,6 @@ def test_with_xvfb(): my_test() if is_travis: display.stop() + # Plant it back in and return the new function: + test_with_xvfb.__name__ = fname return test_with_xvfb From 9e0683ee5948cdccacc84d23c6d05b0e3acf4608 Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 16:48:11 -0700 Subject: [PATCH 232/242] TST: Generalize the variable names a bit. Add comment to explain. --- .travis.yml | 2 +- dipy/testing/decorators.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ce6c9b213..b4b72bb76a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ matrix: - VTK=1 - LIBGL_ALWAYS_INDIRECT=y - VENV_ARGS="--system-site-packages --python=/usr/bin/python2.7" - - IS_TRAVIS=true + - TEST_WITH_XVFB=true before_install: - source tools/travis_tools.sh - virtualenv $VENV_ARGS venv diff --git a/dipy/testing/decorators.py b/dipy/testing/decorators.py index 0fedd9a551..cfefcc5e1f 100644 --- a/dipy/testing/decorators.py +++ b/dipy/testing/decorators.py @@ -46,18 +46,22 @@ def doctest_skip_parser(func): func.__doc__ = "\n".join(new_lines) return func -# Travis testing with virtual frame-buffer -is_travis = os.environ.get('IS_TRAVIS', False) +### +# In some cases (e.g., on Travis), we want to use a virtual frame-buffer for +# testing. The following decorator runs the tests under xvfb (mediated by +# xvfbwrapper) conditioned on an environment variable (that we set in +# .travis.yml for these cases): +use_xvfb = os.environ.get('TEST_WITH_XVFB', False) def xvfb_it(my_test): # When we use verbose testing we want the name: fname = my_test.__name__ def test_with_xvfb(): - if is_travis: + if use_xvfb: from xvfbwrapper import Xvfb display = Xvfb() display.start() my_test() - if is_travis: + if use_xvfb: display.stop() # Plant it back in and return the new function: test_with_xvfb.__name__ = fname From 03b12a9b4ca22ce30d874aaeeb41c961f6b57fe3 Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 16:57:28 -0700 Subject: [PATCH 233/242] TST: Add back a few more test machines. --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index b4b72bb76a..bd893cb91a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,22 @@ env: - VENV_ARGS="--python=python" python: - 2.6 + - 3.2 + - 3.3 + - 3.4 matrix: include: + - python: 2.7 + env: + - COVERAGE=1 + # To test minimum dependencies + - python: 2.7 + env: + - COVERAGE=1 + - DEPENDS="cython==0.18 numpy==1.7.1 scipy==0.9.0 nibabel==1.2.0" + - python: 2.7 + env: + - DEPENDS="cython numpy scipy matplotlib h5py nibabel cvxopt scikit_learn" # To test vtk functionality - python: 2.7 sudo: true # This is set to true for apt-get From 4052a0b35f0000b30b0500d049d1d2ee476e8bec Mon Sep 17 00:00:00 2001 From: arokem Date: Fri, 30 Oct 2015 17:36:55 -0700 Subject: [PATCH 234/242] Add another bot to test on vtk6 --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bd893cb91a..ede7dd2042 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,15 @@ matrix: sudo: true # This is set to true for apt-get env: - VTK=1 + - VTK_VER="python-vtk" + - LIBGL_ALWAYS_INDIRECT=y + - VENV_ARGS="--system-site-packages --python=/usr/bin/python2.7" + - TEST_WITH_XVFB=true + - python: 2.7 + sudo: true # This is set to true for apt-get + env: + - VTK=1 + - VTK_VER="python-vtk6" - LIBGL_ALWAYS_INDIRECT=y - VENV_ARGS="--system-site-packages --python=/usr/bin/python2.7" - TEST_WITH_XVFB=true @@ -52,7 +61,7 @@ before_install: fi - if [ "${VTK}" == "1" ]; then sudo apt-get update; - sudo apt-get install -y python-vtk; + sudo apt-get install -y $VTK_VER; sudo apt-get install -y xvfb; sudo apt-get install -y python-tk; retry pip install xvfbwrapper; From 240f91cd640a57ca4cfdefce483fcb074a1a8dc2 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 31 Oct 2015 16:03:13 -0400 Subject: [PATCH 235/242] BF: In some GPUs when you use snapshot with complete stealthmode (no window appears) depth peeling is not supported but if you allow for a quick window to appear then transparent ordering works fine. --- dipy/viz/tests/test_fvtk_widgets.py | 1 + dipy/viz/tests/test_fvtk_window.py | 10 +++----- dipy/viz/window.py | 40 ++++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index 3219302782..c2b06c96c2 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -4,6 +4,7 @@ import numpy.testing as npt from dipy.testing.decorators import xvfb_it + @xvfb_it @npt.dec.skipif(not actor.have_vtk) @npt.dec.skipif(not actor.have_vtk_colors) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 2b130e9f39..6b9610ec73 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -184,26 +184,24 @@ def test_order_transparent(): renderer.add(stream_actor) - renderer.UseDepthPeelingOn() - renderer.SetMaximumNumberOfPeels(4) - renderer.SetOcclusionRatio(0.0) - renderer.reset_camera() # green in front renderer.elevation(90) + renderer.camera().OrthogonalizeViewUp() renderer.reset_clipping_range() - arr = window.snapshot(renderer) + arr = window.snapshot(renderer, offscreen=False, order_transparent=True) # therefore the green component must have a higher value (in RGB terms) npt.assert_equal(arr[150, 150][1] > arr[150, 150][0], True) # red in front renderer.elevation(-180) + renderer.camera().OrthogonalizeViewUp() renderer.reset_clipping_range() - arr = window.snapshot(renderer) + arr = window.snapshot(renderer, offscreen=False, order_transparent=True) # therefore the red component must have a higher value (in RGB terms) npt.assert_equal(arr[150, 150][0] > arr[150, 150][1], True) diff --git a/dipy/viz/window.py b/dipy/viz/window.py index bae484bb8d..c545263f49 100644 --- a/dipy/viz/window.py +++ b/dipy/viz/window.py @@ -658,7 +658,8 @@ def record(ren=None, cam_pos=None, cam_focal=None, cam_view=None, ang = +az_ang -def snapshot(ren, fname=None, size=(300, 300)): +def snapshot(ren, fname=None, size=(300, 300), offscreen=True, + order_transparent=False): """ Saves a snapshot of the renderer in a file or in memory Parameters @@ -669,6 +670,10 @@ def snapshot(ren, fname=None, size=(300, 300)): Save PNG file. If None return only an array without saving PNG. size : (int, int) ``(width, height)`` of the window. Default is (300, 300). + offscreen : bool + Default True. Go stealthmode no window should appear. + order_transparent : bool + Default False. Use depth peeling to sort transparent objects. Returns ------- @@ -679,16 +684,39 @@ def snapshot(ren, fname=None, size=(300, 300)): width, height = size - graphics_factory = vtk.vtkGraphicsFactory() - graphics_factory.SetOffScreenOnlyMode(1) - # TODO check if the line below helps in something - # graphics_factory.SetUseMesaClasses(1) + if offscreen: + graphics_factory = vtk.vtkGraphicsFactory() + graphics_factory.SetOffScreenOnlyMode(1) + # TODO check if the line below helps in something + # graphics_factory.SetUseMesaClasses(1) render_window = vtk.vtkRenderWindow() - render_window.SetOffScreenRendering(1) + if offscreen: + render_window.SetOffScreenRendering(1) render_window.AddRenderer(ren) render_window.SetSize(width, height) + if order_transparent: + + # Use a render window with alpha bits + # as default is 0 (false)) + render_window.SetAlphaBitPlanes(True) + + # Force to not pick a framebuffer with a multisample buffer + # (default is 8) + render_window.SetMultiSamples(0) + + # Choose to use depth peeling (if supported) + # (default is 0 (false)): + ren.UseDepthPeelingOn() + + # Set depth peeling parameters + # Set the maximum number of rendering passes (default is 4) + ren.SetMaximumNumberOfPeels(4) + + # Set the occlusion ratio (initial value is 0.0, exact image): + ren.SetOcclusionRatio(0.0) + render_window.Render() window_to_image_filter = vtk.vtkWindowToImageFilter() From 91a3c6f28cf4c9f38ee21f92216f27d3f1f3cd8c Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 31 Oct 2015 16:52:05 -0400 Subject: [PATCH 236/242] Default xvfb display size is changed to HD 1920x1080 --- dipy/testing/decorators.py | 2 +- dipy/viz/tests/test_fvtk_widgets.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dipy/testing/decorators.py b/dipy/testing/decorators.py index cfefcc5e1f..768b429f84 100644 --- a/dipy/testing/decorators.py +++ b/dipy/testing/decorators.py @@ -58,7 +58,7 @@ def xvfb_it(my_test): def test_with_xvfb(): if use_xvfb: from xvfbwrapper import Xvfb - display = Xvfb() + display = Xvfb(width=1920, height=1080) display.start() my_test() if use_xvfb: diff --git a/dipy/viz/tests/test_fvtk_widgets.py b/dipy/viz/tests/test_fvtk_widgets.py index c2b06c96c2..7919c5b08f 100644 --- a/dipy/viz/tests/test_fvtk_widgets.py +++ b/dipy/viz/tests/test_fvtk_widgets.py @@ -125,7 +125,7 @@ def test_text_widget(): window.add(renderer, axes) renderer.ResetCamera() - show_manager = window.ShowManager(renderer, size=(1200, 1200)) + show_manager = window.ShowManager(renderer, size=(900, 900)) if interactive: show_manager.initialize() @@ -175,7 +175,7 @@ def text_callback(obj, event): show_manager.render() show_manager.start() - arr = window.snapshot(renderer, size=(1200, 1200)) + arr = window.snapshot(renderer, size=(900, 900)) report = window.analyze_snapshot(arr) npt.assert_equal(report.objects, 3) From 5568302d2c3df33a65df6c43010d6794a97c8d61 Mon Sep 17 00:00:00 2001 From: arokem Date: Sat, 31 Oct 2015 15:13:58 -0700 Subject: [PATCH 237/242] TST: Add python-imaging --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ede7dd2042..8c6444fe77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,6 +64,7 @@ before_install: sudo apt-get install -y $VTK_VER; sudo apt-get install -y xvfb; sudo apt-get install -y python-tk; + sudo apt-get install -y python-imaging; retry pip install xvfbwrapper; fi install: From 9bc93a96f0a8e0bcf34c83ab988bb3982d8917a7 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 31 Oct 2015 18:23:10 -0400 Subject: [PATCH 238/242] BF+TEST: In xvfb offscreen rendering with True returns black window but it works fine in standard displays. Added if statement to deal with this issue --- dipy/viz/tests/test_fvtk_window.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_window.py b/dipy/viz/tests/test_fvtk_window.py index 6b9610ec73..7164b5a06b 100644 --- a/dipy/viz/tests/test_fvtk_window.py +++ b/dipy/viz/tests/test_fvtk_window.py @@ -1,3 +1,4 @@ +import os import numpy as np from dipy.viz import actor, window import numpy.testing as npt @@ -191,7 +192,16 @@ def test_order_transparent(): renderer.camera().OrthogonalizeViewUp() renderer.reset_clipping_range() - arr = window.snapshot(renderer, offscreen=False, order_transparent=True) + renderer.reset_camera() + + not_xvfb = os.environ.get("TEST_WITH_XVFB", False) + + if not_xvfb: + arr = window.snapshot(renderer, fname='green_front.png', + offscreen=True, order_transparent=False) + else: + arr = window.snapshot(renderer, fname='green_front.png', + offscreen=False, order_transparent=False) # therefore the green component must have a higher value (in RGB terms) npt.assert_equal(arr[150, 150][1] > arr[150, 150][0], True) @@ -201,7 +211,12 @@ def test_order_transparent(): renderer.camera().OrthogonalizeViewUp() renderer.reset_clipping_range() - arr = window.snapshot(renderer, offscreen=False, order_transparent=True) + if not_xvfb: + arr = window.snapshot(renderer, fname='red_front.png', + offscreen=True, order_transparent=True) + else: + arr = window.snapshot(renderer, fname='red_front.png', + offscreen=False, order_transparent=True) # therefore the red component must have a higher value (in RGB terms) npt.assert_equal(arr[150, 150][0] > arr[150, 150][1], True) From 05cecb3f699945509e997283223c6ae1a9204fc0 Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 31 Oct 2015 19:39:06 -0400 Subject: [PATCH 239/242] TST: removed updated and used display_extent instead --- dipy/viz/tests/test_fvtk_actors.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 4241ef1e06..c817ab7a14 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -28,8 +28,7 @@ def test_slicer(): npt.assert_equal(report.objects, 1) # The slicer can cut directly a smaller part of the image - slicer.SetDisplayExtent(10, 30, 10, 30, 35, 35) - slicer.Update() + slicer.display_extent(10, 30, 10, 30, 35, 35) renderer.ResetCamera() window.add(renderer, slicer) From 748de39b79d3bfd506c31f40be4690e41acca90f Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 31 Oct 2015 20:44:30 -0400 Subject: [PATCH 240/242] TST: I am assuming that rendering was too fast and snapshot was not updated fast enough --- dipy/viz/tests/test_fvtk_actors.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index c817ab7a14..619b2c1ebf 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -20,6 +20,8 @@ def test_slicer(): affine = np.eye(4) slicer = actor.slicer(data, affine) window.add(renderer, slicer) + renderer.reset_camera() + renderer.reset_clipping_range() # window.show(renderer) # copy pixels in numpy array directly From 3eb2b4f76eef7875ea5f0931a138a49fd7c731cd Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sat, 31 Oct 2015 21:56:16 -0400 Subject: [PATCH 241/242] Trying to enforce displaying the actor --- dipy/viz/tests/test_fvtk_actors.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 619b2c1ebf..21ca7a1fc6 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -19,15 +19,19 @@ def test_slicer(): data = (255 * np.random.rand(50, 50, 50)) affine = np.eye(4) slicer = actor.slicer(data, affine) + slicer.display(None, None, 25) window.add(renderer, slicer) + renderer.reset_camera() renderer.reset_clipping_range() # window.show(renderer) # copy pixels in numpy array directly - arr = window.snapshot(renderer) + arr = window.snapshot(renderer, 'test_slicer.png') + print(arr.sum()) report = window.analyze_snapshot(arr, find_objects=True) npt.assert_equal(report.objects, 1) + # print(arr[..., 0]) # The slicer can cut directly a smaller part of the image slicer.display_extent(10, 30, 10, 30, 35, 35) From b590ca0bd089d1aac3322f9f115cf9b6e0410d6b Mon Sep 17 00:00:00 2001 From: Eleftherios Garyfallidis Date: Sun, 1 Nov 2015 16:10:01 -0500 Subject: [PATCH 242/242] Debugging with VTK=1 --- dipy/viz/tests/test_fvtk_actors.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dipy/viz/tests/test_fvtk_actors.py b/dipy/viz/tests/test_fvtk_actors.py index 21ca7a1fc6..86ae67ecc1 100644 --- a/dipy/viz/tests/test_fvtk_actors.py +++ b/dipy/viz/tests/test_fvtk_actors.py @@ -28,8 +28,20 @@ def test_slicer(): # copy pixels in numpy array directly arr = window.snapshot(renderer, 'test_slicer.png') + import scipy + print(scipy.__version__) + print(scipy.__file__) + print(arr.sum()) + print(np.sum(arr == 0)) + print(np.sum(arr > 0)) + print(arr.shape) + print(arr.dtype) + report = window.analyze_snapshot(arr, find_objects=True) + + print(report) + npt.assert_equal(report.objects, 1) # print(arr[..., 0])