From 1ffd8d89bd6a60b23c22a887e3c40f9f592f2b74 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Thu, 23 Jul 2015 13:34:15 +0100 Subject: [PATCH] I have no idea how bricon <-> display range sync was working at all. Replaced the old contrast scaling equation with somthing simpler to invert (and replaced the previously-incorrect inverted scale->contrast equation). VolumeOpts was incorrectly flipping the resulting bricon values, as well. Other small changes - fsldirdlg layout tweak, and ActionButton now does not require the action to be listed in the strings module. --- fsl/fslview/actions/__init__.py | 13 ++--- fsl/fslview/colourmaps.py | 64 +++++++++++++----------- fsl/fslview/displaycontext/volumeopts.py | 4 +- fsl/utils/fsldirdlg.py | 4 +- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/fsl/fslview/actions/__init__.py b/fsl/fslview/actions/__init__.py index 6d76b40a3..8fd3a8627 100644 --- a/fsl/fslview/actions/__init__.py +++ b/fsl/fslview/actions/__init__.py @@ -55,12 +55,13 @@ class ActionButton(props.Button): self.name = actionName - props.Button.__init__(self, - actionName, - text=strings.actions[classType, actionName], - callback=self.__onButton, - setup=self.__setup, - **kwargs) + props.Button.__init__( + self, + actionName, + text=strings.actions.get((classType, actionName), actionName), + callback=self.__onButton, + setup=self.__setup, + **kwargs) def __setup(self, instance, parent, widget, *a): diff --git a/fsl/fslview/colourmaps.py b/fsl/fslview/colourmaps.py index c500932c1..2b3a6e583 100644 --- a/fsl/fslview/colourmaps.py +++ b/fsl/fslview/colourmaps.py @@ -712,6 +712,35 @@ def installLookupTable(lutName): ############### +def _briconToScaleOffset(brightness, contrast, drange): + """Used by the :func:`briconToDisplayRange` and the :func:`applyBricon` + functions. + + Calculates a scale and offset which can be used to transform a display + range of the given size so that the given brightness/contrast settings + are applied. + """ + + # The brightness is applied as a linear offset, + # with 0.5 equivalent to an offset of 0.0. + offset = (brightness * 2 - 1) * drange + + # If the contrast lies between 0.0 and 0.5, it is + # applied to the colour as a linear scaling factor. + if contrast <= 0.5: + scale = contrast * 2 + + # If the contrast lies between 0.5 and 1, it + # is applied as an exponential scaling factor, + # so lower values (closer to 0.5) have less of + # an effect than higher values (closer to 1.0). + else: + scale = 20 * contrast ** 4 - 0.25 + + return scale, offset + + + def briconToDisplayRange(dataRange, brightness, contrast): """Converts the given brightness/contrast values to a display range, given the data range. @@ -733,20 +762,8 @@ def briconToDisplayRange(dataRange, brightness, contrast): drange = dmax - dmin dmid = dmin + 0.5 * drange - # The brightness is applied as a linear offset, - # with 0.5 equivalent to an offset of 0.0. - offset = (brightness * 2 - 1) * drange + scale, offset = _briconToScaleOffset(brightness, contrast, drange) - # If the contrast lies between 0.0 and 0.5, it is - # applied to the colour as a linear scaling factor. - scale = contrast * 2 - - # If the contrast lies between 0.5 and 1, it - # is applied as an exponential scaling factor, - # so lower values (closer to 0.5) have less of - # an effect than higher values (closer to 1.0). - if contrast > 0.5: - scale += np.exp((contrast - 0.5) * 6) - 1 # Calculate the new display range, keeping it # centered in the middle of the data range @@ -773,7 +790,7 @@ def displayRangeToBricon(dataRange, displayRange): dmid = dmin + 0.5 * drange # These are inversions of the equations in - # the briconToDisplayRange function above, + # the briconToScaleOffset function above, # which calculate the display ranges from # the bricon offset/scale offset = dlo + 0.5 * (dhi - dlo) - dmid @@ -782,7 +799,7 @@ def displayRangeToBricon(dataRange, displayRange): brightness = 0.5 * (offset / drange + 1) if scale <= 1: contrast = scale / 2.0 - else: contrast = np.log(scale + 1) / 6.0 + 0.5 + else: contrast = ((scale + 0.25) / 20.0) ** 0.25 brightness = 1.0 - brightness contrast = 1.0 - contrast @@ -805,26 +822,13 @@ def applyBricon(rgb, brightness, contrast): :arg brightness: A brightness level in the range ``[0, 1]``. - :arg contrast: A brightness level in the range ``[0, 1]``. + :arg contrast: A contrast level in the range ``[0, 1]``. """ rgb = np.array(rgb) oneColour = len(rgb.shape) == 1 rgb = rgb.reshape(-1, rgb.shape[-1]) - # The brightness is applied as a linear offset, - # with 0.5 equivalent to an offset of 0.0. - offset = (brightness * 2 - 1) - - # If the contrast lies between 0.0 and 0.5, it is - # applied to the colour as a linear scaling factor. - scale = contrast * 2 - - # If the contrast lies between 0.5 and 0.1, it - # is applied as an exponential scaling factor, - # so lower values (closer to 0.5) have less of - # an effect than higher values (closer to 1.0). - if (contrast > 0.5): - scale += np.exp((contrast - 0.5) * 6) - 1 + scale, offset = _briconToScaleOffset(brightness, contrast, 1) # The contrast factor scales the existing colour # range, but keeps the new range centred at 0.5. diff --git a/fsl/fslview/displaycontext/volumeopts.py b/fsl/fslview/displaycontext/volumeopts.py index c167454e2..928a92b96 100644 --- a/fsl/fslview/displaycontext/volumeopts.py +++ b/fsl/fslview/displaycontext/volumeopts.py @@ -430,7 +430,7 @@ class VolumeOpts(ImageOpts): self.__toggleListeners(False) # update bricon - self.display.brightness = 100 - brightness * 100 - self.display.contrast = 100 - contrast * 100 + self.display.brightness = brightness * 100 + self.display.contrast = contrast * 100 self.__toggleListeners(True) diff --git a/fsl/utils/fsldirdlg.py b/fsl/utils/fsldirdlg.py index ba983379b..86fe646d3 100644 --- a/fsl/utils/fsldirdlg.py +++ b/fsl/utils/fsldirdlg.py @@ -62,11 +62,11 @@ class FSLDirDialog(wx.Dialog): flag=wx.ALL | wx.CENTRE, border=10, proportion=1) - - self.__buttonSizer.Add((40, -1)) + self.__buttonSizer.Add((20, -1)) self.__sizer.Add(self.__labelSizer, flag=wx.EXPAND, proportion=1) self.__sizer.Add(self.__buttonSizer, flag=wx.EXPAND) + self.__sizer.Add((-1, 20)) self.SetSizer(self.__sizer) self.Fit() -- GitLab