File size: 8,134 Bytes
fadb92b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
78
79
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
import random
from typing import List, Optional, Tuple

import cv2
import numpy as np
from skimage.draw import polygon


class RoomDropoutStrategy:
    """
    Strategy for randomly dropping rooms from a density map using ground truth coordinates.

    Density map: grayscale image where foreground (rooms) are white points and background is black
    GT room coordinates: list of 2D points defining each room's boundary
    """

    def __init__(self, density_map: np.ndarray, room_coordinates: List[List[Tuple[int, int]]]):
        """
        Initialize the dropout strategy.

        Args:
            density_map: Grayscale image (H, W) where white pixels represent rooms
            room_coordinates: List of rooms, each room is a list of (x, y) coordinate tuples
        """
        self.original_density_map = density_map.copy()
        self.room_coordinates = room_coordinates
        self.num_rooms = len(room_coordinates)

    def create_room_masks(self) -> List[np.ndarray]:
        """
        Create binary masks for each room using their GT coordinates.

        Returns:
            List of binary masks, one for each room
        """
        h, w = self.original_density_map.shape
        room_masks = []

        for room_coords in self.room_coordinates:
            mask = np.zeros((h, w), dtype=np.uint8)

            if len(room_coords) >= 3:  # Need at least 3 points for a polygon
                # Convert coordinates to numpy array
                coords = np.array(room_coords)
                x_coords = coords[:, 0]
                y_coords = coords[:, 1]

                # Create polygon mask using skimage
                rr, cc = polygon(y_coords, x_coords, shape=(h, w))
                mask[rr, cc] = 1

            room_masks.append(mask)

        return room_masks

    def drop_rooms_random(self, dropout_rate: float = 0.3, seed: Optional[int] = None) -> Tuple[np.ndarray, List[int]]:
        """
        Randomly drop rooms from the density map.

        Args:
            dropout_rate: Fraction of rooms to drop (0.0 to 1.0)
            seed: Random seed for reproducibility

        Returns:
            Tuple of (modified_density_map, list_of_dropped_room_indices)
        """
        if seed is not None:
            random.seed(seed)
            np.random.seed(seed)

        # Determine number of rooms to drop
        num_to_drop = int(self.num_rooms * dropout_rate)

        # Randomly select room indices to drop
        room_indices = list(range(self.num_rooms))
        dropped_indices = random.sample(room_indices, num_to_drop)

        return self._apply_dropout(dropped_indices), dropped_indices

    def drop_rooms_by_indices(self, room_indices: List[int]) -> np.ndarray:
        """
        Drop specific rooms by their indices.

        Args:
            room_indices: List of room indices to drop

        Returns:
            Modified density map with specified rooms removed
        """
        return self._apply_dropout(room_indices)

    def drop_rooms_by_area(
        self, min_area: Optional[int] = None, max_area: Optional[int] = None
    ) -> Tuple[np.ndarray, List[int]]:
        """
        Drop rooms based on their area constraints.

        Args:
            min_area: Minimum area threshold (drop rooms smaller than this)
            max_area: Maximum area threshold (drop rooms larger than this)

        Returns:
            Tuple of (modified_density_map, list_of_dropped_room_indices)
        """
        room_masks = self.create_room_masks()
        dropped_indices = []

        for i, mask in enumerate(room_masks):
            area = np.sum(mask)

            should_drop = False
            if min_area is not None and area < min_area:
                should_drop = True
            if max_area is not None and area > max_area:
                should_drop = True

            if should_drop:
                dropped_indices.append(i)

        return self._apply_dropout(dropped_indices), dropped_indices

    def _apply_dropout(self, room_indices_to_drop: List[int]) -> np.ndarray:
        """
        Apply dropout by removing specified rooms from the density map.

        Args:
            room_indices_to_drop: List of room indices to remove

        Returns:
            Modified density map with rooms removed
        """
        modified_map = self.original_density_map.copy()
        room_masks = self.create_room_masks()

        # Remove each specified room
        for room_idx in room_indices_to_drop:
            if 0 <= room_idx < len(room_masks):
                mask = room_masks[room_idx]
                # Set pixels in the room area to background (black/0)
                modified_map[mask == 1] = 0

        return modified_map

    def visualize_dropout(
        self, original_map: np.ndarray, modified_map: np.ndarray, dropped_indices: List[int]
    ) -> np.ndarray:
        """
        Create a visualization showing the dropout effect.

        Args:
            original_map: Original density map
            modified_map: Modified density map after dropout
            dropped_indices: Indices of dropped rooms

        Returns:
            Visualization image with original and modified maps side by side
        """
        h, w = original_map.shape

        # Create side-by-side comparison
        vis = np.zeros((h, w * 2), dtype=np.uint8)
        vis[:, :w] = original_map
        vis[:, w:] = modified_map

        # Highlight dropped rooms in red on the original map
        if len(dropped_indices) > 0:
            room_masks = self.create_room_masks()
            vis_color = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)

            for idx in dropped_indices:
                if 0 <= idx < len(room_masks):
                    mask = room_masks[idx]
                    # Highlight in red on the left (original) side
                    vis_color[mask == 1, 0] = 0  # Blue channel
                    vis_color[mask == 1, 1] = 0  # Green channel
                    vis_color[mask == 1, 2] = 255  # Red channel

            return vis_color

        return cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)


# Example usage and testing
def example_usage():
    """
    Example of how to use the RoomDropoutStrategy class.
    """
    # Create a sample density map (200x200 image)
    density_map = np.zeros((200, 200), dtype=np.uint8)

    # Create some sample room coordinates (rectangles and polygons)
    room_coordinates = [
        # Room 1: Rectangle
        [(20, 20), (80, 20), (80, 60), (20, 60)],
        # Room 2: Another rectangle
        [(100, 30), (180, 30), (180, 80), (100, 80)],
        # Room 3: L-shaped room
        [(30, 100), (90, 100), (90, 130), (60, 130), (60, 160), (30, 160)],
        # Room 4: Triangle
        [(120, 120), (160, 120), (140, 160)],
        # Room 5: Pentagon
        [(50, 180), (70, 170), (90, 180), (80, 195), (40, 195)],
    ]

    # Fill the density map with white pixels for each room
    for room_coords in room_coordinates:
        coords = np.array(room_coords)
        x_coords = coords[:, 0]
        y_coords = coords[:, 1]

        from skimage.draw import polygon

        rr, cc = polygon(y_coords, x_coords, shape=density_map.shape)
        density_map[rr, cc] = 255  # White pixels for rooms

    # Initialize the dropout strategy
    dropout_strategy = RoomDropoutStrategy(density_map, room_coordinates)

    # Example 1: Random dropout
    print("Example 1: Random dropout (30% of rooms)")
    modified_map1, dropped_indices1 = dropout_strategy.drop_rooms_random(dropout_rate=0.3, seed=42)
    print(f"Dropped rooms: {dropped_indices1}")

    # Example 2: Drop specific rooms
    print("\nExample 2: Drop specific rooms (indices 0 and 2)")
    modified_map2 = dropout_strategy.drop_rooms_by_indices([0, 2])

    # Example 3: Drop rooms by area
    print("\nExample 3: Drop rooms with area > 3000 pixels")
    modified_map3, dropped_indices3 = dropout_strategy.drop_rooms_by_area(max_area=3000)
    print(f"Dropped rooms by area: {dropped_indices3}")

    return density_map, modified_map1, modified_map2, modified_map3


if __name__ == "__main__":
    example_usage()