Exemple #1
0
def correctorStep(siv, level, pos, epsilon=1e-8):
    """Perform corrector step, i.e. perform 1D iterative Newton method in
    direction of gradient in order to return to zero level (with
    accuracy given by epsilon)."""

    x, y = pos
    n = Vector2(siv.dx(x, y), siv.dy(x, y))
    n /= numpy.linalg.norm(n)

    for k in range(100):
        value = siv(x, y) - level
        if abs(value) < epsilon:
            break

        g = numpy.dot(Vector2(siv.dx(x, y), siv.dy(x, y)), n)
        if not g:
            sys.stderr.write("WARNING: correctorStep: zero gradient!\n")
            break  # FIXME: return None instead?
        correction = -value * n / g

        # prevent too large steps (i.e. if norm(g) is small):
        if correction.squaredMagnitude() > 0.25:
            correction /= 20 * numpy.linalg.norm(correction)

        x += correction[0]
        y += correction[1]

        if not siv.isInside(x, y):
            return None  # out of range

    return Vector2(x, y)
Exemple #2
0
 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)
Exemple #3
0
def followEdge(crackConnectionImage, pos, direction):
    """Follow edge starting at `pos` in `direction` until
    crackConnectionImage[pos] has the CONN_NODE bit set, or until we
    arrive at `pos` again (self-loop).  Any CONN_MAYBE_NODE bits along
    the way are cleared."""
    pos = Point2D(pos[0], pos[1])
    vPos = Vector2(pos[0] - 0.5, pos[1] - 0.5)
    result = Polygon([vPos])

    startPos = copy.copy(pos)
    while True:
        vPos += _dirVector[direction]
        result.append(vPos)
        pos += _dirOffset[direction]

        if pos == startPos:
            break

        connection = int(crackConnectionImage[pos])
        if connection & CONN_DIAG:
            if connection & CONN_DIAG_UPLEFT:
                turnLeft = direction in (DIR_NORTH, DIR_SOUTH)
            else:
                turnLeft = direction in (DIR_EAST, DIR_WEST)

            connection &= ~connections[(direction + 2) % 4]

            if turnLeft:
                direction = _turnLeft[direction]
            else:
                direction = _turnRight[direction]

            connection &= ~connections[direction]

            if not connection & CONN_ALL4:
                connection &= ~CONN_MAYBE_NODE

            crackConnectionImage[pos] = connection
            continue
        elif connection & CONN_NODE:
            break

        if connection & CONN_MAYBE_NODE:
            # we simply pass over it, but we do not want to start a
            # new edge here during further down in the process:
            crackConnectionImage[pos] = connection & ~CONN_MAYBE_NODE

        direction = _turnRight[direction]
        while connection & connections[direction] == 0:
            direction = _turnLeft[direction]

    return result, pos, connections[(direction + 2) % 4]
Exemple #4
0
def cannyEdgeMap(image, scale, thresh):
    """cannyEdgeMap(image, scale, thresh)

    Returns a subpixel-GeoMap object containing thinned canny edges
    obtained from cannyEdgeImage(image, scale, thresh).
    (Internally creates a pixel GeoMap first.)"""

    edgeImage = vigra.analysis.cannyEdgeImageWithThinning(
        image, scale, thresh, 1)
    pixelMap = cellimage.GeoMap(edgeImage, 0, cellimage.CellType.Line)
    spmap = pixelMap2subPixelMap(pixelMap,
                                 offset=Vector2(1, 1),
                                 imageSize=image.size())
    return spmap
Exemple #5
0
def followContour(siv, level, geomap, nodeLabel, h):
    correctorEpsilon = 1e-6
    nodeCrossingDist = 0.01

    #global pos, ip, poly, startNode, diff, npos, nip, intersection
    startNode = geomap.node(nodeLabel)
    pos = startNode.position()
    ix = int(pos[0])
    iy = int(pos[1])
    poly = [pos]
    while True:
        npos, nh = predictorCorrectorStep(siv, level, pos, h, correctorEpsilon)
        h = max(min(h, nh), 1e-5)
        nix = int(npos[0])
        niy = int(npos[1])
        if nix != ix or niy != iy:
            # determine grid intersection:
            diff = npos - pos
            if nix != ix:
                intersectionX = round(npos[0])
                intersectionY = pos[1] + (intersectionX -
                                          pos[0]) * diff[1] / diff[0]
            else:
                intersectionY = round(npos[1])
                intersectionX = pos[0] + (intersectionY -
                                          pos[1]) * diff[0] / diff[1]
            intersection = Vector2(intersectionX, intersectionY)

            # connect to crossed Node:
            endNode = geomap.nearestNode(intersection, nodeCrossingDist)
            if not endNode:
                sys.stderr.write(
                    "WARNING: level contour crossing grid at %s without intersection Node!\n"
                    % repr(intersection))
            elif endNode.label() != startNode.label() or len(poly) >= 3:
                # FIXME: better criterion than len(poly) would be poly.length()
                poly.append(endNode.position())
                geomap.addEdge(startNode, endNode, poly)
                if not endNode.degree() % 2:
                    return
                poly = [endNode.position()]
                startNode = endNode

            ix = nix
            iy = niy

        if nh is None:
            return  # out of image range (/no convergence)
        poly.append(npos)
        pos = npos
Exemple #6
0
def findZeroCrossingsOnGrid(siv, level, minDist=0.1):
    result = []
    existing = geomap.PositionedMap()
    minDist2 = minDist * minDist

    def addIntersection(p):
        if not existing(p, minDist2):
            result.append(p)
            existing.insert(p, True)

    for y in range(siv.height() - 1):
        for x in range(siv.width() - 1):
            coeff = siv.coefficients(x, y)

            xPoly = [coeff[k, 0] for k in range(coeff.width())]
            xPoly[0] -= level
            try:
                for k in vigra.polynomialRealRoots(xPoly):
                    if k < 0.0 or k >= 1.0:
                        continue
                    addIntersection(Vector2(x + k, y))
            except Exception, e:
                sys.stderr.write(
                    "WARNING: no convergence in polynomialRealRoots(%s):\n  %s\n"
                    % (xPoly, e))

            yPoly = [coeff[0, k] for k in range(coeff.height())]
            yPoly[0] -= level
            try:
                for k in vigra.polynomialRealRoots(yPoly):
                    if k < 0.0 or k >= 1.0:
                        continue
                    addIntersection(Vector2(x, y + k))
            except Exception, e:
                sys.stderr.write(
                    "WARNING: no convergence in polynomialRealRoots(%s):\n  %s\n"
                    % (yPoly, e))
Exemple #7
0
    for y in range(labelImage.height()):
        result[0, y] += CONN_DOWN
        result[labelImage.width(), y] += CONN_DOWN
        result[0, y + 1] += CONN_UP
        result[labelImage.width(), y + 1] += CONN_UP

    return result


DIR_EAST = 0
DIR_NORTH = 1
DIR_WEST = 2
DIR_SOUTH = 3
_dirOffset = [Size2D(1, 0), Size2D(0, -1), Size2D(-1, 0), Size2D(0, 1)]
_dirVector = [Vector2(1, 0), Vector2(0, -1), Vector2(-1, 0), Vector2(0, 1)]
_turnRight = [3, 0, 1, 2]
_turnLeft = [1, 2, 3, 0]
_debugDir = ("east", "north", "west", "south")


def followEdge(crackConnectionImage, pos, direction):
    """Follow edge starting at `pos` in `direction` until
    crackConnectionImage[pos] has the CONN_NODE bit set, or until we
    arrive at `pos` again (self-loop).  Any CONN_MAYBE_NODE bits along
    the way are cleared."""
    pos = Point2D(pos[0], pos[1])
    vPos = Vector2(pos[0] - 0.5, pos[1] - 0.5)
    result = Polygon([vPos])

    startPos = copy.copy(pos)
Exemple #8
0
def pixelMap2subPixelMap(pixelMap,
                         scale=1.0,
                         offset=Vector2(0, 0),
                         imageSize=None,
                         skipEverySecond=False,
                         midCracks=False):
    """Extract node positions and edge geometry from a
    cellimage.GeoMap object and returns a new subpixel-GeoMap object
    initialized with it.  For nodes, this function simply uses the
    center of their bounding box.  All positions are shifted by the
    optional offset and then scaled with the given factor.  The
    imageSize defaults to the (scaled) pixel-based pixelMap's
    cellImage.size().

    Set skipEverySecond to True if the pixelMap contains a crack edge
    map (otherwise, each resulting edge segment will have an
    additional mid crack point).  If you set midCracks to True, the
    edge geometry will include the midpoints of each crack instead of
    the endpoints (skipEverySecond is implied by/ignored if midCracks
    == True)."""

    if imageSize == None:
        imageSize = pixelMap.cellImage.size() * scale
    result = geomap.GeoMap(imageSize=imageSize)

    if midCracks:
        skipEverySecond = False

    nodes = [None] * (pixelMap.maxNodeLabel() + 1)
    for node in pixelMap.nodes:
        ul = node.bounds.upperLeft()
        center = Vector2(ul[0], ul[1]) + \
                 Vector2(node.bounds.width() - 1,
                         node.bounds.height() - 1) / 2
        nodes[node.label] = result.addNode((center + offset) * scale)

    # mark as sorted (sigma order will be copied from source map):
    result.sortEdgesDirectly()

    undesirable = []

    edges = [None] * (pixelMap.maxEdgeLabel() + 1)
    for edge in pixelMap.edges:
        it = iter(edge.start)
        startPos = it.nodePosition()
        points = list(it)
        if midCracks:
            points = points[::2]
        endPos = it.nodePosition()

        points.insert(0, startPos)
        points.append(endPos)

        if skipEverySecond:
            points = points[::2]

        points = [(Vector2(p[0], p[1]) + offset) * scale for p in points]

        startNeighbor = nodes[edge.start.startNodeLabel()]
        endNeighbor = nodes[edge.end.startNodeLabel()]

        if startNeighbor.position() != points[0]:
            points.insert(0, startNeighbor.position())
        if endNeighbor.position() != points[-1]:
            points.append(endNeighbor.position())

        # re-use sigma order from source map:
        if not startNeighbor.isIsolated():
            neighbor = cellimage.GeoMap.DartTraverser(edge.start)
            while neighbor.nextSigma().edgeLabel() >= edge.label:
                pass
            startNeighbor = edges[neighbor.edgeLabel()].dart()
            if neighbor == neighbor.edge().end:
                startNeighbor.nextAlpha()

        if not endNeighbor.isIsolated():
            neighbor = cellimage.GeoMap.DartTraverser(edge.end)
            while neighbor.nextSigma().edgeLabel() >= edge.label:
                pass
            endNeighbor = edges[neighbor.edgeLabel()].dart()
            if neighbor == neighbor.edge().end:
                endNeighbor.nextAlpha()

        newEdge = result.addEdge(startNeighbor, endNeighbor, points)
        edges[edge.label] = newEdge

        if newEdge.isLoop() and newEdge.partialArea() == 0.0:
            undesirable.append(newEdge.dart())

    for dart in undesirable:
        result.removeEdge(dart)

    result.initializeMap()

    # the border closing was done in C++, so we have to mark the
    # border edges manually:
    assert result.face(0).holeCount() == 1
    for dart in result.face(0).holeContours().next().phiOrbit():
        assert not dart.leftFaceLabel()
        dart.edge().setFlag(BORDER_PROTECTION)

    return result
Exemple #9
0
def samplingPoints(img, threshold=128):
    return [
        Vector2(pos[0], pos[1]) for pos in img.size() if img[pos] < threshold
    ]
Exemple #10
0
def tangentDir(siv, pos):
    result = Vector2(-siv.dy(pos[0], pos[1]), siv.dx(pos[0], pos[1]))
    return result / numpy.linalg.norm(result)
Exemple #11
0
 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)