Skip to content

Commit 50d781a

Browse files
committed
refactor: remove adjust/adjusted functions
1 parent 964ce99 commit 50d781a

File tree

3 files changed

+7
-183
lines changed

3 files changed

+7
-183
lines changed

src/arduino/app_utils/image/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"PipeableFunction",
1212
"letterboxed",
1313
"resized",
14-
"adjusted",
1514
"greyscaled",
1615
"compressed_to_jpeg",
1716
"compressed_to_png",

src/arduino/app_utils/image/image_editor.py

Lines changed: 3 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ImageEditor:
2727
result = frame | letterboxed(target_size=(640, 640))
2828
2929
Chained operations:
30-
result = frame | letterboxed(target_size=(640, 640)) | adjusted(brightness=10)
30+
result = frame | letterboxed(target_size=(640, 640)) | greyscaled()
3131
"""
3232

3333
@staticmethod
@@ -101,54 +101,6 @@ def resize(frame: np.ndarray,
101101
else:
102102
return cv2.resize(frame, (target_size[1], target_size[0]), interpolation=interpolation)
103103

104-
@staticmethod
105-
def adjust(frame: np.ndarray,
106-
brightness: float = 0.0,
107-
contrast: float = 1.0,
108-
saturation: float = 1.0) -> np.ndarray:
109-
"""
110-
Apply basic image filters.
111-
112-
Args:
113-
frame (np.ndarray): Input frame
114-
brightness (float): Brightness adjustment (-100 to 100)
115-
contrast (float): Contrast multiplier (0.0 to 3.0)
116-
saturation (float): Saturation multiplier (0.0 to 3.0)
117-
118-
Returns:
119-
np.ndarray: adjusted frame
120-
"""
121-
original_dtype = frame.dtype
122-
123-
# Convert to float for calculations to avoid overflow/underflow
124-
result = frame.astype(np.float32)
125-
126-
# Apply contrast and brightness
127-
result = result * contrast + brightness
128-
129-
# Clamp to valid range based on original dtype
130-
try:
131-
if np.issubdtype(original_dtype, np.integer):
132-
info = np.iinfo(original_dtype)
133-
result = np.clip(result, info.min, info.max)
134-
else:
135-
info = np.finfo(original_dtype)
136-
result = np.clip(result, info.min, info.max)
137-
except ValueError:
138-
# If we fail, just ensure a non-negative output
139-
result = np.clip(result, 0.0, np.inf)
140-
141-
result = result.astype(original_dtype)
142-
143-
# Apply saturation
144-
if saturation != 1.0:
145-
hsv = cv2.cvtColor(result, cv2.COLOR_BGR2HSV).astype(np.float32)
146-
hsv[:, :, 1] *= saturation
147-
hsv[:, :, 1] = np.clip(hsv[:, :, 1], 0, 255)
148-
result = cv2.cvtColor(hsv.astype(np.uint8), cv2.COLOR_HSV2BGR)
149-
150-
return result
151-
152104
@staticmethod
153105
def greyscale(frame: np.ndarray) -> np.ndarray:
154106
"""
@@ -244,26 +196,6 @@ def pil_to_numpy(image: Image.Image) -> np.ndarray:
244196
rgb_array = np.array(image)
245197
return cv2.cvtColor(rgb_array, cv2.COLOR_RGB2BGR)
246198

247-
@staticmethod
248-
def get_frame_info(frame: np.ndarray) -> dict:
249-
"""
250-
Get information about a frame.
251-
252-
Args:
253-
frame (np.ndarray): Input frame
254-
255-
Returns:
256-
dict: Frame information including dimensions, channels, dtype, size
257-
"""
258-
return {
259-
'height': frame.shape[0],
260-
'width': frame.shape[1],
261-
'channels': frame.shape[2] if len(frame.shape) > 2 else 1,
262-
'dtype': str(frame.dtype),
263-
'size_bytes': frame.nbytes,
264-
'shape': frame.shape
265-
}
266-
267199

268200
# =============================================================================
269201
# Functional API - Standalone pipeable functions
@@ -283,7 +215,7 @@ def letterboxed(target_size: Optional[Tuple[int, int]] = None,
283215
284216
Examples:
285217
pipe = letterboxed(target_size=(640, 640))
286-
pipe = letterboxed() | adjusted(brightness=10)
218+
pipe = letterboxed() | greyscaled()
287219
"""
288220
return PipeableFunction(ImageEditor.letterbox, target_size=target_size, color=color)
289221

@@ -309,27 +241,6 @@ def resized(target_size: Tuple[int, int],
309241
return PipeableFunction(ImageEditor.resize, target_size=target_size, maintain_ratio=maintain_ratio, interpolation=interpolation)
310242

311243

312-
def adjusted(brightness: float = 0.0,
313-
contrast: float = 1.0,
314-
saturation: float = 1.0):
315-
"""
316-
Pipeable filter function - apply filters with pipe operator support.
317-
318-
Args:
319-
brightness (float): Brightness adjustment (-100 to 100)
320-
contrast (float): Contrast multiplier (0.0 to 3.0)
321-
saturation (float): Saturation multiplier (0.0 to 3.0)
322-
323-
Returns:
324-
Partial function that takes a frame and returns the adjusted frame
325-
326-
Examples:
327-
pipe = adjusted(brightness=10, contrast=1.2)
328-
pipe = letterboxed() | adjusted(brightness=5) | resized(target_size=(320, 240))
329-
"""
330-
return PipeableFunction(ImageEditor.adjust, brightness=brightness, contrast=contrast, saturation=saturation)
331-
332-
333244
def greyscaled():
334245
"""
335246
Pipeable greyscale function - convert frame to greyscale with pipe operator support.
@@ -339,7 +250,7 @@ def greyscaled():
339250
340251
Examples:
341252
pipe = greyscaled()
342-
pipe = letterboxed() | greyscaled() | adjusted(contrast=1.2)
253+
pipe = letterboxed() | greyscaled() | greyscaled()
343254
"""
344255
return PipeableFunction(ImageEditor.greyscale)
345256

tests/arduino/app_utils/image/test_image_editor.py

Lines changed: 4 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
ImageEditor,
1111
letterboxed,
1212
resized,
13-
adjusted,
1413
greyscaled,
1514
compressed_to_jpeg,
1615
compressed_to_png
@@ -87,53 +86,6 @@ def test_resize_interpolation_methods(self, sample_frame):
8786
result = ImageEditor.resize(sample_frame, target_size=target_size, interpolation=interpolation)
8887
assert result.shape[:2] == (50, 40)
8988

90-
def test_adjust_brightness(self, sample_frame):
91-
"""Test brightness adjustment."""
92-
# Increase brightness
93-
result = ImageEditor.adjust(sample_frame, brightness=50)
94-
assert result.shape == sample_frame.shape
95-
# Brightness should increase (but clipped at 255)
96-
assert np.all(result >= sample_frame)
97-
98-
# Decrease brightness - should clamp at 0, so all values <= original
99-
result = ImageEditor.adjust(sample_frame, brightness=-50)
100-
assert result.shape == sample_frame.shape
101-
assert result.dtype == sample_frame.dtype
102-
assert np.all(result <= sample_frame)
103-
# Values should never go below 0
104-
assert np.all(result >= 0)
105-
106-
def test_adjust_contrast(self, sample_frame):
107-
"""Test contrast adjustment."""
108-
# Increase contrast
109-
result = ImageEditor.adjust(sample_frame, contrast=1.5)
110-
assert result.shape == sample_frame.shape
111-
112-
# Decrease contrast
113-
result = ImageEditor.adjust(sample_frame, contrast=0.5)
114-
assert result.shape == sample_frame.shape
115-
116-
def test_adjust_saturation(self, sample_frame):
117-
"""Test saturation adjustment."""
118-
# Increase saturation
119-
result = ImageEditor.adjust(sample_frame, saturation=1.5)
120-
assert result.shape == sample_frame.shape
121-
122-
# Decrease saturation (towards grayscale)
123-
result = ImageEditor.adjust(sample_frame, saturation=0.5)
124-
assert result.shape == sample_frame.shape
125-
126-
# Zero saturation should be grayscale
127-
result = ImageEditor.adjust(sample_frame, saturation=0.0)
128-
# All channels should be equal for grayscale
129-
assert np.allclose(result[:, :, 0], result[:, :, 1], atol=1)
130-
assert np.allclose(result[:, :, 1], result[:, :, 2], atol=1)
131-
132-
def test_adjust_combined(self, sample_frame):
133-
"""Test combined brightness, contrast, and saturation adjustment."""
134-
result = ImageEditor.adjust(sample_frame, brightness=10, contrast=1.2, saturation=0.8)
135-
assert result.shape == sample_frame.shape
136-
13789
def test_greyscale_conversion(self, sample_frame):
13890
"""Test grayscale conversion."""
13991
result = ImageEditor.greyscale(sample_frame)
@@ -250,17 +202,6 @@ def test_resized_pipe_operator(self, sample_frame):
250202
assert result.shape[:2] == (50, 40)
251203
assert result.shape[2] == 3
252204

253-
def test_adjusted_function_returns_pipeable(self):
254-
"""Test that adjusted function returns PipeableFunction."""
255-
result = adjusted(brightness=10, contrast=1.2)
256-
assert isinstance(result, PipeableFunction)
257-
258-
def test_adjusted_pipe_operator(self, sample_frame):
259-
"""Test adjusted function with pipe operator."""
260-
result = adjusted(brightness=10, contrast=1.2, saturation=0.8)(sample_frame)
261-
262-
assert result.shape == sample_frame.shape
263-
264205
def test_greyscaled_function_returns_pipeable(self):
265206
"""Test that greyscaled function returns PipeableFunction."""
266207
result = greyscaled()
@@ -329,9 +270,7 @@ def test_simple_pipeline(self, sample_frame):
329270
def test_complex_pipeline(self, sample_frame):
330271
"""Test complex pipeline with multiple operations."""
331272
# Create pipeline using function-to-function composition
332-
pipe = (letterboxed(target_size=(150, 150)) |
333-
adjusted(brightness=10, contrast=1.1, saturation=0.9) |
334-
resized(target_size=(75, 75)))
273+
pipe = (letterboxed(target_size=(150, 150)) | resized(target_size=(75, 75)))
335274
result = pipe(sample_frame)
336275

337276
assert result.shape[:2] == (75, 75)
@@ -344,19 +283,15 @@ def test_pipeline_with_compression(self, mock_imencode, sample_frame):
344283
mock_imencode.return_value = (True, mock_encoded)
345284

346285
# Create pipeline using function-to-function composition
347-
pipe = (letterboxed(target_size=(100, 100)) |
348-
adjusted(brightness=5) |
349-
compressed_to_jpeg(quality=90))
286+
pipe = (letterboxed(target_size=(100, 100)) | compressed_to_jpeg(quality=90))
350287
result = pipe(sample_frame)
351288

352289
assert np.array_equal(result, mock_encoded)
353290

354291
def test_pipeline_with_greyscale(self, sample_frame):
355292
"""Test pipeline with greyscale conversion."""
356293
# Create pipeline using function-to-function composition
357-
pipe = (letterboxed(target_size=(100, 100)) |
358-
greyscaled() |
359-
adjusted(brightness=10, contrast=1.2))
294+
pipe = (letterboxed(target_size=(100, 100)) | greyscaled())
360295
result = pipe(sample_frame)
361296

362297
assert len(result.shape) == 3 and result.shape[2] == 3
@@ -411,25 +346,4 @@ def test_invalid_target_sizes(self):
411346
ImageEditor.resize(frame, target_size=(0, 100))
412347

413348
with pytest.raises((ValueError, cv2.error)):
414-
ImageEditor.resize(frame, target_size=(-10, 100))
415-
416-
def test_extreme_adjustment_values(self, sample_frame=None):
417-
"""Test extreme adjustment values."""
418-
if sample_frame is None:
419-
sample_frame = np.random.randint(0, 256, (50, 50, 3), dtype=np.uint8)
420-
421-
# Extreme brightness
422-
result = ImageEditor.adjust(sample_frame, brightness=1000)
423-
assert result.shape == sample_frame.shape
424-
assert np.all(result <= 255) # Should be clipped
425-
426-
result = ImageEditor.adjust(sample_frame, brightness=-1000)
427-
assert np.all(result >= 0) # Should be clipped
428-
429-
# Extreme contrast
430-
result = ImageEditor.adjust(sample_frame, contrast=100)
431-
assert result.shape == sample_frame.shape
432-
433-
# Zero contrast
434-
result = ImageEditor.adjust(sample_frame, contrast=0)
435-
assert result.shape == sample_frame.shape
349+
ImageEditor.resize(frame, target_size=(-10, 100))

0 commit comments

Comments
 (0)