Skip to content

Commit 1cd6b1e

Browse files
committed
Added substitute tool to the transform module.
1 parent 6d5a240 commit 1cd6b1e

File tree

5 files changed

+53
-8
lines changed

5 files changed

+53
-8
lines changed
Loading
Loading
Loading

dmtools/tests/test_transform.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
from dmtools.transform import (rescale, blur, composite, clip, normalize,
55
wraparound, _over_alpha_composite,
6-
_over_color_composite, crop)
6+
_over_color_composite, crop, substitute)
77
from dmtools.colorspace import gray_to_RGB
88
from dmtools.io import read
99

@@ -117,6 +117,19 @@ def test_composite_functions():
117117
assert np.allclose(result, image, atol=0.01)
118118

119119

120+
@pytest.mark.parametrize("path,sub_path,x,y,relative,loc,exp_path",[
121+
('red_box', 'blue_box', 100, 200, False, 'upper-left', 'red_blue_box'),
122+
('red_box', 'blue_box', 100, 100, False, 'lower-left', 'red_blue_box'),
123+
('red_box', 'blue_box', 150, 150, False, 'center', 'red_blue_box'),
124+
('red_box', 'blue_box', 0.5, 0.5, True, 'center', 'red_blue_box')])
125+
def test_substitute(path, sub_path, x, y, relative, loc, exp_path):
126+
image = read(f"{RESOURCES_PATH}/substitute_tests/{path}.png")
127+
sub_image = read(f"{RESOURCES_PATH}/substitute_tests/{sub_path}.png")
128+
exp = read(f"{RESOURCES_PATH}/substitute_tests/{exp_path}.png")
129+
result = substitute(image, sub_image, x, y, relative=relative, loc=loc)
130+
assert np.allclose(exp, result, atol=0.01)
131+
132+
120133
@pytest.mark.parametrize("path,x,y,w,h,relative,loc,exp_path",[
121134
('black_square', 0, 125, 125, 125, False, 'upper-left', 'black_square'),
122135
('red_square', 0, 0, 125, 125, False, 'lower-left', 'red_square'),

dmtools/transform.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -322,20 +322,52 @@ def _standardize_selection(image: np.ndarray, x: float, y: float, w: float,
322322
h: float, relative: bool, loc: str) -> List[float]:
323323
if relative:
324324
n,m,*_ = image.shape
325-
x = int(m * x)
326-
y = int(n * y)
327-
w = int(m * w)
328-
h = int(n * h)
325+
x = m * x
326+
y = n * y
327+
w = m * w
328+
h = n * h
329329
if loc == "upper-left":
330330
y = image.shape[0] - y
331331
elif loc == "lower-left":
332332
pass
333333
elif loc == "center":
334-
x = int(x - (w / 2)) + 1
335-
y = int(y - (h / 2)) + 1
334+
x = x - (w / 2)
335+
y = y - (h / 2)
336336
else:
337337
raise ValueError(f"{loc} is not a supported loc.")
338-
return x, y, w, h
338+
return int(x), int(y), int(w), int(h)
339+
340+
341+
def substitute(image: np.ndarray, substitution: np.ndarray, x: float, y: float,
342+
relative: bool = False, loc: str = 'upper-left') -> np.ndarray:
343+
"""Substitute a portion of image with substitution.
344+
345+
Args:
346+
image (np.ndarray): Base image.
347+
substitution (np.ndarray): Image to substitute into the base image.
348+
x (float): x coordinate of the point (relative to left of image).
349+
y (float): y coordinate of the point (relative to bottom of image).
350+
relative (bool): If True, x, y, w, and h are given relative to the \
351+
dimensions of the image. Defaults to False.
352+
loc (str): Location of (x,y) relative to substituted portion: \
353+
{upper-left, lower-left, center}.
354+
355+
Returns:
356+
np.ndarray: The image with substitution substituted in.
357+
"""
358+
if relative:
359+
n,m,*_ = image.shape
360+
h,w,*_ = substitution.shape
361+
w = w / m
362+
h = h / n
363+
else:
364+
h,w,*_ = substitution.shape
365+
x, y, w, h = _standardize_selection(image, x, y, w, h, relative, loc)
366+
if len(image.shape) == 3:
367+
image[y:y+h, x:x+w, :] = substitution
368+
else:
369+
image[y:y+h, x:x+w] = substitution
370+
return image
339371

340372

341373
def crop(image: np.ndarray, x: float, y: float, w: float, h: float,

0 commit comments

Comments
 (0)