Beispiel #1
0
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
Beispiel #2
0
maputils.removeCruft(spmap, 7)
assert checkSaddles(spmap, img.spws.saddles(), flowlines)
checkPassValues(spmap, img.gm.siv)

# --------------------------------------------------------------------

import pixelmap
lab, count = labelImage4(spmap.labelImage())
cm = pixelmap.crackEdgeMap(lab)
assert cm.faceCount == count + 1

# --------------------------------------------------------------------

map = GeoMap(maxima1, [], Size2D(256, 256))
maputils.addFlowLinesToMap(flowlines1, map)
maputils.connectBorderNodes(map, 0.1)
map.sortEdgesEventually(stepDist=0.2, minDist=0.05)
map.initializeMap()
assert map.checkConsistency(), "map inconsistent"
assert maputils.checkLabelConsistency(map), "map.labelImage() inconsistent"

# showMapStats(map)
# bg = readImage("../../../Testimages/blox.gif")
# d = MapDisplay(bg, map)

labels = [
    map.faceAt(p).label()
    for p in [Vector2(91, 86.4),
              Vector2(91, 85.8),
              Vector2(91.4, 85.8)]
]
Beispiel #3
0
maputils.removeCruft(spmap, 7)
assert checkSaddles(spmap, img.spws.saddles(), flowlines)
checkPassValues(spmap, img.gm.siv)

# --------------------------------------------------------------------

import pixelmap
lab, count = labelImage4(spmap.labelImage())
cm = pixelmap.crackEdgeMap(lab)
assert cm.faceCount == count + 1

# --------------------------------------------------------------------

map = GeoMap(maxima1, [], Size2D(256, 256))
maputils.addFlowLinesToMap(flowlines1, map)
maputils.connectBorderNodes(map, 0.1)
map.sortEdgesEventually(stepDist = 0.2, minDist = 0.05)
map.initializeMap()
assert map.checkConsistency(), "map inconsistent"
assert maputils.checkLabelConsistency(map), "map.labelImage() inconsistent"

# showMapStats(map)
# bg = readImage("../../../Testimages/blox.gif")
# d = MapDisplay(bg, map)

labels = [map.faceAt(p).label() for p in
          [Vector2(91, 86.4), Vector2(91, 85.8), Vector2(91.4, 85.8)]]
assert len(dict.fromkeys(labels).keys()) == 3, \
       "those nearby positions point to three pairwise different faces"

# --------------------------------------------------------------------
Beispiel #4
0
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