0
# Layer Management System
1
2
Global state management system for intermediate processing results, enabling modular pipeline architecture and debugging capabilities. The layer system allows each processing stage to register intermediate results for use by subsequent stages.
3
4
## Capabilities
5
6
### Layer Registration
7
8
Register processing layers for global access throughout the pipeline.
9
10
```python { .api }
11
def register_layer(name: str, layer: ndarray) -> None:
12
"""
13
Register a processing layer with a given name.
14
15
Stores the layer data in global memory for access by other
16
processing stages. Prints a warning if layer name already exists.
17
18
Parameters:
19
- name (str): Unique identifier for the layer
20
- layer (ndarray): Numpy array containing the layer data
21
22
Raises:
23
AssertionError: If layer is not a numpy array
24
"""
25
```
26
27
### Layer Retrieval
28
29
Retrieve registered processing layers by name.
30
31
```python { .api }
32
def get_layer(name: str) -> ndarray:
33
"""
34
Retrieve a registered processing layer by name.
35
36
Parameters:
37
- name (str): Name of the layer to retrieve
38
39
Returns:
40
ndarray: The requested layer data
41
42
Raises:
43
KeyError: If no layer with the given name exists
44
"""
45
```
46
47
### Layer Management
48
49
Manage the lifecycle of registered layers.
50
51
```python { .api }
52
def delete_layer(name: str) -> None:
53
"""
54
Delete a registered layer and free its memory.
55
56
Silently handles cases where the layer doesn't exist.
57
58
Parameters:
59
- name (str): Name of the layer to delete
60
"""
61
62
def list_layers() -> List[str]:
63
"""
64
List all currently registered layer names.
65
66
Returns:
67
List[str]: List of all registered layer names
68
"""
69
70
def show_access_count() -> None:
71
"""
72
Display access statistics for all registered layers.
73
74
Shows how many times each layer has been accessed,
75
useful for debugging and optimization.
76
"""
77
```
78
79
## Standard Layer Names
80
81
The oemer pipeline uses standardized layer names for consistency:
82
83
### Input Layers
84
- `"original_image"` - Original input image (RGB)
85
- `"staff_pred"` - Staff line predictions from neural network
86
- `"symbols_pred"` - Combined symbol predictions
87
- `"notehead_pred"` - Note head predictions
88
- `"stems_rests_pred"` - Stems and rests predictions
89
- `"clefs_keys_pred"` - Clefs and accidentals predictions
90
91
### Extracted Elements
92
- `"staffs"` - Array of Staff instances
93
- `"zones"` - Staff zone boundaries
94
- `"notes"` - Array of NoteHead instances
95
- `"note_groups"` - Array of NoteGroup instances
96
- `"clefs"` - Array of Clef instances
97
- `"sfns"` - Array of sharp/flat/natural instances
98
- `"rests"` - Array of Rest instances
99
- `"barlines"` - Array of Barline instances
100
101
### Processing Layers
102
- `"note_id"` - Note ID mapping layer
103
- `"group_map"` - Note group mapping layer
104
- `"bboxes"` - Bounding box registration layer
105
106
## Usage Examples
107
108
### Basic Layer Operations
109
110
```python
111
from oemer.layers import register_layer, get_layer, delete_layer, list_layers
112
import numpy as np
113
import cv2
114
115
# Register an image layer
116
image = cv2.imread("sheet_music.jpg")
117
register_layer("original_image", image)
118
119
# Register prediction layers
120
staff_predictions = np.random.randint(0, 2, (1000, 1500), dtype=np.uint8)
121
register_layer("staff_pred", staff_predictions)
122
123
symbol_predictions = np.random.randint(0, 3, (1000, 1500), dtype=np.uint8)
124
register_layer("symbols_pred", symbol_predictions)
125
126
# List all registered layers
127
print("Registered layers:", list_layers())
128
129
# Retrieve layers for processing
130
original = get_layer("original_image")
131
staff = get_layer("staff_pred")
132
symbols = get_layer("symbols_pred")
133
134
print(f"Original image shape: {original.shape}")
135
print(f"Staff predictions shape: {staff.shape}")
136
print(f"Symbol predictions shape: {symbols.shape}")
137
138
# Clean up specific layer
139
delete_layer("symbols_pred")
140
print("Layers after deletion:", list_layers())
141
```
142
143
### Pipeline Integration
144
145
```python
146
from oemer.layers import register_layer, get_layer
147
from oemer.staffline_extraction import extract as staff_extract
148
from oemer.notehead_extraction import extract as note_extract
149
import numpy as np
150
151
def process_with_layers(image_path: str):
152
"""Example of layer-based processing pipeline."""
153
154
# 1. Load and register input image
155
image = cv2.imread(image_path)
156
register_layer("original_image", image)
157
158
# 2. Generate and register predictions (simplified)
159
# In real usage, these come from neural network inference
160
h, w = image.shape[:2]
161
staff_pred = np.random.randint(0, 2, (h, w), dtype=np.uint8)
162
symbols_pred = np.random.randint(0, 2, (h, w), dtype=np.uint8)
163
164
register_layer("staff_pred", staff_pred)
165
register_layer("symbols_pred", symbols_pred)
166
167
# 3. Extract stafflines (reads from layers automatically)
168
staffs, zones = staff_extract()
169
register_layer("staffs", np.array(staffs))
170
register_layer("zones", zones)
171
172
# 4. Extract noteheads (reads from layers automatically)
173
notes = note_extract()
174
register_layer("notes", np.array(notes))
175
176
# 5. Access results from any stage
177
extracted_staffs = get_layer("staffs")
178
extracted_notes = get_layer("notes")
179
180
print(f"Extracted {len(extracted_staffs)} staffs")
181
print(f"Extracted {len(extracted_notes)} notes")
182
183
return extracted_staffs, extracted_notes
184
185
# Run the pipeline
186
staffs, notes = process_with_layers("test_score.jpg")
187
```
188
189
### Memory Management
190
191
```python
192
from oemer.layers import register_layer, delete_layer, list_layers, show_access_count
193
import numpy as np
194
195
def memory_efficient_processing():
196
"""Example of memory-efficient layer management."""
197
198
# Register large intermediate layers
199
large_layer1 = np.zeros((5000, 5000), dtype=np.float32)
200
large_layer2 = np.zeros((5000, 5000), dtype=np.float32)
201
202
register_layer("temp_layer1", large_layer1)
203
register_layer("temp_layer2", large_layer2)
204
205
print(f"Layers registered: {list_layers()}")
206
207
# Process data using the layers
208
data1 = get_layer("temp_layer1")
209
data2 = get_layer("temp_layer2")
210
211
# Combine and create final result
212
result = data1 + data2
213
register_layer("final_result", result)
214
215
# Clean up intermediate layers to free memory
216
delete_layer("temp_layer1")
217
delete_layer("temp_layer2")
218
219
print(f"Layers after cleanup: {list_layers()}")
220
221
# Show access statistics
222
show_access_count()
223
224
return get_layer("final_result")
225
226
result = memory_efficient_processing()
227
```
228
229
### Debugging with Layers
230
231
```python
232
from oemer.layers import register_layer, get_layer, list_layers
233
import matplotlib.pyplot as plt
234
import numpy as np
235
236
def debug_pipeline_stage(stage_name: str):
237
"""Debug a specific pipeline stage by examining its layers."""
238
239
print(f"\n=== Debugging {stage_name} ===")
240
print(f"Available layers: {list_layers()}")
241
242
# Check if expected layers exist
243
expected_layers = ["original_image", "staff_pred", "symbols_pred"]
244
for layer_name in expected_layers:
245
try:
246
layer = get_layer(layer_name)
247
print(f"✓ {layer_name}: shape={layer.shape}, dtype={layer.dtype}")
248
249
# Show basic statistics
250
if layer.dtype in [np.uint8, np.int32, np.float32]:
251
print(f" Range: [{np.min(layer)}, {np.max(layer)}]")
252
print(f" Non-zero pixels: {np.count_nonzero(layer)}")
253
254
except KeyError:
255
print(f"✗ {layer_name}: NOT FOUND")
256
257
# Visualize layers if available
258
try:
259
original = get_layer("original_image")
260
staff = get_layer("staff_pred")
261
262
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
263
264
axes[0].imshow(original)
265
axes[0].set_title("Original Image")
266
axes[0].axis('off')
267
268
axes[1].imshow(staff, cmap='gray')
269
axes[1].set_title("Staff Predictions")
270
axes[1].axis('off')
271
272
plt.tight_layout()
273
plt.savefig(f"debug_{stage_name}.png")
274
print(f"Saved debug visualization: debug_{stage_name}.png")
275
276
except KeyError as e:
277
print(f"Could not create visualization: {e}")
278
279
# Use in pipeline debugging
280
debug_pipeline_stage("after_inference")
281
```
282
283
### Layer Data Validation
284
285
```python
286
from oemer.layers import get_layer, register_layer
287
import numpy as np
288
289
def validate_layer_consistency():
290
"""Validate that all layers have consistent dimensions."""
291
292
try:
293
# Get core layers
294
original = get_layer("original_image")
295
staff = get_layer("staff_pred")
296
symbols = get_layer("symbols_pred")
297
298
# Check shape consistency
299
h, w = original.shape[:2]
300
301
if staff.shape != (h, w):
302
print(f"WARNING: Staff predictions shape {staff.shape} != image shape {(h, w)}")
303
304
if symbols.shape != (h, w):
305
print(f"WARNING: Symbol predictions shape {symbols.shape} != image shape {(h, w)}")
306
307
# Check data ranges
308
if staff.dtype == np.uint8 and (staff.min() < 0 or staff.max() > 255):
309
print(f"WARNING: Staff predictions out of uint8 range: [{staff.min()}, {staff.max()}]")
310
311
if symbols.dtype == np.uint8 and (symbols.min() < 0 or symbols.max() > 255):
312
print(f"WARNING: Symbol predictions out of uint8 range: [{symbols.min()}, {symbols.max()}]")
313
314
print("✓ Layer consistency validation passed")
315
316
except KeyError as e:
317
print(f"✗ Layer validation failed: Missing layer {e}")
318
except Exception as e:
319
print(f"✗ Layer validation error: {e}")
320
321
# Run validation during pipeline execution
322
validate_layer_consistency()
323
```
324
325
## Best Practices
326
327
### Layer Naming Conventions
328
- Use descriptive, lowercase names with underscores
329
- Follow the standard naming scheme when possible
330
- Use prefixes for temporary or debug layers (`temp_`, `debug_`)
331
332
### Memory Management
333
- Delete large intermediate layers when no longer needed
334
- Use `show_access_count()` to identify unused layers
335
- Clear all layers between processing different images
336
337
### Error Handling
338
- Always check if required layers exist before accessing them
339
- Handle `KeyError` exceptions when retrieving layers
340
- Validate layer shapes and data types for consistency
341
342
The layer management system provides a flexible foundation for the oemer pipeline, enabling modular development, easy debugging, and efficient memory usage.