Exemple #1
0
    def angle(self):
        """angle() -> theta

           Returns the orientation of the pixels"""
        xs = ys = tot = 0
        # multiplication counters
        xx = yy = xy = 0
        for x in range(self._mask.w):
            for y in range(self._mask.h):
                if sdl.bitmask_getbit(self._mask, x, y):
                    ys += y
                    xs += x
                    tot += 1
                    xx += x * x
                    yy += y * y
                    xy += x * y
        if tot:
            xc = xs // tot
            yc = ys // tot
            theta = atan2(2 * (xy / tot - xc * yc),
                          (xx / tot - xc * xc) - (yy / tot - yc * yc))
            # covert from radians
            # We copy this logic from pygame upstream, because reasons
            theta = -90.0 * theta / pi
            return theta
        return 0.0
Exemple #2
0
    def angle(self):
        """angle() -> theta

           Returns the orientation of the pixels"""
        xs = ys = tot = 0
        # multiplication counters
        xx = yy = xy = 0
        for x in range(self._mask.w):
            for y in range(self._mask.h):
                if sdl.bitmask_getbit(self._mask, x, y):
                    ys += y
                    xs += x
                    tot += 1
                    xx += x * x
                    yy += y * y
                    xy += x * y
        if tot:
            xc = xs // tot
            yc = ys // tot
            theta = math.atan2(2 * (xy / tot - xc * yc),
                               (xx / tot - xc * xc) - (yy / tot - yc * yc))
            # covert from radians
            # We copy this logic from pygame upstream, because reasons
            theta = -90.0 * theta / math.pi
            return theta
        return 0.0
Exemple #3
0
    def get_at(self, pos):
        """get_at((x,y)) -> int

           Returns nonzero if the bit at (x,y) is set."""
        x, y = pos
        if 0 <= x < self._mask.w and 0 <= y < self._mask.h:
            val = sdl.bitmask_getbit(self._mask, x, y)
        else:
            raise IndexError("%d, %d out of bounds" % pos)
        return val
Exemple #4
0
    def get_at(self, pos):
        """get_at((x,y)) -> int

           Returns nonzero if the bit at (x,y) is set."""
        x, y = pos
        if 0 <= x < self._mask.w and 0 <= y < self._mask.h:
            val = sdl.bitmask_getbit(self._mask, x, y)
        else:
            raise IndexError("%d, %d out of bounds" % pos)
        return val
Exemple #5
0
    def centroid(self):
        """centroid() -> (x, y)

           Returns the centroid of the pixels in a Mask"""
        xs = ys = tot = 0
        for x in range(self._mask.w):
            for y in range(self._mask.h):
                if sdl.bitmask_getbit(self._mask, x, y):
                    ys += y
                    xs += x
                    tot += 1
        if tot:
            return (xs // tot, ys // tot)
        return (0, 0)
Exemple #6
0
    def centroid(self):
        """centroid() -> (x, y)

           Returns the centroid of the pixels in a Mask"""
        xs = ys = tot = 0
        for x in range(self._mask.w):
            for y in range(self._mask.h):
                if sdl.bitmask_getbit(self._mask, x, y):
                    ys += y
                    xs += x
                    tot += 1
        if tot:
            return (xs // tot, ys // tot)
        return (0, 0)
Exemple #7
0
    def connected_component(self, pos=None):
        """connected_component((x,y) = None) -> Mask

            Returns a mask of a connected region of pixels."""
        output = Mask((self._mask.w, self._mask.h))
        # if a coordinate is specified, make sure the pixel there is
        # actually set
        x = y = -1
        check = True
        if pos:
            x, y = pos
            if not sdl.bitmask_getbit(self._mask, x, y):
                check = False
        if check:
            r = sdl.largest_connected_comp(self._mask, output._mask, x, y)
            # largest_connected_comp returns -2 on memory errors, 0 otherwise
            if r == -2:
                raise MemoryError("Not enough memory to get largest component")
        return output
Exemple #8
0
    def connected_component(self, pos=None):
        """connected_component((x,y) = None) -> Mask

            Returns a mask of a connected region of pixels."""
        output = Mask((self._mask.w, self._mask.h))
        # if a coordinate is specified, make sure the pixel there is
        # actually set
        x = y = -1
        check = True
        if pos:
            x, y = pos
            if not sdl.bitmask_getbit(self._mask, x, y):
                check = False
        if check:
            r = sdl.largest_connected_comp(self._mask, output._mask, x, y)
            # largest_connected_comp returns -2 on memory errors, 0 otherwise
            if r == -2:
                raise MemoryError("Not enough memory to get largest component")
        return output
Exemple #9
0
    def outline(self, every=1):
        """outline(every = 1) -> [(x,y), (x,y) ...]

           list of points outlining an object"""
        # Find the first set pixel in the mask
        points = []
        start_point = None
        for y in range(self._mask.h):
            for x in range(self._mask.w):
                if sdl.bitmask_getbit(self._mask, x, y):
                    # We add 1 because of later padding trick
                    start_point = x + 1, y + 1
                    points.append((x, y))
                    break
            if points:
                break
        # If not pixels, break out
        if not points:
            return points
        # Check for corner case around only last pixel being set
        if start_point == (self._mask.w, self._mask.h):
            return points
        # We create a larger mask, to avoid checking edges for every pixel
        trace = Mask((self._mask.w + 2, self._mask.h + 2))
        sdl.bitmask_draw(trace._mask, self._mask, 1, 1)

        # This walks around a pixel clockwise.
        # We have doubled this for the logic later
        offsets = [(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1),
                   (1, -1)] * 2
        curr = second = None
        pos = 0
        # We check just the first point for neighbours
        for p, off in enumerate(offsets[:8]):
            cand = (start_point[0] + off[0], start_point[1] + off[1])
            if sdl.bitmask_getbit(trace._mask, cand[0], cand[1]):
                curr = second = cand
                # Scale back to our mask
                points.append((second[0] - 1, second[1] - 1))
                # Set appropriate start point for next loop
                pos = p + 5
                break
        if not second:
            # No neighbours
            return points

        # Trace the outline
        next_point = curr
        while True:
            for p, off in enumerate(offsets[pos:pos + 8]):
                cand = (curr[0] + off[0], curr[1] + off[1])
                if sdl.bitmask_getbit(trace._mask, cand[0], cand[1]):
                    # The logic here is a little hairy, but we must
                    # make sure we test all other neighbors before we
                    # test going from next_point back to curr_point
                    # For example, if we found next_point using (1, 1)
                    # we need to test (-1, -1) last when checking next_point.
                    pos = (pos + p + 5) % 8
                    next_point = cand
                    if curr != start_point or next_point != second:
                        # Not yet back at the start
                        points.append((next_point[0] - 1, next_point[1] - 1))
                    break
            if curr == start_point and next_point == second:
                # About to repeat ourselves, so we're done
                break
            curr = next_point

        # Return asked for subset of points
        return points[::every]
Exemple #10
0
    def outline(self, every=1):
        """outline(every = 1) -> [(x,y), (x,y) ...]

           list of points outlining an object"""
        # Find the first set pixel in the mask
        points = []
        start_point = None
        for y in range(self._mask.h):
            for x in range(self._mask.w):
                if sdl.bitmask_getbit(self._mask, x, y):
                    # We add 1 because of later padding trick
                    start_point = x + 1, y + 1
                    points.append((x, y))
                    break
            if points:
                break
        # If not pixels, break out
        if not points:
            return points
        # Check for corner case around only last pixel being set
        if start_point == (self._mask.w, self._mask.h):
            return points
        # We create a larger mask, to avoid checking edges for every pixel
        trace = Mask((self._mask.w + 2, self._mask.h + 2))
        sdl.bitmask_draw(trace._mask, self._mask, 1, 1)

        # This walks around a pixel clockwise.
        # We have doubled this for the logic later
        offsets = [(1, 0), (1, 1), (0, 1), (-1, 1),
                   (-1, 0), (-1, -1), (0, -1), (1, -1)] * 2
        curr = second = None
        pos = 0
        # We check just the first point for neighbours
        for p, off in enumerate(offsets[:8]):
            cand = (start_point[0] + off[0], start_point[1] + off[1])
            if sdl.bitmask_getbit(trace._mask, cand[0], cand[1]):
                curr = second = cand
                # Scale back to our mask
                points.append((second[0] - 1, second[1] - 1))
                # Set appropriate start point for next loop
                pos = p + 5
                break
        if not second:
            # No neighbours
            return points

        # Trace the outline
        next_point = curr
        while True:
            for p, off in enumerate(offsets[pos:pos + 8]):
                cand = (curr[0] + off[0], curr[1] + off[1])
                if sdl.bitmask_getbit(trace._mask, cand[0], cand[1]):
                    # The logic here is a little hairy, but we must
                    # make sure we test all other neighbors before we
                    # test going from next_point back to curr_point
                    # For example, if we found next_point using (1, 1)
                    # we need to test (-1, -1) last when checking next_point.
                    pos = (pos + p + 5) % 8
                    next_point = cand
                    if curr != start_point or next_point != second:
                        # Not yet back at the start
                        points.append((next_point[0] - 1, next_point[1] - 1))
                    break
            if curr == start_point and next_point == second:
                # About to repeat ourselves, so we're done
                break
            curr = next_point

        # Return asked for subset of points
        return points[::every]