summaryrefslogtreecommitdiff
path: root/examples/findContours.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/findContours.py')
-rw-r--r--examples/findContours.py704
1 files changed, 704 insertions, 0 deletions
diff --git a/examples/findContours.py b/examples/findContours.py
new file mode 100644
index 0000000..a5bb663
--- /dev/null
+++ b/examples/findContours.py
@@ -0,0 +1,704 @@
+#!/usr/bin/env python
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2016-2018 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.
+#
+# ###########################################################################*/
+"""Find contours examples
+
+.. note:: This module has an optional dependancy with sci-kit image library.
+ You might need to install it if you don't already have it.
+"""
+
+import logging
+import sys
+import numpy
+import time
+
+logging.basicConfig()
+_logger = logging.getLogger("find_contours")
+
+from silx.gui import qt
+import silx.gui.plot
+from silx.gui.colors import Colormap
+import silx.image.bilinear
+
+
+try:
+ import skimage
+except ImportError:
+ _logger.debug("Error while importing skimage", exc_info=True)
+ skimage = None
+
+if skimage is not None:
+ try:
+ from silx.image.marchingsquares._skimage import MarchingSquaresSciKitImage
+ except ImportError:
+ _logger.debug("Error while importing MarchingSquaresSciKitImage", exc_info=True)
+ MarchingSquaresSciKitImage = None
+else:
+ MarchingSquaresSciKitImage = None
+
+
+def rescale_image(image, shape):
+ y, x = numpy.ogrid[:shape[0], :shape[1]]
+ y, x = y * 1.0 * (image.shape[0] - 1) / (shape[0] - 1), x * 1.0 * (image.shape[1] - 1) / (shape[1] - 1)
+ b = silx.image.bilinear.BilinearImage(image)
+ # TODO: could be optimized using strides
+ x2d = numpy.zeros_like(y) + x
+ y2d = numpy.zeros_like(x) + y
+ result = b.map_coordinates((y2d, x2d))
+ return result
+
+
+def create_spiral(size, nb=1, freq=100):
+ half = size // 2
+ y, x = numpy.ogrid[-half:half, -half:half]
+ coef = 1.0 / half
+ y, x = y * coef, x * coef + 0.0001
+ distance = numpy.sqrt(x * x + y * y)
+ angle = numpy.arctan(y / x)
+ data = numpy.sin(angle * nb * 2 + distance * freq * half / 100, dtype=numpy.float32)
+ return data
+
+
+def create_magnetic_field(size, x1=0.0, y1=0.0, x2=0.0, y2=0.0):
+ half = size // 2
+ yy, xx = numpy.ogrid[-half:half, -half:half]
+ coef = 1.0 / half
+ yy1, xx1 = (yy + half * y1) * coef, (xx + half * x1) * coef
+ distance1 = numpy.sqrt(xx1 * xx1 + yy1 * yy1)
+ yy2, xx2 = (yy + half * y2) * coef, (xx + half * x2) * coef
+ distance2 = numpy.sqrt(xx2 * xx2 + yy2 * yy2)
+ return (numpy.arctan2(distance1, distance2) - numpy.pi * 0.25) * 1000
+
+
+def create_gravity_field(size, objects):
+ half = size // 2
+ yy, xx = numpy.ogrid[-half:half, -half:half]
+ coef = 1.0 / half
+
+ def distance(x, y):
+ yy1, xx1 = (yy + half * y) * coef, (xx + half * x) * coef
+ return numpy.sqrt(xx1 ** 2 + yy1 ** 2)
+ result = numpy.zeros((size, size), dtype=numpy.float32)
+ for x, y, m in objects:
+ result += m / distance(x, y)
+ return numpy.log(result) * 1000
+
+
+def create_gradient(size, dx=0, dy=0, sx=1.0, sy=1.0):
+ half = size // 2
+ yy, xx = numpy.ogrid[-half:half, -half:half]
+ coef = 1.0 / half
+ yy, xx = (yy - (dy * half)) * coef, (xx - (dx * half)) * coef + 0.0001
+ distance = numpy.sqrt(xx * xx * sx + yy * yy * sy)
+ return distance
+
+
+def create_composite_gradient(size, dx=0, dy=0, sx=1.0, sy=1.0):
+ hole = (size - 4) // 4
+ gap = 10
+ base = create_gradient(size + hole + gap * 4, dx, dy, sx, sy)
+ result = numpy.zeros((size, size))
+ width = (size - 2) // 2
+ half_hole = hole // 2
+
+ def copy_module(x1, y1, x2, y2, width, height):
+ result[y1:y1 + height, x1:x1 + width] = base[y2:y2 + height, x2:x2 + width]
+
+ y1 = 0
+ y2 = 0
+ copy_module(0, y1, half_hole, y2, width, hole)
+ copy_module(width + 1, y1, half_hole + width, y2, width, hole)
+
+ y1 += hole + 1
+ y2 += hole + gap
+ copy_module(0, y1, 0, y2, width, hole)
+ copy_module(width + 1, y1, width + hole, y2, width, hole)
+
+ y1 += hole + 1
+ y2 += hole + gap
+ copy_module(0, y1, half_hole, y2, width, hole)
+ copy_module(width + 1, y1, half_hole + width, y2, width, hole)
+
+ y1 += hole + 1
+ y2 += hole + gap
+ copy_module(0, y1, half_hole, y2, width, hole)
+ copy_module(width + 1, y1, half_hole + width, y2, width, hole)
+
+ return result
+
+
+def create_value_noise(shape, octaves=8, weights=None, first_array=None):
+ data = numpy.zeros(shape, dtype=numpy.float32)
+ t = 2
+ for i in range(octaves):
+ if t > shape[0] and t > shape[1]:
+ break
+ if i == 0 and first_array is not None:
+ d = first_array
+ else:
+ if weights is None:
+ w = (256 >> i) - 1
+ else:
+ w = weights[i]
+ d = numpy.random.randint(w, size=(t, t)).astype(dtype=numpy.uint8)
+ d = rescale_image(d, shape)
+ data = data + d
+ t = t << 1
+ return data
+
+
+def create_island(shape, summit, under_water):
+ # Force a centric shape
+ first_array = numpy.zeros((4, 4), dtype=numpy.uint8)
+ first_array[1:3, 1:3] = 255
+ weights = [255] + [(256 >> (i)) - 1 for i in range(8)]
+ data = create_value_noise(shape, octaves=7, first_array=first_array, weights=weights)
+ # more slops
+ data *= data
+ # normalize the height
+ data -= data.min()
+ data = data * ((summit + under_water) / data.max()) - under_water
+ return data
+
+
+def createRgbaMaskImage(mask, color):
+ """Generate an RGBA image where a custom color is apply to the location of
+ the mask. Non masked part of the image is transparent."""
+ image = numpy.zeros((mask.shape[0], mask.shape[1], 4), dtype=numpy.uint8)
+ color = numpy.array(color)
+ image[mask == True] = color
+ return image
+
+
+class FindContours(qt.QMainWindow):
+ """
+ This window show an example of use of a Hdf5TreeView.
+
+ The tree is initialized with a list of filenames. A panel allow to play
+ with internal property configuration of the widget, and a text screen
+ allow to display events.
+ """
+
+ def __init__(self, filenames=None):
+ """
+ :param files_: List of HDF5 or Spec files (pathes or
+ :class:`silx.io.spech5.SpecH5` or :class:`h5py.File`
+ instances)
+ """
+ qt.QMainWindow.__init__(self)
+ self.setWindowTitle("Silx HDF5 widget example")
+
+ self.__plot = silx.gui.plot.Plot2D(parent=self)
+ dummy = numpy.array([[0]])
+ self.__plot.addImage(dummy, legend="image", z=-10, replace=False)
+ dummy = numpy.array([[[0, 0, 0, 0]]])
+ self.__plot.addImage(dummy, legend="iso-pixels", z=0, replace=False)
+
+ self.__algo = None
+ self.__polygons = []
+ self.__customPolygons = []
+ self.__image = None
+ self.__mask = None
+ self.__customValue = None
+
+ mainPanel = qt.QWidget(self)
+ layout = qt.QHBoxLayout()
+ layout.addWidget(self.__createConfigurationPanel(self))
+ layout.addWidget(self.__plot)
+ mainPanel.setLayout(layout)
+
+ self.setCentralWidget(mainPanel)
+
+ def __createConfigurationPanel(self, parent):
+ panel = qt.QWidget(parent=parent)
+ layout = qt.QVBoxLayout()
+ panel.setLayout(layout)
+
+ self.__kind = qt.QButtonGroup(self)
+ self.__kind.setExclusive(True)
+
+ group = qt.QGroupBox(self)
+ group.setTitle("Image")
+ layout.addWidget(group)
+ groupLayout = qt.QVBoxLayout(group)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("Island")
+ button.clicked.connect(self.generateIsland)
+ button.setCheckable(True)
+ button.setChecked(True)
+ groupLayout.addWidget(button)
+ self.__kind.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("Gravity")
+ button.clicked.connect(self.generateGravityField)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__kind.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("Magnetic")
+ button.clicked.connect(self.generateMagneticField)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__kind.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("Spiral")
+ button.clicked.connect(self.generateSpiral)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__kind.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("Gradient")
+ button.clicked.connect(self.generateGradient)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__kind.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("Composite gradient")
+ button.clicked.connect(self.generateCompositeGradient)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__kind.addButton(button)
+
+ button = qt.QPushButton(parent=panel)
+ button.setText("Generate a new image")
+ button.clicked.connect(self.generate)
+ groupLayout.addWidget(button)
+
+ # Contours
+
+ group = qt.QGroupBox(self)
+ group.setTitle("Contours")
+ layout.addWidget(group)
+ groupLayout = qt.QVBoxLayout(group)
+
+ button = qt.QCheckBox(parent=panel)
+ button.setText("Use the plot's mask")
+ button.setCheckable(True)
+ button.setChecked(True)
+ button.clicked.connect(self.updateContours)
+ groupLayout.addWidget(button)
+ self.__useMaskButton = button
+
+ button = qt.QPushButton(parent=panel)
+ button.setText("Update contours")
+ button.clicked.connect(self.updateContours)
+ groupLayout.addWidget(button)
+
+ # Implementations
+
+ group = qt.QGroupBox(self)
+ group.setTitle("Implementation")
+ layout.addWidget(group)
+ groupLayout = qt.QVBoxLayout(group)
+
+ self.__impl = qt.QButtonGroup(self)
+ self.__impl.setExclusive(True)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("silx")
+ button.clicked.connect(self.updateContours)
+ button.setCheckable(True)
+ button.setChecked(True)
+ groupLayout.addWidget(button)
+ self.__implMerge = button
+ self.__impl.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("silx with cache")
+ button.clicked.connect(self.updateContours)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__implMergeCache = button
+ self.__impl.addButton(button)
+
+ button = qt.QRadioButton(parent=panel)
+ button.setText("skimage")
+ button.clicked.connect(self.updateContours)
+ button.setCheckable(True)
+ groupLayout.addWidget(button)
+ self.__implSkimage = button
+ self.__impl.addButton(button)
+ if MarchingSquaresSciKitImage is None:
+ button.setEnabled(False)
+ button.setToolTip("skimage is not installed or not compatible")
+
+ # Processing
+
+ group = qt.QGroupBox(self)
+ group.setTitle("Processing")
+ layout.addWidget(group)
+ group.setLayout(self.__createInfoLayout(group))
+
+ # Processing
+
+ group = qt.QGroupBox(self)
+ group.setTitle("Custom level")
+ layout.addWidget(group)
+ groupLayout = qt.QVBoxLayout(group)
+
+ label = qt.QLabel(parent=panel)
+ self.__value = qt.QSlider(panel)
+ self.__value.setOrientation(qt.Qt.Horizontal)
+ self.__value.sliderMoved.connect(self.__updateCustomContours)
+ self.__value.valueChanged.connect(self.__updateCustomContours)
+ groupLayout.addWidget(self.__value)
+
+ return panel
+
+ def __createInfoLayout(self, parent):
+ layout = qt.QGridLayout()
+
+ header = qt.QLabel(parent=parent)
+ header.setText("Time: ")
+ label = qt.QLabel(parent=parent)
+ label.setText("")
+ layout.addWidget(header, 0, 0)
+ layout.addWidget(label, 0, 1)
+ self.__timeLabel = label
+
+ header = qt.QLabel(parent=parent)
+ header.setText("Nb polygons: ")
+ label = qt.QLabel(parent=parent)
+ label.setText("")
+ layout.addWidget(header, 2, 0)
+ layout.addWidget(label, 2, 1)
+ self.__polygonsLabel = label
+
+ header = qt.QLabel(parent=parent)
+ header.setText("Nb points: ")
+ label = qt.QLabel(parent=parent)
+ label.setText("")
+ layout.addWidget(header, 1, 0)
+ layout.addWidget(label, 1, 1)
+ self.__pointsLabel = label
+
+ return layout
+
+ def __cleanCustomContour(self):
+ for name in self.__customPolygons:
+ self.__plot.removeCurve(name)
+ self.__customPolygons = []
+ dummy = numpy.array([[[0, 0, 0, 0]]])
+ item = self.__plot.getImage(legend="iso-pixels")
+ item.setData([[[0, 0, 0, 0]]])
+
+ def __cleanPolygons(self):
+ for name in self.__polygons:
+ self.__plot.removeCurve(name)
+
+ def clean(self):
+ self.__cleanCustomContour()
+ self.__cleanPolygons()
+ self.__polygons = []
+ self.__image = None
+ self.__mask = None
+
+ def updateContours(self):
+ self.__redrawContours()
+ self.updateCustomContours()
+
+ def __updateCustomContours(self, value):
+ self.__customValue = value
+ self.updateCustomContours()
+
+ def updateCustomContours(self):
+ if self.__algo is None:
+ return
+ value = self.__customValue
+ self.__cleanCustomContour()
+ if value is None:
+ return
+
+ # iso pixels
+ iso_pixels = self.__algo.find_pixels(value)
+ if len(iso_pixels) != 0:
+ mask = numpy.zeros(self.__image.shape, dtype=numpy.int8)
+ indexes = iso_pixels[:, 0] * self.__image.shape[1] + iso_pixels[:, 1]
+ mask = mask.ravel()
+ mask[indexes] = 1
+ mask.shape = self.__image.shape
+ mask = createRgbaMaskImage(mask, color=numpy.array([255, 0, 0, 128]))
+ item = self.__plot.getImage(legend="iso-pixels")
+ item.setData(mask)
+
+ # iso contours
+ polygons = self.__algo.find_contours(value)
+ for ipolygon, polygon in enumerate(polygons):
+ if len(polygon) == 0:
+ continue
+ isClosed = numpy.allclose(polygon[0], polygon[-1])
+ x = polygon[:, 1] + 0.5
+ y = polygon[:, 0] + 0.5
+ legend = "custom-polygon-%d" % ipolygon
+ self.__customPolygons.append(legend)
+ self.__plot.addCurve(x=x, y=y, linestyle="--", color="red", linewidth=2.0, legend=legend, resetzoom=False)
+
+ def __updateAlgo(self, image, mask=None):
+ if mask is None:
+ if self.__useMaskButton.isChecked():
+ mask = self.__plot.getMaskToolsDockWidget().getSelectionMask()
+
+ self.__image = image
+ self.__mask = mask
+
+ implButton = self.__impl.checkedButton()
+ if implButton == self.__implMerge:
+ from silx.image.marchingsquares import MarchingSquaresMergeImpl
+ self.__algo = MarchingSquaresMergeImpl(self.__image, self.__mask)
+ elif implButton == self.__implMergeCache:
+ from silx.image.marchingsquares import MarchingSquaresMergeImpl
+ self.__algo = MarchingSquaresMergeImpl(self.__image, self.__mask, use_minmax_cache=True)
+ elif implButton == self.__implSkimage and MarchingSquaresSciKitImage is not None:
+ self.__algo = MarchingSquaresSciKitImage(self.__image, self.__mask)
+ else:
+ _logger.error("No algorithm available")
+ self.__algo = None
+
+ def setData(self, image, mask=None, value=0.0):
+ self.clean()
+
+ self.__updateAlgo(image, mask=None)
+
+ # image
+ item = self.__plot.getImage(legend="image")
+ item.setData(image)
+ item.setColormap(self.__colormap)
+
+ self.__plot.resetZoom()
+
+ def __redrawContours(self):
+ self.__updateAlgo(self.__image)
+ if self.__algo is None:
+ return
+ self.__cleanPolygons()
+ self.__drawContours(self.__values, self.__lineStyleCallback)
+
+ def __drawContours(self, values, lineStyleCallback=None):
+ if self.__algo is None:
+ return
+
+ self.__values = values
+ self.__lineStyleCallback = lineStyleCallback
+ if self.__values is None:
+ return
+
+ nbTime = 0
+ nbPolygons = 0
+ nbPoints = 0
+
+ # iso contours
+ ipolygon = 0
+ for ivalue, value in enumerate(values):
+ startTime = time.time()
+ polygons = self.__algo.find_contours(value)
+ nbTime += (time.time() - startTime)
+ nbPolygons += len(polygons)
+ for polygon in polygons:
+ if len(polygon) == 0:
+ continue
+ nbPoints += len(polygon)
+ isClosed = numpy.allclose(polygon[0], polygon[-1])
+ x = polygon[:, 1] + 0.5
+ y = polygon[:, 0] + 0.5
+ legend = "polygon-%d" % ipolygon
+ if lineStyleCallback is not None:
+ extraStyle = lineStyleCallback(value, ivalue, ipolygon)
+ else:
+ extraStyle = {"linestyle": "-", "linewidth": 1.0, "color": "black"}
+ self.__polygons.append(legend)
+ self.__plot.addCurve(x=x, y=y, legend=legend, resetzoom=False, **extraStyle)
+ ipolygon += 1
+
+ self.__timeLabel.setText("%0.3fs" % nbTime)
+ self.__polygonsLabel.setText("%d" % nbPolygons)
+ self.__pointsLabel.setText("%d" % nbPoints)
+
+ def __defineDefaultValues(self, value=None):
+ # Do not use min and max to avoid to create iso contours on small
+ # and many artefacts
+ if value is None:
+ value = self.__image.mean()
+ self.__customValue = value
+ div = 12
+ delta = (self.__image.max() - self.__image.min()) / div
+ self.__value.setValue(value)
+ self.__value.setRange(self.__image.min() + delta,
+ self.__image.min() + delta * (div - 1))
+ self.updateCustomContours()
+
+ def generate(self):
+ self.__kind.checkedButton().click()
+
+ def generateSpiral(self):
+ shape = 512
+ nb_spiral = numpy.random.randint(1, 8)
+ freq = numpy.random.randint(2, 50)
+ image = create_spiral(shape, nb_spiral, freq)
+ image *= 1000.0
+ self.__colormap = Colormap("cool")
+ self.setData(image=image, mask=None)
+ self.__defineDefaultValues()
+
+ def generateIsland(self):
+ shape = (512, 512)
+ image = create_island(shape, summit=4808.72, under_water=1500)
+ self.__colormap = Colormap("terrain")
+ self.setData(image=image, mask=None)
+
+ values = range(-800, 5000, 200)
+
+ def styleCallback(value, ivalue, ipolygon):
+ if value == 0:
+ style = {"linestyle": "-", "linewidth": 1.0, "color": "black"}
+ elif value % 1000 == 0:
+ style = {"linestyle": "--", "linewidth": 0.5, "color": "black"}
+ else:
+ style = {"linestyle": "--", "linewidth": 0.1, "color": "black"}
+ return style
+
+ self.__drawContours(values, styleCallback)
+
+ self.__value.setValue(0)
+ self.__value.setRange(0, 5000)
+ self.__updateCustomContours(0)
+
+ def generateMagneticField(self):
+ shape = 512
+ x1 = numpy.random.random() * 2 - 1
+ y1 = numpy.random.random() * 2 - 1
+ x2 = numpy.random.random() * 2 - 1
+ y2 = numpy.random.random() * 2 - 1
+ image = create_magnetic_field(shape, x1, y1, x2, y2)
+ self.__colormap = Colormap("coolwarm")
+ self.setData(image=image, mask=None)
+
+ maximum = abs(image.max())
+ m = abs(image.min())
+ if m > maximum:
+ maximum = m
+ maximum = int(maximum)
+ values = range(-maximum, maximum, maximum // 20)
+
+ def styleCallback(value, ivalue, ipolygon):
+ if (ivalue % 2) == 0:
+ style = {"linestyle": "-", "linewidth": 0.5, "color": "black"}
+ else:
+ style = {"linestyle": "-", "linewidth": 0.5, "color": "white"}
+ return style
+
+ self.__drawContours(values, styleCallback)
+ self.__defineDefaultValues(value=0)
+
+ def generateGravityField(self):
+ shape = 512
+ nb = numpy.random.randint(2, 10)
+ objects = []
+ for _ in range(nb):
+ x = numpy.random.random() * 2 - 1
+ y = numpy.random.random() * 2 - 1
+ m = numpy.random.random() * 10 + 1.0
+ objects.append((x, y, m))
+ image = create_gravity_field(shape, objects)
+ self.__colormap = Colormap("inferno")
+ self.setData(image=image, mask=None)
+
+ delta = (image.max() - image.min()) / 30.0
+ values = numpy.arange(image.min(), image.max(), delta)
+
+ def styleCallback(value, ivalue, ipolygon):
+ return {"linestyle": "-", "linewidth": 0.1, "color": "white"}
+
+ self.__drawContours(values, styleCallback)
+ self.__defineDefaultValues()
+
+ def generateGradient(self):
+ shape = 512
+ dx = numpy.random.random() * 2 - 1
+ dy = numpy.random.random() * 2 - 1
+ sx = numpy.random.randint(10, 5000) / 10.0
+ sy = numpy.random.randint(10, 5000) / 10.0
+ image = create_gradient(shape, dx=dx, dy=dy, sx=sx, sy=sy)
+ image *= 1000.0
+
+ def styleCallback(value, ivalue, ipolygon):
+ colors = ["#9400D3", "#4B0082", "#0000FF", "#00FF00", "#FFFF00", "#FF7F00", "#FF0000"]
+ color = colors[ivalue % len(colors)]
+ style = {"linestyle": "-", "linewidth": 2.0, "color": color}
+ return style
+ delta = (image.max() - image.min()) / 9.0
+ values = numpy.arange(image.min(), image.max(), delta)
+ values = values[1:8]
+
+ self.__colormap = Colormap("Greys")
+ self.setData(image=image, mask=None)
+ self.__drawContours(values, styleCallback)
+ self.__defineDefaultValues()
+
+ def generateCompositeGradient(self):
+ shape = 512
+ hole = 1 / 4.0
+ dx = numpy.random.random() * hole - hole / 2.0
+ dy = numpy.random.random() * hole - hole * 2
+ sx = numpy.random.random() * 10.0 + 1
+ sy = numpy.random.random() * 10.0 + 1
+ image = create_composite_gradient(shape, dx, dy, sx, sy)
+ image *= 1000.0
+
+ def styleCallback(value, ivalue, ipolygon):
+ colors = ["#9400D3", "#4B0082", "#0000FF", "#00FF00", "#FFFF00", "#FF7F00", "#FF0000"]
+ color = colors[ivalue % len(colors)]
+ style = {"linestyle": "-", "linewidth": 2.0, "color": color}
+ return style
+ delta = (image.max() - image.min()) / 9.0
+ values = numpy.arange(image.min(), image.max(), delta)
+ values = values[1:8]
+
+ self.__colormap = Colormap("Greys")
+ self.setData(image=image, mask=None)
+ self.__drawContours(values, styleCallback)
+ self.__defineDefaultValues()
+
+
+def main():
+ app = qt.QApplication([])
+ sys.excepthook = qt.exceptionHandler
+ window = FindContours()
+ window.generateIsland()
+ window.show()
+ result = app.exec_()
+ # remove ending warnings relative to QTimer
+ app.deleteLater()
+ return result
+
+
+if __name__ == "__main__":
+ result = main()
+ sys.exit(result)