summaryrefslogtreecommitdiff
path: root/silx/gui/plot/actions/histogram.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/plot/actions/histogram.py')
-rw-r--r--silx/gui/plot/actions/histogram.py170
1 files changed, 170 insertions, 0 deletions
diff --git a/silx/gui/plot/actions/histogram.py b/silx/gui/plot/actions/histogram.py
new file mode 100644
index 0000000..a4a91e9
--- /dev/null
+++ b/silx/gui/plot/actions/histogram.py
@@ -0,0 +1,170 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""
+:mod:`silx.gui.plot.actions.histogram` provides actions relative to histograms
+for :class:`.PlotWidget`.
+
+The following QAction are available:
+
+- :class:`PixelIntensitiesHistoAction`
+"""
+
+from __future__ import division
+
+__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
+__date__ = "27/06/2017"
+__license__ = "MIT"
+
+from . import PlotAction
+from silx.math.histogram import Histogramnd
+import numpy
+import logging
+from silx.gui import qt
+
+_logger = logging.getLogger(__name__)
+
+
+class PixelIntensitiesHistoAction(PlotAction):
+ """QAction to plot the pixels intensities diagram
+
+ :param plot: :class:`.PlotWidget` instance on which to operate
+ :param parent: See :class:`QAction`
+ """
+
+ def __init__(self, plot, parent=None):
+ PlotAction.__init__(self,
+ plot,
+ icon='pixel-intensities',
+ text='pixels intensity',
+ tooltip='Compute image intensity distribution',
+ triggered=self._triggered,
+ parent=parent,
+ checkable=True)
+ self._plotHistogram = None
+ self._connectedToActiveImage = False
+ self._histo = None
+
+ def _triggered(self, checked):
+ """Update the plot of the histogram visibility status
+
+ :param bool checked: status of the action button
+ """
+ if checked:
+ if not self._connectedToActiveImage:
+ self.plot.sigActiveImageChanged.connect(
+ self._activeImageChanged)
+ self._connectedToActiveImage = True
+ self.computeIntensityDistribution()
+
+ self.getHistogramPlotWidget().show()
+
+ else:
+ if self._connectedToActiveImage:
+ self.plot.sigActiveImageChanged.disconnect(
+ self._activeImageChanged)
+ self._connectedToActiveImage = False
+
+ self.getHistogramPlotWidget().hide()
+
+ def _activeImageChanged(self, previous, legend):
+ """Handle active image change: toggle enabled toolbar, update curve"""
+ if self.isChecked():
+ self.computeIntensityDistribution()
+
+ def computeIntensityDistribution(self):
+ """Get the active image and compute the image intensity distribution
+ """
+ activeImage = self.plot.getActiveImage()
+
+ if activeImage is not None:
+ image = activeImage.getData(copy=False)
+ if image.ndim == 3: # RGB(A) images
+ _logger.info('Converting current image from RGB(A) to grayscale\
+ in order to compute the intensity distribution')
+ image = (image[:, :, 0] * 0.299 +
+ image[:, :, 1] * 0.587 +
+ image[:, :, 2] * 0.114)
+
+ xmin = numpy.nanmin(image)
+ xmax = numpy.nanmax(image)
+ nbins = min(1024, int(numpy.sqrt(image.size)))
+ data_range = xmin, xmax
+
+ # bad hack: get 256 bins in the case we have a B&W
+ if numpy.issubdtype(image.dtype, numpy.integer):
+ if nbins > xmax - xmin:
+ nbins = xmax - xmin
+
+ nbins = max(2, nbins)
+
+ data = image.ravel().astype(numpy.float32)
+ histogram = Histogramnd(data, n_bins=nbins, histo_range=data_range)
+ assert len(histogram.edges) == 1
+ self._histo = histogram.histo
+ edges = histogram.edges[0]
+ plot = self.getHistogramPlotWidget()
+ plot.addHistogram(histogram=self._histo,
+ edges=edges,
+ legend='pixel intensity',
+ fill=True,
+ color='red')
+ plot.resetZoom()
+
+ def eventFilter(self, qobject, event):
+ """Observe when the close event is emitted then
+ simply uncheck the action button
+
+ :param qobject: the object observe
+ :param event: the event received by qobject
+ """
+ if event.type() == qt.QEvent.Close:
+ if self._plotHistogram is not None:
+ self._plotHistogram.hide()
+ self.setChecked(False)
+
+ return PlotAction.eventFilter(self, qobject, event)
+
+ def getHistogramPlotWidget(self):
+ """Create the plot histogram if needed, otherwise create it
+
+ :return: the PlotWidget showing the histogram of the pixel intensities
+ """
+ from silx.gui.plot.PlotWindow import Plot1D
+ if self._plotHistogram is None:
+ self._plotHistogram = Plot1D(parent=self.plot)
+ self._plotHistogram.setWindowFlags(qt.Qt.Window)
+ self._plotHistogram.setWindowTitle('Image Intensity Histogram')
+ self._plotHistogram.installEventFilter(self)
+ self._plotHistogram.getXAxis().setLabel("Value")
+ self._plotHistogram.getYAxis().setLabel("Count")
+
+ return self._plotHistogram
+
+ def getHistogram(self):
+ """Return the last computed histogram
+
+ :return: the histogram displayed in the HistogramPlotWiget
+ """
+ return self._histo