Skip to content

single

Generates Features for things that aren't like their neighbors

Single

Bases: FeatureExtractor[Point]

A component for identifying single, isolated visual features

Source code in roc/feature_extractors/single.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
@register_component("single", "perception")
class Single(FeatureExtractor[Point]):
    """A component for identifying single, isolated visual features"""

    def event_filter(self, e: PerceptionEvent) -> bool:
        """Filters out non-VisionData

        Args:
            e (PerceptionEvent): Any event on the perception bus

        Returns:
            bool: Returns True if the event is VisionData to keep processing it,
            False otherwise.
        """
        return isinstance(e.data, VisionData)

    def get_feature(self, e: PerceptionEvent) -> None:
        """Emits the shape features.

        Args:
            e (PerceptionEvent): The VisionData

        Returns:
            Feature | None: None
        """
        vd = e.data
        assert isinstance(vd, VisionData)
        data = IntGrid(vd.glyphs)

        ## iterate points
        for x, y, v in data:
            point = Point(x, y, v)
            if is_unique_from_neighbors(data, point):
                self.pb_conn.send(
                    SingleFeature(
                        origin_id=self.id,
                        point=(x, y),
                        type=v,
                    )
                )
        self.settled()

event_filter(e)

Filters out non-VisionData

Parameters:

Name Type Description Default
e PerceptionEvent

Any event on the perception bus

required

Returns:

Name Type Description
bool bool

Returns True if the event is VisionData to keep processing it,

bool

False otherwise.

Source code in roc/feature_extractors/single.py
41
42
43
44
45
46
47
48
49
50
51
def event_filter(self, e: PerceptionEvent) -> bool:
    """Filters out non-VisionData

    Args:
        e (PerceptionEvent): Any event on the perception bus

    Returns:
        bool: Returns True if the event is VisionData to keep processing it,
        False otherwise.
    """
    return isinstance(e.data, VisionData)

get_feature(e)

Emits the shape features.

Parameters:

Name Type Description Default
e PerceptionEvent

The VisionData

required

Returns:

Type Description
None

Feature | None: None

Source code in roc/feature_extractors/single.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def get_feature(self, e: PerceptionEvent) -> None:
    """Emits the shape features.

    Args:
        e (PerceptionEvent): The VisionData

    Returns:
        Feature | None: None
    """
    vd = e.data
    assert isinstance(vd, VisionData)
    data = IntGrid(vd.glyphs)

    ## iterate points
    for x, y, v in data:
        point = Point(x, y, v)
        if is_unique_from_neighbors(data, point):
            self.pb_conn.send(
                SingleFeature(
                    origin_id=self.id,
                    point=(x, y),
                    type=v,
                )
            )
    self.settled()

SingleFeature dataclass

Bases: PointFeature[SingleNode]

A single isolated feature with no similar features around it.

Source code in roc/feature_extractors/single.py
24
25
26
27
28
29
30
31
32
33
34
@dataclass(kw_only=True)
class SingleFeature(PointFeature[SingleNode]):
    """A single isolated feature with no similar features around it."""

    feature_name: str = "Single"

    def _create_nodes(self) -> SingleNode:
        return SingleNode(type=self.type)

    def _dbfetch_nodes(self) -> SingleNode | None:
        return SingleNode.find_one("src.type = $type", params={"type": self.type})

feature_name = 'Single' class-attribute instance-attribute

__init__(*, feature_name='Single')

SingleNode

Bases: FeatureNode

Source code in roc/feature_extractors/single.py
16
17
18
19
20
21
class SingleNode(FeatureNode):
    type: int

    @property
    def attr_strs(self) -> list[str]:
        return [str(self.type)]

attr_strs property

type instance-attribute

is_unique_from_neighbors(data, point)

Helper function to determine if a point in a matrix has the same value as any points around it.

Parameters:

Name Type Description Default
data VisionData

The matrix / Grid to evaluate

required
point Point

The point to see if any of its neighbors have the same value

required

Returns:

Name Type Description
bool bool

Returns True if the point is different from all surrounding

bool

points, False otherwise.

Source code in roc/feature_extractors/single.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def is_unique_from_neighbors(data: IntGrid, point: Point) -> bool:
    """Helper function to determine if a point in a matrix has the same value as
    any points around it.

    Args:
        data (VisionData): The matrix / Grid to evaluate
        point (Point): The point to see if any of its neighbors have the same value

    Returns:
        bool: Returns True if the point is different from all surrounding
        points, False otherwise.
    """
    max_width = data.width - 1
    max_height = data.height - 1
    # up left
    if point.x > 0 and point.y > 0 and data.get_val(point.x - 1, point.y - 1) == point.val:
        return False
    # up
    if point.y > 0 and data.get_val(point.x, point.y - 1) == point.val:
        return False
    # up right
    if point.x < max_width and point.y > 0 and data.get_val(point.x + 1, point.y - 1) == point.val:
        return False
    # left
    if point.x > 0 and data.get_val(point.x - 1, point.y) == point.val:
        return False
    # right
    if point.x < max_width and data.get_val(point.x + 1, point.y) == point.val:
        return False
    # down left
    if point.x > 0 and point.y < max_height and data.get_val(point.x - 1, point.y + 1) == point.val:
        return False
    # down
    if point.y < max_height and data.get_val(point.x, point.y + 1) == point.val:
        return False
    # down right
    if (
        point.x < max_width
        and point.y < max_height
        and data.get_val(point.x + 1, point.y + 1) == point.val
    ):
        return False
    return True