def levelSetMap(image, level = 0, sigma = None): siv = hasattr(image, "siv") and image.siv or vigra.SplineImageView3(image) zc = findZeroCrossingsOnGrid(siv, level) result = geomap.GeoMap(zc, [], image.size()) msg = progress.StatusMessage("- following level set contours") next = progress.ProgressHook(msg).rangeTicker(result.nodeCount) for node in result.nodeIter(): next() if node.isIsolated(): followContour(siv, level, result, node.label(), 0.1) maputils.mergeDegree2Nodes(result) result = maputils.copyMapContents( # compress labels and simplify polygons result, edgeTransform = lambda e: \ geomap.simplifyPolygon(e, 0.05, 0.2))[0] #maputils.connectBorderNodes(result, 0.01) result.sortEdgesEventually(0.4, 0.01) result.initializeMap() return result
def levelSetMap(image, level=0, sigma=None): siv = hasattr(image, "siv") and image.siv or vigra.SplineImageView3(image) zc = findZeroCrossingsOnGrid(siv, level) result = geomap.GeoMap(zc, [], image.size()) msg = progress.StatusMessage("- following level set contours") next = progress.ProgressHook(msg).rangeTicker(result.nodeCount) for node in result.nodeIter(): next() if node.isIsolated(): followContour(siv, level, result, node.label(), 0.1) maputils.mergeDegree2Nodes(result) result = maputils.copyMapContents( # compress labels and simplify polygons result, edgeTransform = lambda e: \ geomap.simplifyPolygon(e, 0.05, 0.2))[0] #maputils.connectBorderNodes(result, 0.01) result.sortEdgesEventually(0.4, 0.01) result.initializeMap() return result
def marchingSquares(image, level = 0, variant = True, border = True, initialize = True, markOuter = 1): """Return a new GeoMap with sub-pixel level contours extracted by the marching squares method. (Pixels with values < level are separated from pixels >= level.) If the image does not have an attribute 'siv', standard linear interpolation is used. If image.siv exists, it should be a SplineImageView that is used for the Newton-Raphson method to perform another subsequent sub-pixel correction. The optional parameter `variant` determines the handling of the ambiguous diagonal configuration: `variant` = True (default) always let the two sampling points above `level` be connected `variant` = False always let the two opposite sampling points < `level` be connected `variant` = SplineImageView(...) for each ambiguous configuration, check the midpoint of the square; then handle as if variant = (midpoint >= level) If `initialize` is a true value (default), the map will be initialized. If markOuter is != 0, the faces above(outer == 1) / below(outer == -1) the threshold are marked with the OUTER_FACE flag (this only works if the map is initialized).""" connections1 = ((1, 0), (0, 2), (1, 2), (3, 1), (3, 0), (0, 2), (3, 1), (3, 2), (2, 3), (1, 0), (2, 3), (0, 3), (1, 3), (2, 1), (2, 0), (0, 1)) connections2 = ((1, 0), (0, 2), (1, 2), (3, 1), (3, 0), (0, 1), (3, 2), (3, 2), (2, 3), (1, 3), (2, 0), (0, 3), (1, 3), (2, 1), (2, 0), (0, 1)) configurations = (0, 0, 1, 2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 16) result = geomap.GeoMap(image.shape) def addNodeDirectX(x, y, ofs): pos = Vector2(x+ofs, y) # out of three successive pixels, the middle one may be the # threshold, then we would get duplicate points already in the # horizontal pass: node = result.nearestNode(pos, 1e-8) return node or result.addNode(pos) def addNodeDirectY(x, y, ofs): pos = Vector2(x, y+ofs) node = result.nearestNode(pos, 1e-8) # already exists? (e.g. hNodes?) return node or result.addNode(pos) def addNodeNewtonRefinementX(x, y, ofs): for i in range(100): o = -(image.siv(x+ofs, y)-level) / image.siv.dx(x+ofs, y) if abs(o) > 0.5: o = vigra.sign(o)*0.05 ofs += o if ofs <= 0 or ofs >= 1: ofs -= o break if abs(o) < 1e-4: break return addNodeDirectX(x, y, ofs) def addNodeNewtonRefinementY(x, y, ofs): for i in range(100): o = -(image.siv(x, y+ofs)-level) / image.siv.dy(x, y+ofs) if abs(o) > 0.5: o = vigra.sign(o)*0.05 ofs += o if ofs <= 0 or ofs >= 1: ofs -= o break if abs(o) < 1e-4: break return addNodeDirectY(y, y, ofs) if hasattr(image, "siv"): addNodeX = addNodeNewtonRefinementX addNodeY = addNodeNewtonRefinementY else: addNodeX = addNodeDirectX addNodeY = addNodeDirectY hNodes = vigra.Image(image.shape, numpy.uint32) v1 = image[:-1] v2 = image[1:] ofs = (level - v1)/(v2 - v1) for x, y in numpy.transpose(numpy.nonzero((v1 < level) != (v2 < level))): hNodes[x, y] = addNodeX(x, y, ofs).label() vNodes = vigra.Image(image.shape, numpy.uint32) v1 = image[:,:-1] v2 = image[:,1:] ofs = (level - v1)/(v2 - v1) for x, y in numpy.transpose(numpy.nonzero((v1 < level) != (v2 < level))): vNodes[x, y] = addNodeY(x, y, ofs).label() nodes = (hNodes, vNodes, vNodes, hNodes) offsets = numpy.array(((0, 0), (0, 0), (1, 0), (0, 1))) defaultConnections = connections1 if variant == False: defaultConnections = connections2 if isinstance(variant, bool): variant = None configurations = ((image[:-1,:-1] < level) + (image[ 1:,:-1] < level)*2 + (image[:-1, 1:] < level)*4 + (image[ 1:, 1:] < level)*8) for x, y in numpy.transpose(numpy.nonzero(configurations)): config = configurations[x,y] connections = connections1 if variant is not None and config in (6, 9): if variant(x + 0.5, y + 0.5) < level: connections = connections2 for s, e in connections[ configurations[config]:configurations[config+1]]: startNode = result.node(int(nodes[s][tuple(offsets[s] + (x, y))])) endNode = result.node(int(nodes[e][tuple(offsets[e] + (x, y))])) if startNode != endNode: result.addEdge(startNode, endNode, [startNode.position(), endNode.position()]) maputils.mergeDegree2Nodes(result) # node suppression result = maputils.copyMapContents(result)[0] # compress edge labels if border: maputils.connectBorderNodes(result, 0.5) result.sortEdgesEventually(0.4, 0.01) if not initialize: return result result.initializeMap() if markOuter: markOuter = markOuter > 0 it = result.faceIter() if border: it.next().setFlag(flag_constants.OUTER_FACE) for face in it: face.setFlag(flag_constants.OUTER_FACE, (face.contours().next().label() < 0) == markOuter) return result
def marchingSquares(image, level=0, variant=True, border=True, initialize=True, markOuter=1): """Return a new GeoMap with sub-pixel level contours extracted by the marching squares method. (Pixels with values < level are separated from pixels >= level.) If the image does not have an attribute 'siv', standard linear interpolation is used. If image.siv exists, it should be a SplineImageView that is used for the Newton-Raphson method to perform another subsequent sub-pixel correction. The optional parameter `variant` determines the handling of the ambiguous diagonal configuration: `variant` = True (default) always let the two sampling points above `level` be connected `variant` = False always let the two opposite sampling points < `level` be connected `variant` = SplineImageView(...) for each ambiguous configuration, check the midpoint of the square; then handle as if variant = (midpoint >= level) If `initialize` is a true value (default), the map will be initialized. If markOuter is != 0, the faces above(outer == 1) / below(outer == -1) the threshold are marked with the OUTER_FACE flag (this only works if the map is initialized).""" connections1 = ((1, 0), (0, 2), (1, 2), (3, 1), (3, 0), (0, 2), (3, 1), (3, 2), (2, 3), (1, 0), (2, 3), (0, 3), (1, 3), (2, 1), (2, 0), (0, 1)) connections2 = ((1, 0), (0, 2), (1, 2), (3, 1), (3, 0), (0, 1), (3, 2), (3, 2), (2, 3), (1, 3), (2, 0), (0, 3), (1, 3), (2, 1), (2, 0), (0, 1)) configurations = (0, 0, 1, 2, 3, 4, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16, 16) result = geomap.GeoMap(image.shape) def addNodeDirectX(x, y, ofs): pos = Vector2(x + ofs, y) # out of three successive pixels, the middle one may be the # threshold, then we would get duplicate points already in the # horizontal pass: node = result.nearestNode(pos, 1e-8) return node or result.addNode(pos) def addNodeDirectY(x, y, ofs): pos = Vector2(x, y + ofs) node = result.nearestNode(pos, 1e-8) # already exists? (e.g. hNodes?) return node or result.addNode(pos) def addNodeNewtonRefinementX(x, y, ofs): for i in range(100): o = -(image.siv(x + ofs, y) - level) / image.siv.dx(x + ofs, y) if abs(o) > 0.5: o = vigra.sign(o) * 0.05 ofs += o if ofs <= 0 or ofs >= 1: ofs -= o break if abs(o) < 1e-4: break return addNodeDirectX(x, y, ofs) def addNodeNewtonRefinementY(x, y, ofs): for i in range(100): o = -(image.siv(x, y + ofs) - level) / image.siv.dy(x, y + ofs) if abs(o) > 0.5: o = vigra.sign(o) * 0.05 ofs += o if ofs <= 0 or ofs >= 1: ofs -= o break if abs(o) < 1e-4: break return addNodeDirectY(y, y, ofs) if hasattr(image, "siv"): addNodeX = addNodeNewtonRefinementX addNodeY = addNodeNewtonRefinementY else: addNodeX = addNodeDirectX addNodeY = addNodeDirectY hNodes = vigra.Image(image.shape, numpy.uint32) v1 = image[:-1] v2 = image[1:] ofs = (level - v1) / (v2 - v1) for x, y in numpy.transpose(numpy.nonzero((v1 < level) != (v2 < level))): hNodes[x, y] = addNodeX(x, y, ofs).label() vNodes = vigra.Image(image.shape, numpy.uint32) v1 = image[:, :-1] v2 = image[:, 1:] ofs = (level - v1) / (v2 - v1) for x, y in numpy.transpose(numpy.nonzero((v1 < level) != (v2 < level))): vNodes[x, y] = addNodeY(x, y, ofs).label() nodes = (hNodes, vNodes, vNodes, hNodes) offsets = numpy.array(((0, 0), (0, 0), (1, 0), (0, 1))) defaultConnections = connections1 if variant == False: defaultConnections = connections2 if isinstance(variant, bool): variant = None configurations = ((image[:-1, :-1] < level) + (image[1:, :-1] < level) * 2 + (image[:-1, 1:] < level) * 4 + (image[1:, 1:] < level) * 8) for x, y in numpy.transpose(numpy.nonzero(configurations)): config = configurations[x, y] connections = connections1 if variant is not None and config in (6, 9): if variant(x + 0.5, y + 0.5) < level: connections = connections2 for s, e in connections[configurations[config]:configurations[config + 1]]: startNode = result.node(int(nodes[s][tuple(offsets[s] + (x, y))])) endNode = result.node(int(nodes[e][tuple(offsets[e] + (x, y))])) if startNode != endNode: result.addEdge(startNode, endNode, [startNode.position(), endNode.position()]) maputils.mergeDegree2Nodes(result) # node suppression result = maputils.copyMapContents(result)[0] # compress edge labels if border: maputils.connectBorderNodes(result, 0.5) result.sortEdgesEventually(0.4, 0.01) if not initialize: return result result.initializeMap() if markOuter: markOuter = markOuter > 0 it = result.faceIter() if border: it.next().setFlag(flag_constants.OUTER_FACE) for face in it: face.setFlag(flag_constants.OUTER_FACE, (face.contours().next().label() < 0) == markOuter) return result