Example #1
0
def draw_props(properties):
    global img, img_src

    img = img_src.copy()

    for props in properties:
        if props['Ellipse'] != None:
            cv2.circle(img, props['Centroid'], 5, BLUE, 1)
            cv2.ellipse(img, props['Ellipse'], CYAN)
            cv2.drawContours(img, [props['ConvexHull']], 0, RED, 1)

            major_axis = ft.angled_line(props['Centroid'], props['Orientation'], props['MajorAxisLength']/2)
            cv2.line(img, tuple(major_axis[0]), tuple(major_axis[1]), RED)

            minor_axis = ft.angled_line(props['Centroid'], props['Orientation'] + 90, props['MinorAxisLength']/2)
            cv2.line(img, tuple(minor_axis[0]), tuple(minor_axis[1]), BLUE)

        box = cv2.cv.BoxPoints(props['BoundingBox'])
        box = np.int0(box)
        cv2.drawContours(img, [box], 0, CYAN, 1)

        for p in props['Extrema']:
            cv2.circle(img, p, 5, CYAN, 1)

    cv2.imshow('image', img)
Example #2
0
def draw_angle_shape(angle):
    global rotation, img, center, intersects

    # Draw the angle.
    line = ft.extreme_points(intersects[angle] + intersects[angle + 180])
    if line == None:
        line = ft.angled_line(center, angle + rotation, 100)
    cv2.line(img, tuple(line[0]), tuple(line[1]), GREEN)

    # Draw main intersections.
    for x, y in intersects[angle]:
        cv2.circle(img, (x, y), 5, RED)
    for x, y in intersects[angle + 180]:
        cv2.circle(img, (x, y), 5, BLUE)

    cv2.imshow('image', img)
Example #3
0
def draw_angle_shape(angle):
    global rotation, img, center, intersects

    # Draw the angle.
    line = ft.extreme_points(intersects[angle] + intersects[angle + 180])
    if line == None:
        line = ft.angled_line(center, angle + rotation, 100)
    cv2.line(img, tuple(line[0]), tuple(line[1]), GREEN)

    # Draw main intersections.
    for x, y in intersects[angle]:
        cv2.circle(img, (x, y), 5, RED)
    for x, y in intersects[angle + 180]:
        cv2.circle(img, (x, y), 5, BLUE)

    cv2.imshow("image", img)
Example #4
0
def shape_360_v1(contour, rotation=0, step=1, t=8):
    """Returns a shape feature from a contour.

    The rotation in degrees of the contour can be set with `rotation`, which
    must be a value between 0 and 179 inclusive. A rotation above 90 degrees
    is interpreted as a rotation to the left (e.g. a rotation of 120 is
    interpreted as 60 degrees to the left). The returned shape is shifted by
    the rotation. The step size for the angle can be set with `step`. Argument
    `t` is passed to :meth:`weighted_points_nearest`. The returned shape is
    rotation invariant provided that the rotation argument is set properly and
    the rotation is no more than 90 degrees left or right.

    Shape is returned as a tuple ``(intersects, center)``, where ``intersects``
    is a dict where the keys are 0 based angles and the values are lists
    of intersecting points. If `step` is set to 1, then the dict will contain
    the intersections for 360 degrees. ``center`` specifies the center of the
    contour and can be used to calculate distances from center to contour.
    """
    if len(contour) < 6:
        raise ValueError("Contour must have at least 6 points, found %d" % len(contour))
    if not 0 <= rotation <= 179:
        raise ValueError("The rotation must be between 0 and 179 inclusive, found %d" % rotation)

    # Get the center.
    center, _ = cv2.minEnclosingCircle(contour)
    center = np.int32(center)

    # If the rotation is more than 90 degrees, assume the object is rotated to
    # the left.
    if rotation <= 90:
        a = 0
        b = 180
    else:
        a = 180
        b = 0

    # Get the intersecting points with the contour for every degree
    # from the symmetry axis.
    intersects = {}
    for angle in range(0, 180, step):
        # Get the slope for the linear function of this angle and account for
        # the rotation of the object.
        slope = ft.slope_from_angle(angle + rotation, inverse=True)

        # Since pixel points can only be defined with natural numbers,
        # resulting in gaps in between two points, means the maximum
        # gap is equal to the slope of the linear function.
        gap_max = math.ceil(abs(slope))

        # Find al contour points that closely fit the angle's linear function.
        # Only save points for which the distance to the expected point is
        # no more than the maximum gap. Save each point with a weight value,
        # which is used for clustering.
        weighted_points = []
        for p in contour:
            p = p[0]
            x = p[0] - center[0]
            y = p[1] - center[1]
            if math.isinf(slope):
                if x == 0:
                    # Save points that are on the vertical axis.
                    weighted_points.append( (1, tuple(p)) )
            else:
                y_exp = slope * x
                d = abs(y - y_exp)
                if d <= gap_max:
                    w = 1 / (d+1)
                    weighted_points.append( (w, tuple(p)) )

        assert len(weighted_points) != 0, "No intersections found"

        # Cluster the points.
        weighted_points = ft.weighted_points_nearest(weighted_points, t)
        _, points = zip(*weighted_points)

        # Figure out on which side of the symmetry the points lie.
        # Create a line that separates points on the left from points on
        # the right.
        if (angle + rotation) != 0:
            division_line = ft.angled_line(center, angle + rotation + 90, 100)
        else:
            # Points cannot be separated when the division line is horizontal.
            # So make a division line that is rotated 45 degrees to the left
            # instead, so that the points are properly separated.
            division_line = ft.angled_line(center, angle + rotation - 45, 100)

        intersects[angle] = []
        intersects[angle+180] = []
        for p in points:
            side = ft.side_of_line(division_line, p)
            if side < 0:
                intersects[angle+a].append(p)
            elif side > 0:
                intersects[angle+b].append(p)
            else:
                assert side != 0, "A point cannot be on the division line"

    return (intersects, center)
Example #5
0
def shape_360_v1(contour, rotation=0, step=1, t=8):
    """Returns a shape feature from a contour.

    The rotation in degrees of the contour can be set with `rotation`, which
    must be a value between 0 and 179 inclusive. A rotation above 90 degrees
    is interpreted as a rotation to the left (e.g. a rotation of 120 is
    interpreted as 60 degrees to the left). The returned shape is shifted by
    the rotation. The step size for the angle can be set with `step`. Argument
    `t` is passed to :meth:`weighted_points_nearest`. The returned shape is
    rotation invariant provided that the rotation argument is set properly and
    the rotation is no more than 90 degrees left or right.

    Shape is returned as a tuple ``(intersects, center)``, where ``intersects``
    is a dict where the keys are 0 based angles and the values are lists
    of intersecting points. If `step` is set to 1, then the dict will contain
    the intersections for 360 degrees. ``center`` specifies the center of the
    contour and can be used to calculate distances from center to contour.
    """
    if len(contour) < 6:
        raise ValueError("Contour must have at least 6 points, found %d" %
                         len(contour))
    if not 0 <= rotation <= 179:
        raise ValueError(
            "The rotation must be between 0 and 179 inclusive, found %d" %
            rotation)

    # Get the center.
    center, _ = cv2.minEnclosingCircle(contour)
    center = np.int32(center)

    # If the rotation is more than 90 degrees, assume the object is rotated to
    # the left.
    if rotation <= 90:
        a = 0
        b = 180
    else:
        a = 180
        b = 0

    # Get the intersecting points with the contour for every degree
    # from the symmetry axis.
    intersects = {}
    for angle in range(0, 180, step):
        # Get the slope for the linear function of this angle and account for
        # the rotation of the object.
        slope = ft.slope_from_angle(angle + rotation, inverse=True)

        # Since pixel points can only be defined with natural numbers,
        # resulting in gaps in between two points, means the maximum
        # gap is equal to the slope of the linear function.
        gap_max = math.ceil(abs(slope))

        # Find al contour points that closely fit the angle's linear function.
        # Only save points for which the distance to the expected point is
        # no more than the maximum gap. Save each point with a weight value,
        # which is used for clustering.
        weighted_points = []
        for p in contour:
            p = p[0]
            x = p[0] - center[0]
            y = p[1] - center[1]
            if math.isinf(slope):
                if x == 0:
                    # Save points that are on the vertical axis.
                    weighted_points.append((1, tuple(p)))
            else:
                y_exp = slope * x
                d = abs(y - y_exp)
                if d <= gap_max:
                    w = 1 / (d + 1)
                    weighted_points.append((w, tuple(p)))

        assert len(weighted_points) != 0, "No intersections found"

        # Cluster the points.
        weighted_points = ft.weighted_points_nearest(weighted_points, t)
        _, points = zip(*weighted_points)

        # Figure out on which side of the symmetry the points lie.
        # Create a line that separates points on the left from points on
        # the right.
        if (angle + rotation) != 0:
            division_line = ft.angled_line(center, angle + rotation + 90, 100)
        else:
            # Points cannot be separated when the division line is horizontal.
            # So make a division line that is rotated 45 degrees to the left
            # instead, so that the points are properly separated.
            division_line = ft.angled_line(center, angle + rotation - 45, 100)

        intersects[angle] = []
        intersects[angle + 180] = []
        for p in points:
            side = ft.side_of_line(division_line, p)
            if side < 0:
                intersects[angle + a].append(p)
            elif side > 0:
                intersects[angle + b].append(p)
            else:
                assert side != 0, "A point cannot be on the division line"

    return (intersects, center)