Commit aa9d1fe9629f689902ff165d734c3b7a6607b4f7
1 parent
291b78c3
Exists in
master
and in
68 other branches
ADD: The histogram in the clut raycasting widget
Showing
3 changed files
with
49 additions
and
19 deletions
Show diff stats
invesalius/data/volume.py
... | ... | @@ -19,14 +19,17 @@ |
19 | 19 | import plistlib |
20 | 20 | import os |
21 | 21 | |
22 | +import numpy | |
22 | 23 | import vtk |
23 | 24 | import wx |
24 | 25 | import wx.lib.pubsub as ps |
25 | 26 | |
26 | 27 | import constants as const |
27 | -from data import vtk_utils | |
28 | 28 | import project as prj |
29 | 29 | |
30 | +from data import vtk_utils | |
31 | +from vtk.util import numpy_support | |
32 | + | |
30 | 33 | Kernels = { |
31 | 34 | "Basic Smooth 5x5" : [1.0, 1.0, 1.0, 1.0, 1.0, |
32 | 35 | 1.0, 4.0, 4.0, 4.0, 1.0, |
... | ... | @@ -128,6 +131,7 @@ class Volume(): |
128 | 131 | #ps.Publisher().sendMessage('Render volume viewer') |
129 | 132 | else: |
130 | 133 | self.LoadVolume() |
134 | + self.CalculateHistogram() | |
131 | 135 | self.exist = 1 |
132 | 136 | |
133 | 137 | if (self.plane and self.plane_on): |
... | ... | @@ -173,7 +177,7 @@ class Volume(): |
173 | 177 | ww = self.ww + diff_ww |
174 | 178 | wl = self.wl + diff_wl |
175 | 179 | ps.Publisher().sendMessage('Set volume window and level text', |
176 | - (ww, wl)) | |
180 | + (ww, wl)) | |
177 | 181 | self.SetWWWL(ww, wl) |
178 | 182 | self.ww = ww |
179 | 183 | self.wl = wl |
... | ... | @@ -184,7 +188,6 @@ class Volume(): |
184 | 188 | self.SetWWWL(ww,wl) |
185 | 189 | |
186 | 190 | def SetWWWL(self, ww, wl): |
187 | - | |
188 | 191 | if self.config['advancedCLUT']: |
189 | 192 | try: |
190 | 193 | curve = self.config['16bitClutCurves'][self.curve] |
... | ... | @@ -233,7 +236,6 @@ class Volume(): |
233 | 236 | def Refresh(self, pubsub_evt): |
234 | 237 | self.__update_colour_table() |
235 | 238 | |
236 | -#*************** | |
237 | 239 | def Create16bColorTable(self, scale): |
238 | 240 | if self.color_transfer: |
239 | 241 | color_transfer = self.color_transfer |
... | ... | @@ -530,6 +532,18 @@ class Volume(): |
530 | 532 | self.plane = CutPlane(self.final_imagedata, |
531 | 533 | self.volume_mapper) |
532 | 534 | |
535 | + def CalculateHistogram(self): | |
536 | + proj = prj.Project() | |
537 | + image = proj.imagedata | |
538 | + r = image.GetScalarRange()[1] - image.GetScalarRange()[0] | |
539 | + accumulate = vtk.vtkImageAccumulate() | |
540 | + accumulate.SetInput(image) | |
541 | + accumulate.SetComponentExtent(0, r -1, 0, 0, 0, 0) | |
542 | + accumulate.SetComponentOrigin(image.GetScalarRange()[0], 0, 0) | |
543 | + accumulate.Update() | |
544 | + n_image = numpy_support.vtk_to_numpy(accumulate.GetOutput().GetPointData().GetScalars()) | |
545 | + ps.Publisher().sendMessage('Load histogram', (n_image, | |
546 | + image.GetScalarRange())) | |
533 | 547 | |
534 | 548 | def TranslateScale(self, scale, value): |
535 | 549 | #if value < 0: | ... | ... |
invesalius/gui/default_viewers.py
... | ... | @@ -237,8 +237,10 @@ class VolumeInteraction(wx.Panel): |
237 | 237 | 'Hide raycasting widget') |
238 | 238 | ps.Publisher().subscribe(self.OnSetRaycastPreset, |
239 | 239 | 'Update raycasting preset') |
240 | - ps.Publisher().subscribe( self.RefreshPoints, | |
240 | + ps.Publisher().subscribe(self.RefreshPoints, | |
241 | 241 | 'Refresh raycasting widget points') |
242 | + ps.Publisher().subscribe(self.LoadHistogram, | |
243 | + 'Load histogram') | |
242 | 244 | |
243 | 245 | def __update_curve_wwwl_text(self, curve): |
244 | 246 | ww, wl = self.clut_raycasting.GetCurveWWWl(curve) |
... | ... | @@ -283,6 +285,12 @@ class VolumeInteraction(wx.Panel): |
283 | 285 | p.Hide() |
284 | 286 | self.aui_manager.Update() |
285 | 287 | |
288 | + def LoadHistogram(self, pubsub_evt): | |
289 | + histogram = pubsub_evt.data[0] | |
290 | + init, end = pubsub_evt.data[1] | |
291 | + self.clut_raycasting.SetRange((init, end)) | |
292 | + self.clut_raycasting.SetHistogramArray(histogram, (init, end)) | |
293 | + | |
286 | 294 | def RefreshPoints(self, pubsub_evt): |
287 | 295 | self.clut_raycasting.CalculatePixelPoints() |
288 | 296 | self.clut_raycasting.Refresh() | ... | ... |
invesalius/gui/widgets/clut_raycasting.py
... | ... | @@ -51,6 +51,12 @@ class Curve(object): |
51 | 51 | self.wl = self.nodes[0].graylevel + self.ww / 2.0 |
52 | 52 | |
53 | 53 | |
54 | +class Histogram(object): | |
55 | + def __init__(self): | |
56 | + self.init = -1024 | |
57 | + self.end = 2000 | |
58 | + | |
59 | + | |
54 | 60 | class CLUTRaycastingWidget(wx.Panel): |
55 | 61 | """ |
56 | 62 | This class represents the frame where images is showed |
... | ... | @@ -68,6 +74,7 @@ class CLUTRaycastingWidget(wx.Panel): |
68 | 74 | self.curves = [] |
69 | 75 | self.init = -1024 |
70 | 76 | self.end = 2000 |
77 | + self.Histogram = Histogram() | |
71 | 78 | self.padding = 5 |
72 | 79 | self.previous_wl = 0 |
73 | 80 | self.to_render = False |
... | ... | @@ -484,14 +491,14 @@ class CLUTRaycastingWidget(wx.Panel): |
484 | 491 | ctx.set_line_width(HISTOGRAM_LINE_WIDTH) |
485 | 492 | for x,y in self.histogram_pixel_points: |
486 | 493 | ctx.line_to(x,y) |
487 | - ctx.line_to(x, height) | |
488 | - ctx.line_to(0, height) | |
494 | + ctx.set_source_rgb(*HISTOGRAM_LINE_COLOUR) | |
495 | + ctx.stroke_preserve() | |
496 | + ctx.line_to(x, height + self.padding) | |
497 | + ctx.line_to(self.HounsfieldToPixel(self.Histogram.init), height + self.padding) | |
489 | 498 | x,y = self.histogram_pixel_points[0] |
490 | 499 | ctx.line_to(x, y) |
491 | 500 | ctx.set_source_rgb(*HISTOGRAM_FILL_COLOUR) |
492 | - ctx.fill_preserve() | |
493 | - ctx.set_source_rgb(*HISTOGRAM_LINE_COLOUR) | |
494 | - ctx.stroke() | |
501 | + ctx.fill() | |
495 | 502 | |
496 | 503 | def _draw_selection_curve(self, ctx, height): |
497 | 504 | for curve in self.curves: |
... | ... | @@ -520,24 +527,23 @@ class CLUTRaycastingWidget(wx.Panel): |
520 | 527 | self._draw_selected_point_text(ctx) |
521 | 528 | |
522 | 529 | def _build_histogram(self): |
523 | - width, height= self.GetVirtualSizeTuple() | |
530 | + width, height = self.GetVirtualSizeTuple() | |
524 | 531 | width -= self.padding |
525 | - height -= self.padding | |
532 | + height -= (self.padding * 2) | |
533 | + x_init = self.Histogram.init | |
534 | + x_end = self.Histogram.end | |
526 | 535 | y_init = 0 |
527 | 536 | y_end = math.log(max(self.histogram_array)) |
528 | - print y_end | |
529 | - proportion_x = width * 1.0 / (self.end - self.init) | |
537 | + proportion_x = width * 1.0 / (x_end - x_init) | |
530 | 538 | proportion_y = height * 1.0 / (y_end - y_init) |
531 | - print ":) ", y_end, proportion_y | |
532 | 539 | self.histogram_pixel_points = [] |
533 | 540 | for i in xrange(len(self.histogram_array)): |
534 | 541 | if self.histogram_array[i]: |
535 | 542 | y = math.log(self.histogram_array[i]) |
536 | 543 | else: |
537 | 544 | y = 0 |
538 | - x = self.init+ i | |
539 | - x = (x + abs(self.init)) * proportion_x | |
540 | - y = height - y * proportion_y | |
545 | + x = self.HounsfieldToPixel(x_init + i) | |
546 | + y = height - y * proportion_y + self.padding | |
541 | 547 | self.histogram_pixel_points.append((x, y)) |
542 | 548 | |
543 | 549 | def __sort_pixel_points(self): |
... | ... | @@ -627,8 +633,10 @@ class CLUTRaycastingWidget(wx.Panel): |
627 | 633 | self.to_draw_points = 0 |
628 | 634 | self.Refresh() |
629 | 635 | |
630 | - def SetHistrogramArray(self, h_array): | |
636 | + def SetHistogramArray(self, h_array, range): | |
631 | 637 | self.histogram_array = h_array |
638 | + self.Histogram.init = range[0] | |
639 | + self.Histogram.end = range[1] | |
632 | 640 | |
633 | 641 | def GetCurveWWWl(self, curve): |
634 | 642 | return (self.curves[curve].ww, self.curves[curve].wl) | ... | ... |