Spaces:
Sleeping
Sleeping
Fix tiling strategy to avoid infinite loops
Browse files- Replace while loops with for loops using calculated tile counts
- Add _calculate_tiles_count() to compute optimal number of tiles per dimension
- Ensure minimum overlap ratio while minimizing total tile count
- Fix infinite loop issue in previous implementation
- Example: 1360x800 image → 2 tiles (1x2 grid) with 30% overlap instead of timeout
model.py
CHANGED
|
@@ -107,44 +107,80 @@ class TrafficSignDetector:
|
|
| 107 |
|
| 108 |
print("="*80 + "\n")
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
def _create_tiles(self, image, overlap_ratio=0.2):
|
| 111 |
"""
|
| 112 |
-
Cắt ảnh thành các tiles vuông với overlap.
|
|
|
|
|
|
|
| 113 |
:param image: input image (numpy array)
|
| 114 |
-
:param overlap_ratio: tỉ lệ overlap
|
| 115 |
-
:return: list of
|
| 116 |
"""
|
| 117 |
height, width = image.shape[:2]
|
| 118 |
-
|
| 119 |
|
| 120 |
-
print(f"\n[TILING] Image: {width}x{height}, Min dimension: {
|
| 121 |
|
| 122 |
-
#
|
| 123 |
-
|
| 124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
tiles = []
|
| 127 |
-
tile_size = min_dim
|
| 128 |
|
| 129 |
# Tạo grid tiles
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
if x_end - x < tile_size and x > 0:
|
| 143 |
-
x = width - tile_size
|
| 144 |
-
x_end = width
|
| 145 |
|
| 146 |
# Extract tile
|
| 147 |
tile = image[y:y_end, x:x_end]
|
|
|
|
| 148 |
tiles.append({
|
| 149 |
'image': tile,
|
| 150 |
'y_min': y,
|
|
@@ -152,18 +188,8 @@ class TrafficSignDetector:
|
|
| 152 |
'y_max': y_end,
|
| 153 |
'x_max': x_end
|
| 154 |
})
|
| 155 |
-
|
| 156 |
-
x += stride
|
| 157 |
-
if x >= width:
|
| 158 |
-
break
|
| 159 |
-
|
| 160 |
-
y += stride
|
| 161 |
-
if y >= height:
|
| 162 |
-
break
|
| 163 |
|
| 164 |
-
print(f" -
|
| 165 |
-
print(f" - Stride: {stride} (overlap: {overlap_ratio*100:.0f}%)")
|
| 166 |
-
print(f" - Số tiles: {len(tiles)}")
|
| 167 |
|
| 168 |
return tiles
|
| 169 |
|
|
|
|
| 107 |
|
| 108 |
print("="*80 + "\n")
|
| 109 |
|
| 110 |
+
def _calculate_tiles_count(self, length, tile_size, min_overlap=0.2):
|
| 111 |
+
"""
|
| 112 |
+
Tính số tiles tối thiểu cần thiết cho 1 chiều.
|
| 113 |
+
Đảm bảo overlap >= min_overlap.
|
| 114 |
+
|
| 115 |
+
:param length: chiều dài của ảnh (width hoặc height)
|
| 116 |
+
:param tile_size: kích thước tile
|
| 117 |
+
:param min_overlap: overlap tối thiểu (0.2 = 20%)
|
| 118 |
+
:return: (num_tiles, stride)
|
| 119 |
+
"""
|
| 120 |
+
if length <= tile_size:
|
| 121 |
+
return 1, 0
|
| 122 |
+
|
| 123 |
+
# Cần ít nhất 2 tiles
|
| 124 |
+
num_tiles = 2
|
| 125 |
+
max_iterations = 100
|
| 126 |
+
|
| 127 |
+
for _ in range(max_iterations):
|
| 128 |
+
# stride = (length - tile_size) / (num_tiles - 1)
|
| 129 |
+
stride = (length - tile_size) / (num_tiles - 1)
|
| 130 |
+
overlap = (tile_size - stride) / tile_size
|
| 131 |
+
|
| 132 |
+
if overlap >= min_overlap:
|
| 133 |
+
return num_tiles, int(stride)
|
| 134 |
+
|
| 135 |
+
num_tiles += 1
|
| 136 |
+
|
| 137 |
+
return num_tiles, int((length - tile_size) / (num_tiles - 1))
|
| 138 |
+
|
| 139 |
def _create_tiles(self, image, overlap_ratio=0.2):
|
| 140 |
"""
|
| 141 |
+
Cắt ảnh thành các tiles vuông với overlap tối thiểu.
|
| 142 |
+
Tính số tiles cần thiết để cover hết ảnh với overlap >= overlap_ratio.
|
| 143 |
+
|
| 144 |
:param image: input image (numpy array)
|
| 145 |
+
:param overlap_ratio: tỉ lệ overlap tối thiểu (0.2 = 20%)
|
| 146 |
+
:return: list of tile dicts
|
| 147 |
"""
|
| 148 |
height, width = image.shape[:2]
|
| 149 |
+
tile_size = min(height, width)
|
| 150 |
|
| 151 |
+
print(f"\n[TILING] Image: {width}x{height}, Min dimension (tile_size): {tile_size}")
|
| 152 |
|
| 153 |
+
# Tính số tiles và stride cho mỗi chiều
|
| 154 |
+
num_tiles_h, stride_h = self._calculate_tiles_count(height, tile_size, min_overlap=overlap_ratio)
|
| 155 |
+
num_tiles_w, stride_w = self._calculate_tiles_count(width, tile_size, min_overlap=overlap_ratio)
|
| 156 |
+
|
| 157 |
+
# Tính overlap thực tế
|
| 158 |
+
overlap_h = (tile_size - stride_h) / tile_size if stride_h > 0 else 0
|
| 159 |
+
overlap_w = (tile_size - stride_w) / tile_size if stride_w > 0 else 0
|
| 160 |
+
|
| 161 |
+
print(f" - Tile size: {tile_size}x{tile_size}")
|
| 162 |
+
print(f" - Height: {height} → {num_tiles_h} tiles, stride={stride_h}, overlap={overlap_h*100:.0f}%")
|
| 163 |
+
print(f" - Width: {width} → {num_tiles_w} tiles, stride={stride_w}, overlap={overlap_w*100:.0f}%")
|
| 164 |
|
| 165 |
tiles = []
|
|
|
|
| 166 |
|
| 167 |
# Tạo grid tiles
|
| 168 |
+
for i in range(num_tiles_h):
|
| 169 |
+
for j in range(num_tiles_w):
|
| 170 |
+
# Tính vị trí
|
| 171 |
+
y = int(i * stride_h)
|
| 172 |
+
x = int(j * stride_w)
|
| 173 |
+
|
| 174 |
+
# Đảm bảo không vượt quá bounds
|
| 175 |
+
y = min(y, height - tile_size)
|
| 176 |
+
x = min(x, width - tile_size)
|
| 177 |
+
|
| 178 |
+
y_end = y + tile_size
|
| 179 |
+
x_end = x + tile_size
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
# Extract tile
|
| 182 |
tile = image[y:y_end, x:x_end]
|
| 183 |
+
|
| 184 |
tiles.append({
|
| 185 |
'image': tile,
|
| 186 |
'y_min': y,
|
|
|
|
| 188 |
'y_max': y_end,
|
| 189 |
'x_max': x_end
|
| 190 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
+
print(f" - Total tiles: {len(tiles)} ({num_tiles_h}x{num_tiles_w})")
|
|
|
|
|
|
|
| 193 |
|
| 194 |
return tiles
|
| 195 |
|