[jacinto-ai/pytorch-jacinto-ai-devkit.git] / modules / pytorch_jacinto_ai / xvision / transforms / image_transforms.py
1 #################################################################################
2 # Copyright (c) 2018-2021, Texas Instruments Incorporated - http://www.ti.com
3 # All Rights Reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
7 #
8 # * Redistributions of source code must retain the above copyright notice, this
9 # list of conditions and the following disclaimer.
10 #
11 # * Redistributions in binary form must reproduce the above copyright notice,
12 # this list of conditions and the following disclaimer in the documentation
13 # and/or other materials provided with the distribution.
14 #
15 # * Neither the name of the copyright holder nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #
30 #################################################################################
31 # Some parts of the code are borrowed from: https://github.com/ansleliu/LightNet
32 # with the following license:
33 #
34 # MIT License
35 #
36 # Copyright (c) 2018 Huijun Liu
37 #
38 # Permission is hereby granted, free of charge, to any person obtaining a copy
39 # of this software and associated documentation files (the "Software"), to deal
40 # in the Software without restriction, including without limitation the rights
41 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42 # copies of the Software, and to permit persons to whom the Software is
43 # furnished to do so, subject to the following conditions:
44 #
45 # The above copyright notice and this permission notice shall be included in all
46 # copies or substantial portions of the Software.
47 #
48 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54 # SOFTWARE.
55 #################################################################################
57 from __future__ import division
58 import random
59 import numbers
60 import math
61 import cv2
62 import numpy as np
63 import PIL
65 from .image_transform_utils import *
68 class CheckImages(object):
69 def __call__(self, images, targets):
70 assert isinstance(images, (list, tuple)), 'Input must a list'
71 assert isinstance(targets, (list, tuple)), 'Target must a list'
72 #assert images[0].shape[:2] == targets[0].shape[:2], 'Image and target sizes must match.'
74 for img_idx in range(len(images)):
75 assert images[img_idx].shape[:2] == images[0].shape[:2], 'Image sizes must match. Either provide same size images or use AlignImages() instead of CheckImages()'
76 images[img_idx] = images[img_idx][...,np.newaxis] if (images[img_idx].shape) == 2 else images[img_idx]
78 for img_idx in range(len(targets)):
79 assert targets[img_idx].shape[:2] == targets[0].shape[:2], 'Target sizes must match. Either provide same size targets or use AlignImages() instead of CheckImages()'
80 targets[img_idx] = targets[img_idx][...,np.newaxis] if (targets[img_idx].shape) == 2 else targets[img_idx]
82 return images, targets
85 class AlignImages(object):
86 """Resize everything to the first image's size, before transformations begin.
87 Also make sure the images are in the desired format."""
88 def __init__(self, is_flow=None, interpolation=-1):
89 self.is_flow = is_flow
90 self.interpolation = interpolation
92 def __call__(self, images, targets):
93 images = images if isinstance(images, (list,tuple)) else [images]
94 images = [np.array(img) if isinstance(img,PIL.Image.Image) else img for img in images]
96 targets = targets if isinstance(targets, (list,tuple)) else [targets]
97 targets = [np.array(tgt) if isinstance(tgt,PIL.Image.Image) else tgt for tgt in targets]
99 img_size = images[0].shape[:2]
100 images, targets = Scale(img_size, is_flow=self.is_flow, interpolation=self.interpolation)(images, targets)
101 CheckImages()(images, targets)
102 return images, targets
105 class ReverseImageChannels(object):
106 """Reverse the channels fo the tensor. eg. RGB to BGR
107 """
108 def __call__(self, images, targets):
109 def func(imgs, img_idx):
110 imgs = [ImageTransformUtils.reverse_channels(img_plane) for img_plane in imgs] \
111 if isinstance(imgs, list) else ImageTransformUtils.reverse_channels(imgs)
112 return imgs
114 images = ImageTransformUtils.apply_to_list(func, images)
115 # do not apply to targets
116 return images, targets
119 class ConvertToTensor(object):
120 """Converts a numpy.ndarray (H x W x C) to a torch.FloatTensor of shape (C x H x W)."""
121 def __call__(self, images, targets):
122 def func(imgs, img_idx):
123 imgs = [ImageTransformUtils.array_to_tensor(img_plane) for img_plane in imgs] \
124 if isinstance(imgs, list) else ImageTransformUtils.array_to_tensor(imgs)
125 return imgs
127 images = ImageTransformUtils.apply_to_list(func, images)
128 targets = ImageTransformUtils.apply_to_list(func, targets)
129 return images, targets
132 class CenterCrop(object):
133 """Crops the given inputs and target arrays at the center to have a region of
134 the given size. size can be a tuple (target_height, target_width)
135 or an integer, in which case the target will be of a square shape (size, size)
136 Careful, img1 and img2 may not be the same size"""
137 def __init__(self, size):
138 self.size = (int(size), int(size)) if isinstance(size, numbers.Number) else size
140 def __call__(self, images, targets):
141 def func(img, tgt, img_idx):
142 th, tw = self.size
143 h1, w1, _ = img.shape
144 x1 = int(round((w1 - tw) / 2.))
145 y1 = int(round((h1 - th) / 2.))
146 img = img[y1: y1 + th, x1: x1 + tw]
147 tgt = tgt[y1: y1 + th, x1: x1 + tw]
148 return img, tgt
150 images = ImageTransformUtils.apply_to_list(func, images)
151 targets = ImageTransformUtils.apply_to_list(func, targets)
153 return images, targets
156 class ScaleMinSide(object):
157 """ Rescales the inputs and target arrays to the given 'size'.
158 After scaling, 'size' will be the size of the smaller edge.
159 For example, if height > width, then image will be rescaled to (size * height / width, size)"""
160 def __init__(self, size, is_flow=None, interpolation=-1):
161 self.size = size
162 self.is_flow = is_flow
163 self.interpolation = interpolation
165 def __call__(self, images, targets):
166 def func(img, img_idx, interpolation, is_flow):
167 h, w, _ = img.shape
168 if (w <= h and w == self.size) or (h <= w and h == self.size):
169 ratio = 1.0
170 size_out = (h, w)
171 else:
172 if w < h:
173 ratio = self.size / w
174 size_out = (int(round(ratio * h)), self.size)
175 else:
176 ratio = self.size / h
177 size_out = (self.size, int(round(ratio * w)))
178 #
180 img = ImageTransformUtils.resize_img(img, size_out, interpolation=interpolation, is_flow=is_flow)
181 return img
183 def func_img(img, img_idx, interpolation=-1):
184 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
185 return func(img, img_idx, interpolation=interpolation, is_flow=is_flow_img)
187 def func_tgt(img, img_idx):
188 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
189 return func(img, img_idx, interpolation=cv2.INTER_NEAREST, is_flow=is_flow_tgt)
191 images = ImageTransformUtils.apply_to_list(func_img, images, interpolation=self.interpolation)
192 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
194 return images, targets
197 class RandomCrop(object):
198 """Crops the given images"""
199 def __init__(self, size):
200 if isinstance(size, numbers.Number):
201 self.size = (int(size), int(size))
202 else:
203 self.size = size
205 def __call__(self, images, targets):
206 size_h, size_w, _ = images[0].shape
207 th, tw = self.size
208 x1 = np.random.randint(0, size_w - tw) if (size_w>tw) else 0
209 y1 = np.random.randint(0, size_h - th) if (size_h>th) else 0
211 def func(img, img_idx):
212 return img[y1:y1+th, x1:x1+tw]
214 images = ImageTransformUtils.apply_to_list(func, images)
215 targets = ImageTransformUtils.apply_to_list(func, targets)
217 return images, targets
220 class RandomHorizontalFlip(object):
221 """Randomly horizontally flips the given images"""
222 def __init__(self, is_flow=None):
223 self.is_flow = is_flow
225 def __call__(self, images, targets):
226 def func(img, img_idx, is_flow):
227 img = np.copy(np.fliplr(img))
228 if is_flow:
229 img = ImageTransformUtils.scale_flow(img, (-1), 1)
230 return img
232 def func_img(img, img_idx):
233 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
234 img = func(img, img_idx, is_flow_img)
235 return img
237 def func_tgt(img, img_idx):
238 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
239 img = func(img, img_idx, is_flow_tgt)
240 return img
242 if np.random.random() < 0.5:
243 images = ImageTransformUtils.apply_to_list(func_img, images)
244 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
246 return images, targets
249 class RandomVerticalFlip(object):
250 """Randomly horizontally flips the given PIL.Image with a probability of 0.5
251 """
252 def __init__(self, is_flow=None):
253 self.is_flow = is_flow
255 def __call__(self, images, targets):
256 def func(img, img_idx, is_flow):
257 img = np.copy(np.flipud(img))
258 if is_flow:
259 img = ImageTransformUtils.scale_flow(img, 1, (-1))
260 return img
262 def func_img(img, img_idx):
263 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
264 img = func(img, img_idx, is_flow_img)
265 return img
267 def func_tgt(img, img_idx):
268 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
269 img = func(img, img_idx, is_flow_tgt)
270 return img
272 if np.random.random() < 0.5:
273 images = ImageTransformUtils.apply_to_list(func_img, images)
274 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
276 return images, targets
279 class RandomRotate(object):
280 """Random rotation of the image from -angle to angle (in degrees)
281 This is useful for dataAugmentation, especially for geometric problems such as FlowEstimation
282 angle: max angle of the rotation
283 interpolation order: Default: 2 (bilinear)
284 reshape: Default: false. If set to true, image size will be set to keep every pixel in the image.
285 diff_angle: Default: 0. Must stay less than 10 degrees, or linear approximation of flowmap will be off.
286 """
287 def __init__(self, angle, diff_angle=0, is_flow=None):
288 self.angle = angle
289 self.diff_angle = diff_angle #if diff_angle else min(angle/2,10)
290 self.is_flow = is_flow
292 def __call__(self, images, targets):
293 applied_angle = random.uniform(-self.angle,self.angle)
294 is_input_image_pair = (len(images) == 2) and ((self.is_flow == None) or (not np.any(self.is_flow[0])))
295 diff = random.uniform(-self.diff_angle,self.diff_angle) if is_input_image_pair else 0
296 angles = [applied_angle - diff/2, applied_angle + diff/2] if is_input_image_pair else [applied_angle for img in images]
298 def func(img, img_idx, angle, interpolation, is_flow):
299 h, w = img.shape[:2]
300 angle_rad = (angle * np.pi / 180)
302 if is_flow:
303 img = img.astype(np.float32)
304 diff_rad = (diff * np.pi / 180)
305 def rotate_flow(i, j, k):
306 return -k * (j - w / 2) * diff_rad + (1 - k) * (i - h / 2) * diff_rad
307 #
308 rotate_flow_map = np.fromfunction(rotate_flow, img.shape)
309 img += rotate_flow_map
311 img = ImageTransformUtils.rotate_img(img, angle, interpolation)
313 # flow vectors must be rotated too! careful about Y flow which is upside down
314 if is_flow:
315 img = np.copy(img)
316 img[:,:,0] = np.cos(angle_rad)*img[:,:,0] + np.sin(angle_rad)*img[:,:,1]
317 img[:,:,1] = -np.sin(angle_rad)*img[:,:,0] + np.cos(angle_rad)*img[:,:,1]
319 return img
321 def func_img(img, img_idx):
322 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
323 interpolation = (cv2.INTER_NEAREST if is_flow_img else cv2.INTER_LINEAR)
324 img = func(img, img_idx, angles[img_idx], interpolation, is_flow_img)
325 return img
327 def func_tgt(img, img_idx):
328 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
329 interpolation = (cv2.INTER_NEAREST)
330 img = func(img, img_idx, applied_angle, interpolation, is_flow_tgt)
331 return img
333 if np.random.random() < 0.5:
334 images = ImageTransformUtils.apply_to_list(func_img, images)
335 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
337 return images, targets
340 class RandomColorWarp(object):
341 def __init__(self, mean_range=0, std_range=0, is_flow=None):
342 self.mean_range = mean_range
343 self.std_range = std_range
344 self.is_flow = is_flow
346 def __call__(self, images, target):
347 if np.random.random() < 0.5:
348 if self.std_range != 0:
349 random_std = np.random.uniform(-self.std_range, self.std_range, 3)
350 for img_idx in range(len(images)):
351 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
352 if not is_flow_img:
353 images[img_idx] *= (1 + random_std)
355 if self.mean_range != 0:
356 random_mean = np.random.uniform(-self.mean_range, self.mean_range, 3)
357 for img_idx in range(len(images)):
358 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
359 if not is_flow_img:
360 images[img_idx] += random_mean
362 for img_idx in range(len(images)):
363 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
364 if not is_flow_img:
365 random_order = np.random.permutation(3)
366 images[img_idx] = images[img_idx][:,:,random_order]
368 return images, target
371 class RandomColor2Gray(object):
372 def __init__(self, mean_range=0, std_range=0, is_flow=None, random_threshold=0.25):
373 self.mean_range = mean_range
374 self.std_range = std_range
375 self.is_flow = is_flow
376 self.random_threshold = random_threshold
378 def __call__(self, images, target):
379 if np.random.random() < self.random_threshold:
380 for img_idx in range(len(images)):
381 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
382 if not is_flow_img:
383 images[img_idx] = cv2.cvtColor(images[img_idx], cv2.COLOR_RGB2GRAY)
384 images[img_idx] = cv2.cvtColor(images[img_idx], cv2.COLOR_GRAY2RGB)
385 return images, target
388 class RandomScaleCrop(object):
389 """Randomly zooms images up to 15% and crop them to keep same size as before."""
390 def __init__(self, img_resize, scale_range=(1.0,2.0), is_flow=None, center_crop=False, resize_in_yv12=False,
391 interpolation=-1):
392 self.img_resize = img_resize
393 self.scale_range = scale_range
394 self.is_flow = is_flow
395 self.center_crop = center_crop
396 self.resize_in_yv12 = resize_in_yv12
397 self.interpolation = interpolation
399 @staticmethod
400 def get_params(img, img_resize, scale_range, center_crop, resize_in_yv12 = False):
401 in_h, in_w = img.shape[:2]
402 out_h, out_w = img_resize
403 if resize_in_yv12:
404 #to make U,V as multiple of 4 shape to properly represent in YV12 format
405 round_or_align4 = lambda x: ((int(x)//4)*4)
406 else:
407 round_or_align4 = lambda x: round(x)
408 # this random scaling is w.r.t. the output size
409 if (np.random.random() < 0.5):
410 resize_h = int(round_or_align4(np.random.uniform(scale_range[0], scale_range[1]) * out_h))
411 resize_w = int(round_or_align4(np.random.uniform(scale_range[0], scale_range[1]) * out_w))
412 else:
413 resize_h, resize_w = out_h, out_w
415 # crop params w.r.t the scaled size
416 out_r = (resize_h - out_h)//2 if center_crop else np.random.randint(resize_h - out_h + 1)
417 out_c = (resize_w - out_w)//2 if center_crop else np.random.randint(resize_w - out_w + 1)
418 return out_r, out_c, out_h, out_w, resize_h, resize_w
420 def __call__(self, images, targets):
421 out_r, out_c, out_h, out_w, resize_h, resize_w = self.get_params(images[0], self.img_resize, self.scale_range,
422 self.center_crop, resize_in_yv12 = self.resize_in_yv12)
424 def func_img(img, img_idx, interpolation=-1):
425 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
426 img = ImageTransformUtils.resize_and_crop(img, out_r, out_c, out_h, out_w, (resize_h, resize_w),
427 interpolation=interpolation, is_flow=is_flow_img, resize_in_yv12=self.resize_in_yv12)
428 return img
430 def func_tgt(img, img_idx):
431 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
432 img = ImageTransformUtils.resize_and_crop(img, out_r, out_c, out_h, out_w, (resize_h, resize_w),
433 interpolation=cv2.INTER_NEAREST, is_flow=is_flow_tgt)
434 return img
436 images = ImageTransformUtils.apply_to_list(func_img, images, interpolation=self.interpolation)
437 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
438 return images, targets
441 class RandomCropScale(object):
442 """Crop the Image to random size and scale to the given resolution"""
443 def __init__(self, size, crop_range=(0.08, 1.0), is_flow=None, center_crop=False, resize_in_yv12=False,
444 interpolation=-1):
445 self.size = size if (type(size) in (list,tuple)) else (size, size)
446 self.crop_range = crop_range
447 self.is_flow = is_flow
448 self.center_crop = center_crop
449 self.resize_in_yv12 = resize_in_yv12
450 self.interpolation = interpolation
452 @staticmethod
453 def get_params(img, crop_range, center_crop):
454 h_orig = img.shape[0]; w_orig = img.shape[1]
455 r_wh = (w_orig/h_orig)
456 ratio = (r_wh/2.0, 2.0*r_wh)
457 for attempt in range(10):
458 area = h_orig * w_orig
459 target_area = random.uniform(*crop_range) * area
460 aspect_ratio = random.uniform(*ratio)
461 w = int(round(math.sqrt(target_area * aspect_ratio)))
462 h = int(round(math.sqrt(target_area / aspect_ratio)))
463 if (h <= h_orig) and (w <= w_orig):
464 i = (h_orig - h)//2 if center_crop else random.randint(0, h_orig - h)
465 j = (w_orig - w)//2 if center_crop else random.randint(0, w_orig - w)
466 return i, j, h, w
468 # Fallback: entire image
469 return 0, 0, h_orig, w_orig
471 def __call__(self, images, targets):
472 out_r, out_c, out_h, out_w = self.get_params(images[0], self.crop_range, self.center_crop)
474 def func_img(img, img_idx, interpolation=-1):
475 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
476 img = ImageTransformUtils.crop_and_resize(img, out_r, out_c, out_h, out_w, self.size,
477 interpolation=interpolation, is_flow=is_flow_img, resize_in_yv12=self.resize_in_yv12)
478 return img
480 def func_tgt(img, img_idx):
481 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
482 img = ImageTransformUtils.crop_and_resize(img, out_r, out_c, out_h, out_w, self.size,
483 interpolation=cv2.INTER_NEAREST, is_flow=is_flow_tgt)
484 return img
486 images = ImageTransformUtils.apply_to_list(func_img, images, interpolation=self.interpolation)
487 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
489 return images, targets
492 class Scale(object):
493 def __init__(self, img_size, target_size=None, is_flow=None, interpolation=-1):
494 self.img_size = img_size
495 self.target_size = target_size if target_size else img_size
496 self.is_flow = is_flow
497 self.interpolation = interpolation
499 def __call__(self, images, targets):
500 if self.img_size is None:
501 return images, targets
503 def func_img(img, img_idx, interpolation=-1):
504 is_flow_img = (self.is_flow[0][img_idx] if self.is_flow else self.is_flow)
505 img = ImageTransformUtils.resize_img(img, self.img_size, interpolation=interpolation, is_flow=is_flow_img)
506 return img
508 def func_tgt(img, img_idx):
509 is_flow_tgt = (self.is_flow[1][img_idx] if self.is_flow else self.is_flow)
510 img = ImageTransformUtils.resize_img(img, self.target_size, interpolation=cv2.INTER_NEAREST, is_flow=is_flow_tgt)
511 return img
513 images = ImageTransformUtils.apply_to_list(func_img, images, interpolation=self.interpolation)
514 targets = ImageTransformUtils.apply_to_list(func_tgt, targets)
516 return images, targets
519 class CropRect(object):
520 def __init__(self, crop_rect):
521 self.crop_rect = crop_rect
523 def __call__(self, images, targets):
524 if self.crop_rect is None:
525 return images, targets
527 def func(img, tgt, img_idx):
528 img_size = img.shape
529 crop_rect = self.crop_rect
530 max_val = max(crop_rect)
531 t, l, h, w = crop_rect
532 if max_val <= 1: # convert float into integer
533 t = int(t * img_size[0] + 0.5) # top
534 l = int(l * img_size[1] + 0.5) # left
535 h = int(h * img_size[0] + 0.5) # height
536 w = int(w * img_size[1] + 0.5) # width
537 else:
538 t = int(t) # top
539 l = int(l) # left
540 h = int(h) # height
541 w = int(w) # width
543 img = img[t:(t+h), l:(l+w)]
544 tgt = tgt[t:(t+h), l:(l+w)]
546 return img, tgt
548 images, targets = ImageTransformUtils.apply_to_lists(func, images, targets)
550 return images, targets
553 class MaskTarget(object):
554 def __init__(self, mask_rect, mask_val):
555 self.mask_rect = mask_rect
556 self.mask_val = mask_val
558 def __call__(self, images, targets):
559 if self.mask_rect is None:
560 return images, targets
562 def func(img, tgt, img_idx):
563 img_size = img.shape
564 crop_rect = self.mask_rect
565 max_val = max(crop_rect)
566 t, l, h, w = crop_rect
567 if max_val <= 1: # convert float into integer
568 t = int(t * img_size[0] + 0.5) # top
569 l = int(l * img_size[1] + 0.5) # left
570 h = int(h * img_size[0] + 0.5) # height
571 w = int(w * img_size[1] + 0.5) # width
572 else:
573 t = int(t) # top
574 l = int(l) # left
575 h = int(h) # height
576 w = int(w) # width
578 tgt[t:(t+h), l:(l+w)] = self.mask_val
579 return img, tgt
581 images = ImageTransformUtils.apply_to_list(func, images)
582 targets = ImageTransformUtils.apply_to_list(func, targets)
584 return images, targets
587 class NormalizeMeanStd(object):
588 def __init__(self, mean, std):
589 self.mean = mean
590 self.std = std
592 def __call__(self, images, target):
593 if isinstance(images, (list,tuple)):
594 images = [(img-self.mean)/self.std for img in images]
595 else:
596 images = (images-self.mean)/self.std
598 return images, target
601 class NormalizeMeanScale(object):
602 def __init__(self, mean, scale):
603 self.mean = mean
604 self.scale = scale
607 def __call__(self, images, target):
608 def func(imgs, img_idx):
609 if isinstance(imgs, (list,tuple)):
610 imgs = [(img-self.mean)*self.scale for img in imgs]
611 else:
612 imgs = (imgs-self.mean)*self.scale
613 #
614 return imgs
615 #
616 images = ImageTransformUtils.apply_to_list(func, images) \
617 if isinstance(images, (list,tuple)) else func(images)
618 return images, target