python-wml 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-wml might be problematic. Click here for more details.

Files changed (164) hide show
  1. python_wml-3.0.0.dist-info/LICENSE +23 -0
  2. python_wml-3.0.0.dist-info/METADATA +51 -0
  3. python_wml-3.0.0.dist-info/RECORD +164 -0
  4. python_wml-3.0.0.dist-info/WHEEL +5 -0
  5. python_wml-3.0.0.dist-info/top_level.txt +1 -0
  6. wml/__init__.py +0 -0
  7. wml/basic_data_def/__init__.py +2 -0
  8. wml/basic_data_def/detection_data_def.py +279 -0
  9. wml/basic_data_def/io_data_def.py +2 -0
  10. wml/basic_img_utils.py +816 -0
  11. wml/img_patch.py +92 -0
  12. wml/img_utils.py +571 -0
  13. wml/iotoolkit/__init__.py +17 -0
  14. wml/iotoolkit/aic_keypoint.py +115 -0
  15. wml/iotoolkit/baidu_mask_toolkit.py +244 -0
  16. wml/iotoolkit/base_dataset.py +210 -0
  17. wml/iotoolkit/bboxes_statistics.py +515 -0
  18. wml/iotoolkit/build.py +0 -0
  19. wml/iotoolkit/cityscapes_toolkit.py +183 -0
  20. wml/iotoolkit/classification_data_statistics.py +25 -0
  21. wml/iotoolkit/coco_data_fwd.py +225 -0
  22. wml/iotoolkit/coco_keypoints.py +118 -0
  23. wml/iotoolkit/coco_keypoints_fmt2.py +103 -0
  24. wml/iotoolkit/coco_toolkit.py +397 -0
  25. wml/iotoolkit/coco_wholebody.py +269 -0
  26. wml/iotoolkit/common.py +108 -0
  27. wml/iotoolkit/crowd_pose.py +146 -0
  28. wml/iotoolkit/fast_labelme.py +110 -0
  29. wml/iotoolkit/image_folder.py +95 -0
  30. wml/iotoolkit/imgs_cache.py +58 -0
  31. wml/iotoolkit/imgs_reader_mt.py +73 -0
  32. wml/iotoolkit/labelme_base.py +102 -0
  33. wml/iotoolkit/labelme_json_to_img.py +49 -0
  34. wml/iotoolkit/labelme_toolkit.py +117 -0
  35. wml/iotoolkit/labelme_toolkit_fwd.py +733 -0
  36. wml/iotoolkit/labelmemckeypoints_dataset.py +169 -0
  37. wml/iotoolkit/lspet.py +48 -0
  38. wml/iotoolkit/mapillary_vistas_toolkit.py +269 -0
  39. wml/iotoolkit/mat_data.py +90 -0
  40. wml/iotoolkit/mckeypoints_statistics.py +28 -0
  41. wml/iotoolkit/mot_datasets.py +62 -0
  42. wml/iotoolkit/mpii.py +108 -0
  43. wml/iotoolkit/npmckeypoints_dataset.py +164 -0
  44. wml/iotoolkit/o365_to_coco.py +136 -0
  45. wml/iotoolkit/object365_toolkit.py +156 -0
  46. wml/iotoolkit/object365v2_toolkit.py +71 -0
  47. wml/iotoolkit/pascal_voc_data.py +51 -0
  48. wml/iotoolkit/pascal_voc_toolkit.py +194 -0
  49. wml/iotoolkit/pascal_voc_toolkit_fwd.py +473 -0
  50. wml/iotoolkit/penn_action.py +57 -0
  51. wml/iotoolkit/rawframe_dataset.py +129 -0
  52. wml/iotoolkit/rewrite_pascal_voc.py +28 -0
  53. wml/iotoolkit/semantic_data.py +49 -0
  54. wml/iotoolkit/split_file_by_type.py +29 -0
  55. wml/iotoolkit/sports_mot_datasets.py +78 -0
  56. wml/iotoolkit/vis_objectdetection_dataset.py +70 -0
  57. wml/iotoolkit/vis_torch_data.py +39 -0
  58. wml/iotoolkit/yolo_toolkit.py +38 -0
  59. wml/object_detection2/__init__.py +4 -0
  60. wml/object_detection2/basic_visualization.py +37 -0
  61. wml/object_detection2/bboxes.py +812 -0
  62. wml/object_detection2/data_process_toolkit.py +146 -0
  63. wml/object_detection2/keypoints.py +292 -0
  64. wml/object_detection2/mask.py +120 -0
  65. wml/object_detection2/metrics/__init__.py +3 -0
  66. wml/object_detection2/metrics/build.py +15 -0
  67. wml/object_detection2/metrics/classifier_toolkit.py +440 -0
  68. wml/object_detection2/metrics/common.py +71 -0
  69. wml/object_detection2/metrics/mckps_toolkit.py +338 -0
  70. wml/object_detection2/metrics/toolkit.py +1953 -0
  71. wml/object_detection2/npod_toolkit.py +361 -0
  72. wml/object_detection2/odtools.py +243 -0
  73. wml/object_detection2/standard_names.py +75 -0
  74. wml/object_detection2/visualization.py +956 -0
  75. wml/object_detection2/wmath.py +34 -0
  76. wml/semantic/__init__.py +0 -0
  77. wml/semantic/basic_toolkit.py +65 -0
  78. wml/semantic/mask_utils.py +156 -0
  79. wml/semantic/semantic_test.py +21 -0
  80. wml/semantic/structures.py +1 -0
  81. wml/semantic/toolkit.py +105 -0
  82. wml/semantic/visualization_utils.py +658 -0
  83. wml/threadtoolkit.py +50 -0
  84. wml/walgorithm.py +228 -0
  85. wml/wcollections.py +212 -0
  86. wml/wfilesystem.py +487 -0
  87. wml/wml_utils.py +657 -0
  88. wml/wstructures/__init__.py +4 -0
  89. wml/wstructures/common.py +9 -0
  90. wml/wstructures/keypoints_train_toolkit.py +149 -0
  91. wml/wstructures/kps_structures.py +579 -0
  92. wml/wstructures/mask_structures.py +1161 -0
  93. wml/wtorch/__init__.py +8 -0
  94. wml/wtorch/bboxes.py +104 -0
  95. wml/wtorch/classes_suppression.py +24 -0
  96. wml/wtorch/conv_module.py +181 -0
  97. wml/wtorch/conv_ws.py +144 -0
  98. wml/wtorch/data/__init__.py +16 -0
  99. wml/wtorch/data/_utils/__init__.py +45 -0
  100. wml/wtorch/data/_utils/collate.py +183 -0
  101. wml/wtorch/data/_utils/fetch.py +47 -0
  102. wml/wtorch/data/_utils/pin_memory.py +121 -0
  103. wml/wtorch/data/_utils/signal_handling.py +72 -0
  104. wml/wtorch/data/_utils/worker.py +227 -0
  105. wml/wtorch/data/base_data_loader_iter.py +93 -0
  106. wml/wtorch/data/dataloader.py +501 -0
  107. wml/wtorch/data/datapipes/__init__.py +1 -0
  108. wml/wtorch/data/datapipes/iter/__init__.py +12 -0
  109. wml/wtorch/data/datapipes/iter/batch.py +126 -0
  110. wml/wtorch/data/datapipes/iter/callable.py +92 -0
  111. wml/wtorch/data/datapipes/iter/listdirfiles.py +37 -0
  112. wml/wtorch/data/datapipes/iter/loadfilesfromdisk.py +30 -0
  113. wml/wtorch/data/datapipes/iter/readfilesfromtar.py +60 -0
  114. wml/wtorch/data/datapipes/iter/readfilesfromzip.py +63 -0
  115. wml/wtorch/data/datapipes/iter/sampler.py +94 -0
  116. wml/wtorch/data/datapipes/utils/__init__.py +0 -0
  117. wml/wtorch/data/datapipes/utils/common.py +65 -0
  118. wml/wtorch/data/dataset.py +354 -0
  119. wml/wtorch/data/datasets/__init__.py +4 -0
  120. wml/wtorch/data/datasets/common.py +53 -0
  121. wml/wtorch/data/datasets/listdirfilesdataset.py +36 -0
  122. wml/wtorch/data/datasets/loadfilesfromdiskdataset.py +30 -0
  123. wml/wtorch/data/distributed.py +135 -0
  124. wml/wtorch/data/multi_processing_data_loader_iter.py +866 -0
  125. wml/wtorch/data/sampler.py +267 -0
  126. wml/wtorch/data/single_process_data_loader_iter.py +24 -0
  127. wml/wtorch/data/test_data_loader.py +26 -0
  128. wml/wtorch/dataset_toolkit.py +67 -0
  129. wml/wtorch/depthwise_separable_conv_module.py +98 -0
  130. wml/wtorch/dist.py +591 -0
  131. wml/wtorch/dropblock/__init__.py +6 -0
  132. wml/wtorch/dropblock/dropblock.py +228 -0
  133. wml/wtorch/dropblock/dropout.py +40 -0
  134. wml/wtorch/dropblock/scheduler.py +48 -0
  135. wml/wtorch/ema.py +61 -0
  136. wml/wtorch/fc_module.py +73 -0
  137. wml/wtorch/functional.py +34 -0
  138. wml/wtorch/iter_dataset.py +26 -0
  139. wml/wtorch/loss.py +69 -0
  140. wml/wtorch/nets/__init__.py +0 -0
  141. wml/wtorch/nets/ckpt_toolkit.py +219 -0
  142. wml/wtorch/nets/fpn.py +276 -0
  143. wml/wtorch/nets/hrnet/__init__.py +0 -0
  144. wml/wtorch/nets/hrnet/config.py +2 -0
  145. wml/wtorch/nets/hrnet/hrnet.py +494 -0
  146. wml/wtorch/nets/misc.py +249 -0
  147. wml/wtorch/nets/resnet/__init__.py +0 -0
  148. wml/wtorch/nets/resnet/layers/__init__.py +17 -0
  149. wml/wtorch/nets/resnet/layers/aspp.py +144 -0
  150. wml/wtorch/nets/resnet/layers/batch_norm.py +231 -0
  151. wml/wtorch/nets/resnet/layers/blocks.py +111 -0
  152. wml/wtorch/nets/resnet/layers/wrappers.py +110 -0
  153. wml/wtorch/nets/resnet/r50_config.py +38 -0
  154. wml/wtorch/nets/resnet/resnet.py +691 -0
  155. wml/wtorch/nets/shape_spec.py +20 -0
  156. wml/wtorch/nets/simple_fpn.py +101 -0
  157. wml/wtorch/nms.py +109 -0
  158. wml/wtorch/nn.py +896 -0
  159. wml/wtorch/ocr_block.py +193 -0
  160. wml/wtorch/summary.py +331 -0
  161. wml/wtorch/train_toolkit.py +603 -0
  162. wml/wtorch/transformer_blocks.py +266 -0
  163. wml/wtorch/utils.py +719 -0
  164. wml/wtorch/wlr_scheduler.py +100 -0
wml/basic_img_utils.py ADDED
@@ -0,0 +1,816 @@
1
+ import numpy as np
2
+ from collections import OrderedDict, Iterable
3
+ import copy
4
+ import cv2
5
+ import math
6
+ import wml.walgorithm as wa
7
+
8
+ BASE_IMG_SUFFIX=".jpg;;.jpeg;;.bmp;;.png;;.gif;;.tif"
9
+
10
+
11
+ def normal_image(image,min_v=0,max_v=255,dtype=np.uint8):
12
+
13
+ if not isinstance(image,np.ndarray):
14
+ image = np.array(image)
15
+
16
+ t = image.dtype
17
+ if t!=np.float32:
18
+ image = image.astype(np.float32)
19
+
20
+ i_min = np.min(image)
21
+ i_max = np.max(image)
22
+ image = (image-float(i_min))*float(max_v-min_v)/max(float(i_max-i_min),1e-8)+float(min_v)
23
+
24
+ if dtype!=np.float32:
25
+ image = image.astype(dtype)
26
+
27
+ return image
28
+
29
+
30
+ def _get_translate_matrix(offset, direction='horizontal'):
31
+ """Generate the translate matrix.
32
+
33
+ Args:
34
+ offset (int | float): The offset used for translate.
35
+ direction (str): The translate direction, either
36
+ "horizontal" or "vertical".
37
+
38
+ Returns:
39
+ ndarray: The translate matrix with dtype float32.
40
+ """
41
+ if direction == 'horizontal':
42
+ translate_matrix = np.float32([[1, 0, offset], [0, 1, 0]])
43
+ elif direction == 'vertical':
44
+ translate_matrix = np.float32([[1, 0, 0], [0, 1, offset]])
45
+ return translate_matrix
46
+
47
+ def _get_shear_matrix(magnitude, direction='horizontal'):
48
+ """Generate the shear matrix for transformation.
49
+
50
+ Args:
51
+ magnitude (int | float): The magnitude used for shear.
52
+ direction (str): The flip direction, either "horizontal"
53
+ or "vertical".
54
+
55
+ Returns:
56
+ ndarray: The shear matrix with dtype float32.
57
+ """
58
+ if direction == 'horizontal':
59
+ shear_matrix = np.float32([[1, magnitude, 0], [0, 1, 0]])
60
+ elif direction == 'vertical':
61
+ shear_matrix = np.float32([[1, 0, 0], [magnitude, 1, 0]])
62
+ return shear_matrix
63
+
64
+ cv2_interp_codes = {
65
+ 'nearest': cv2.INTER_NEAREST,
66
+ 'bilinear': cv2.INTER_LINEAR,
67
+ 'bicubic': cv2.INTER_CUBIC,
68
+ 'area': cv2.INTER_AREA,
69
+ 'lanczos': cv2.INTER_LANCZOS4
70
+ }
71
+
72
+ '''
73
+ box:ymin,xmin,ymax,xmax, absolute corrdinate
74
+ '''
75
+ def crop_img_absolute(img,box):
76
+ shape = img.shape
77
+ box = np.array(box)
78
+ box[0:4:2] = np.minimum(box[0:4:2],shape[0])
79
+ box[1:4:2] = np.minimum(box[1:4:2],shape[1])
80
+ box = np.maximum(box,0)
81
+ ymin = box[0]
82
+ ymax = box[2]
83
+ xmin = box[1]
84
+ xmax = box[3]
85
+ if len(shape)==2:
86
+ return img[ymin:ymax,xmin:xmax]
87
+ else:
88
+ return img[ymin:ymax,xmin:xmax,:]
89
+ '''
90
+ box:xmin,ymin,xmax,ymax, absolute corrdinate
91
+ img:[H,W,C]
92
+ '''
93
+ def crop_img_absolute_xy(img,box):
94
+ shape = img.shape
95
+ box = np.array(box)
96
+ box[0:4:2] = np.minimum(box[0:4:2],shape[1])
97
+ box[1:4:2] = np.minimum(box[1:4:2],shape[0])
98
+ box = np.maximum(box,0)
99
+ ymin = box[1]
100
+ ymax = box[3]
101
+ xmin = box[0]
102
+ xmax = box[2]
103
+ return img[ymin:ymax,xmin:xmax]
104
+
105
+ '''
106
+ box:ymin,xmin,ymax,xmax, relative corrdinate
107
+ '''
108
+ def crop_img(img,box):
109
+ shape = img.shape
110
+ box = np.array(box)
111
+ box = np.minimum(box,1.0)
112
+ box = np.maximum(box,0.0)
113
+ ymin = int((shape[0])*box[0]+0.5)
114
+ ymax = int((shape[0])*box[2]+1+0.5)
115
+ xmin = int((shape[1])*box[1]+0.5)
116
+ xmax = int((shape[1])*box[3]+1+0.5)
117
+ if len(shape)==2:
118
+ return img[ymin:ymax,xmin:xmax]
119
+ else:
120
+ return img[ymin:ymax,xmin:xmax,:]
121
+
122
+
123
+ '''
124
+ box:xmin,ymin,xmax,ymax, absolute corrdinate
125
+ img: [B,C,H,W]
126
+ '''
127
+ def crop_batch_img_absolute_xy(img,box):
128
+ shape = img.shape
129
+ box = np.array(box)
130
+ box[0:4:2] = np.minimum(box[0:4:2],shape[-1])
131
+ box[1:4:2] = np.minimum(box[1:4:2],shape[-2])
132
+ box = np.maximum(box,0)
133
+ ymin = box[1]
134
+ ymax = box[3]
135
+ xmin = box[0]
136
+ xmax = box[2]
137
+ return img[:,:,ymin:ymax,xmin:xmax]
138
+
139
+ def set_subimg(img,sub_img,p0):
140
+ '''
141
+ p0:(x,y)
142
+ '''
143
+ img[p0[1]:p0[1]+sub_img.shape[0],p0[0]:p0[0]+sub_img.shape[1]] = sub_img
144
+
145
+ return img
146
+
147
+ '''
148
+ box:xmin,ymin,xmax,ymax, absolute corrdinate
149
+ size: (w,h)
150
+ '''
151
+ def crop_and_pad(img,bbox,size=None,pad_color=127):
152
+ if size is None:
153
+ size = (bbox[2]-bbox[0],bbox[3]-bbox[1])
154
+ img = crop_img_absolute_xy(img,bbox)
155
+ channels = img.shape[-1]
156
+ if img.shape[0]<size[1] or img.shape[1]<size[0]:
157
+ res = np.ones([size[1],size[0],3],dtype=img.dtype)
158
+ if not isinstance(pad_color,Iterable):
159
+ pad_color = (pad_color,)*channels
160
+ pad_color = np.array(list(pad_color),dtype=img.dtype)
161
+ pad_color = pad_color.reshape([1,1,channels])
162
+ res = res*pad_color
163
+ offset_x = 0
164
+ offset_y = 0
165
+
166
+ w = img.shape[1]
167
+ h = img.shape[0]
168
+ res[offset_y:offset_y+h,offset_x:offset_x+w,:] = img
169
+ return res
170
+ else:
171
+ return img
172
+
173
+ def align_pad(img,align=32,value=127):
174
+ size = list(img.shape)
175
+ size[0] = (size[0]+align-1)//align*align
176
+ size[1] = (size[1]+align-1)//align*align
177
+
178
+ res = np.ones([size[0],size[1],3],dtype=img.dtype)*value
179
+ w = img.shape[1]
180
+ h = img.shape[0]
181
+ res[:h,:w,:] = img
182
+
183
+ return res
184
+
185
+
186
+ '''
187
+ box:ymin,xmin,ymax,xmax, absolute corrdinate
188
+ mask: [NR,H,W]
189
+ '''
190
+ def crop_masks_absolute(masks,box):
191
+ shape = masks.shape[1:]
192
+ box = np.array(box)
193
+ box[0:4:2] = np.minimum(box[0:4:2],shape[0])
194
+ box[1:4:2] = np.minimum(box[1:4:2],shape[1])
195
+ box = np.maximum(box,0)
196
+ ymin = box[0]
197
+ ymax = box[2]
198
+ xmin = box[1]
199
+ xmax = box[3]
200
+ return masks[:,ymin:ymax,xmin:xmax]
201
+
202
+ '''
203
+ box:xmin,ymin,xmax,ymax, absolute corrdinate
204
+ mask: [NR,H,W]
205
+ '''
206
+ def crop_masks_absolute_xy(img,box):
207
+ new_box = [box[1],box[0],box[3],box[2]]
208
+ return crop_masks_absolute(img,new_box)
209
+
210
+ '''
211
+ img:[H,W]/[H,W,C]
212
+ rect:[ymin,xmin,ymax,xmax] absolute coordinate
213
+ 与crop_img类似,但如果rect超出img边界会先pad再剪切
214
+ '''
215
+ def sub_image(img,rect,pad_value=127):
216
+ if rect[0]<0 or rect[1]<0 or rect[2]>img.shape[0] or rect[3]>img.shape[1]:
217
+ py0 = -rect[0] if rect[0]<0 else 0
218
+ py1 = rect[2]-img.shape[0] if rect[2]>img.shape[0] else 0
219
+ px0 = -rect[1] if rect[1] < 0 else 0
220
+ px1 = rect[3] - img.shape[1] if rect[3] > img.shape[1] else 0
221
+ img = np.pad(img,[[py0,py1],[px0,px1],[0,0]],constant_values=pad_value)
222
+ rect[0] += py0
223
+ rect[1] += px0
224
+ rect[2] += py0
225
+ rect[3] += px0
226
+
227
+ return copy.deepcopy(img[rect[0]:rect[2],rect[1]:rect[3]])
228
+
229
+ '''
230
+ img:[H,W]/[H,W,C]
231
+ rect:[N,4] [ymin,xmin,ymax,xmax] absolute coordinate
232
+ '''
233
+ def sub_images(img,rects):
234
+ res = []
235
+ for rect in rects:
236
+ res.append(sub_image(img,rect))
237
+
238
+ return res
239
+ '''
240
+ img:[H,W]/[H,W,C]
241
+ rect:[xmin,ymin,xmax,ymax] absolute coordinate
242
+ '''
243
+ def sub_imagev2(img,rect,pad_value=127):
244
+ return sub_image(img,[rect[1],rect[0],rect[3],rect[2]],pad_value=pad_value)
245
+
246
+ '''
247
+ img: [H,W,C]
248
+ size: [w,h]
249
+ '''
250
+ def center_crop(img,size,pad_value=127):
251
+ cx = img.shape[1]//2
252
+ cy = img.shape[0]//2
253
+ x0 = cx-size[0]//2
254
+ y0 = cy-size[1]//2
255
+ x1 = x0+size[0]
256
+ y1 = y0+size[1]
257
+ return sub_image(img,[y0,x0,y1,x1],pad_value=pad_value)
258
+
259
+ def past_img(dst_img,src_img,pos):
260
+ '''
261
+ dst_img: [H,W,C]
262
+ src_img: [h,w,C]
263
+ pos: [x,y], 粘贴区域的左上角
264
+ '''
265
+ x,y = pos
266
+ dst_img[y:y+src_img.shape[0],x:x+src_img.shape[1]] = src_img
267
+ return dst_img
268
+
269
+ def crop_and_past_img(dst_img,src_img,src_bbox,pos):
270
+ '''
271
+ src_box:xmin,ymin,xmax,ymax, absolute corrdinate
272
+ pos: [x,y], 粘贴区域的左上角
273
+ '''
274
+ src_img = crop_img_absolute_xy(src_img,src_bbox)
275
+ return past_img(dst_img,src_img,pos)
276
+
277
+ def imrotate(img,
278
+ angle,
279
+ center=None,
280
+ scale=1.0,
281
+ border_value=0,
282
+ interpolation='bilinear',
283
+ auto_bound=False):
284
+ """Rotate an image.
285
+
286
+ Args:
287
+ img (ndarray): Image to be rotated.
288
+ angle (float): Rotation angle in degrees, positive values mean
289
+ clockwise rotation.
290
+ center (tuple[float], optional): Center point (w, h) of the rotation in
291
+ the source image. If not specified, the center of the image will be
292
+ used.
293
+ scale (float): Isotropic scale factor.
294
+ border_value (int): Border value.
295
+ interpolation (str): Same as :func:`resize`.
296
+ auto_bound (bool): Whether to adjust the image size to cover the whole
297
+ rotated image.
298
+
299
+ Returns:
300
+ ndarray: The rotated image.
301
+ """
302
+ if center is not None and auto_bound:
303
+ raise ValueError('`auto_bound` conflicts with `center`')
304
+ h, w = img.shape[:2]
305
+ if center is None:
306
+ center = ((w - 1) * 0.5, (h - 1) * 0.5)
307
+ assert isinstance(center, tuple)
308
+
309
+ matrix = cv2.getRotationMatrix2D(center, -angle, scale)
310
+ if auto_bound:
311
+ cos = np.abs(matrix[0, 0])
312
+ sin = np.abs(matrix[0, 1])
313
+ new_w = h * sin + w * cos
314
+ new_h = h * cos + w * sin
315
+ matrix[0, 2] += (new_w - w) * 0.5
316
+ matrix[1, 2] += (new_h - h) * 0.5
317
+ w = int(np.round(new_w))
318
+ h = int(np.round(new_h))
319
+ rotated = cv2.warpAffine(
320
+ img,
321
+ matrix, (w, h),
322
+ flags=cv2_interp_codes[interpolation],
323
+ borderValue=border_value)
324
+ return rotated
325
+
326
+ def imtranslate(img,
327
+ offset,
328
+ direction='horizontal',
329
+ border_value=0,
330
+ interpolation='bilinear'):
331
+ """Translate an image.
332
+
333
+ Args:
334
+ img (ndarray): Image to be translated with format
335
+ (h, w) or (h, w, c).
336
+ offset (int | float): The offset used for translate.
337
+ direction (str): The translate direction, either "horizontal"
338
+ or "vertical".
339
+ border_value (int | tuple[int]): Value used in case of a
340
+ constant border.
341
+ interpolation (str): Same as :func:`resize`.
342
+
343
+ Returns:
344
+ ndarray: The translated image.
345
+ """
346
+ assert direction in ['horizontal',
347
+ 'vertical'], f'Invalid direction: {direction}'
348
+ height, width = img.shape[:2]
349
+ if img.ndim == 2:
350
+ channels = 1
351
+ elif img.ndim == 3:
352
+ channels = img.shape[-1]
353
+ if isinstance(border_value, int):
354
+ border_value = tuple([border_value] * channels)
355
+ elif isinstance(border_value, tuple):
356
+ assert len(border_value) == channels, \
357
+ 'Expected the num of elements in tuple equals the channels' \
358
+ 'of input image. Found {} vs {}'.format(
359
+ len(border_value), channels)
360
+ else:
361
+ raise ValueError(
362
+ f'Invalid type {type(border_value)} for `border_value`.')
363
+ translate_matrix = _get_translate_matrix(offset, direction)
364
+ translated = cv2.warpAffine(
365
+ img,
366
+ translate_matrix,
367
+ (width, height),
368
+ # Note case when the number elements in `border_value`
369
+ # greater than 3 (e.g. translating masks whose channels
370
+ # large than 3) will raise TypeError in `cv2.warpAffine`.
371
+ # Here simply slice the first 3 values in `border_value`.
372
+ borderValue=border_value[:3],
373
+ flags=cv2_interp_codes[interpolation])
374
+ return translated
375
+
376
+ def imshear(img,
377
+ magnitude,
378
+ direction='horizontal',
379
+ border_value=0,
380
+ interpolation='bilinear'):
381
+ """Shear an image.
382
+
383
+ Args:
384
+ img (ndarray): Image to be sheared with format (h, w)
385
+ or (h, w, c).
386
+ magnitude (int | float): The magnitude used for shear.
387
+ direction (str): The flip direction, either "horizontal"
388
+ or "vertical".
389
+ border_value (int | tuple[int]): Value used in case of a
390
+ constant border.
391
+ interpolation (str): Same as :func:`resize`.
392
+
393
+ Returns:
394
+ ndarray: The sheared image.
395
+ """
396
+ assert direction in ['horizontal',
397
+ 'vertical'], f'Invalid direction: {direction}'
398
+ height, width = img.shape[:2]
399
+ if img.ndim == 2:
400
+ channels = 1
401
+ elif img.ndim == 3:
402
+ channels = img.shape[-1]
403
+ if isinstance(border_value, int):
404
+ border_value = tuple([border_value] * channels)
405
+ elif isinstance(border_value, tuple):
406
+ assert len(border_value) == channels, \
407
+ 'Expected the num of elements in tuple equals the channels' \
408
+ 'of input image. Found {} vs {}'.format(
409
+ len(border_value), channels)
410
+ else:
411
+ raise ValueError(
412
+ f'Invalid type {type(border_value)} for `border_value`')
413
+ shear_matrix = _get_shear_matrix(magnitude, direction)
414
+ sheared = cv2.warpAffine(
415
+ img,
416
+ shear_matrix,
417
+ (width, height),
418
+ # Note case when the number elements in `border_value`
419
+ # greater than 3 (e.g. shearing masks whose channels large
420
+ # than 3) will raise TypeError in `cv2.warpAffine`.
421
+ # Here simply slice the first 3 values in `border_value`.
422
+ borderValue=border_value[:3],
423
+ flags=cv2_interp_codes[interpolation])
424
+ return sheared
425
+
426
+ def im_warp_affine(img,
427
+ M,
428
+ border_value=0,
429
+ interpolation='bilinear',
430
+ out_shape = None,
431
+ ):
432
+ '''
433
+ out_shape:[W,H]
434
+ '''
435
+ if out_shape is None:
436
+ h,w = img.shape[:2]
437
+ out_shape = (w,h)
438
+ rotated = cv2.warpAffine(
439
+ img,
440
+ M, out_shape,
441
+ flags=cv2_interp_codes[interpolation],
442
+ borderValue=border_value)
443
+ return rotated
444
+
445
+ def imflip(img, direction='horizontal'):
446
+ """Flip an image horizontally or vertically.
447
+
448
+ Args:
449
+ img (ndarray): Image to be flipped.
450
+ direction (str): The flip direction, either "horizontal" or
451
+ "vertical" or "diagonal".
452
+
453
+ Returns:
454
+ ndarray: The flipped image.
455
+ """
456
+ assert direction in ['horizontal', 'vertical', 'diagonal']
457
+ if direction == 'horizontal':
458
+ return np.flip(img, axis=1)
459
+ elif direction == 'vertical':
460
+ return np.flip(img, axis=0)
461
+ else:
462
+ return np.flip(img, axis=(0, 1))
463
+
464
+
465
+ '''
466
+ size:(w,h)
467
+ return:
468
+ resized img, resized_img.size <= size
469
+ '''
470
+ def resize_img(img,size,keep_aspect_ratio=False,interpolation=cv2.INTER_LINEAR,align=None):
471
+
472
+ img_shape = img.shape
473
+ if size[0] == img.shape[1] and size[1]==img.shape[0]:
474
+ return img
475
+
476
+ if np.any(np.array(img_shape)==0):
477
+ img_shape = list(img_shape)
478
+ img_shape[0] = size[1]
479
+ img_shape[1] = size[0]
480
+ return np.zeros(img_shape,dtype=img.dtype)
481
+ if keep_aspect_ratio:
482
+ if size[1]*img_shape[1] != size[0]*img_shape[0]:
483
+ if size[1]*img_shape[1]>size[0]*img_shape[0]:
484
+ ratio = size[0]/img_shape[1]
485
+ else:
486
+ ratio = size[1]/img_shape[0]
487
+ size = list(copy.deepcopy(size))
488
+ size[0] = int(img_shape[1]*ratio)
489
+ size[1] = int(img_shape[0]*ratio)
490
+
491
+ if align:
492
+ size[0] = (size[0]+align-1)//align*align
493
+ size[1] = (size[1] + align - 1) // align * align
494
+
495
+ if not isinstance(size,tuple):
496
+ size = tuple(size)
497
+ if size[0]==img_shape[0] and size[1]==img_shape[1]:
498
+ return img
499
+
500
+ img = cv2.resize(img,dsize=size,interpolation=interpolation)
501
+
502
+ if len(img_shape)==3 and len(img.shape)==2:
503
+ img = np.expand_dims(img,axis=-1)
504
+
505
+ return img
506
+
507
+ def resize_imgv2(img,size,interpolation=cv2.INTER_LINEAR,return_scale=False,align=None):
508
+ '''
509
+ size: (w,h)
510
+ '''
511
+ old_shape = img.shape
512
+ img = resize_img(img,size,keep_aspect_ratio=True,interpolation=interpolation)
513
+
514
+ if return_scale:
515
+ r = img.shape[0]/max(old_shape[0],1)
516
+
517
+ if align is not None:
518
+ img = align_pad(img,align=align)
519
+
520
+ if return_scale:
521
+ return img,r
522
+ else:
523
+ return img
524
+
525
+ def resize_imgv3(img,size,interpolation=cv2.INTER_LINEAR,return_scale=False,align=None,keep_aspect_ratio=True):
526
+ '''
527
+ size: (w,h)
528
+ '''
529
+ old_shape = img.shape
530
+ img = resize_img(img,size,keep_aspect_ratio=keep_aspect_ratio,interpolation=interpolation)
531
+
532
+ if return_scale:
533
+ r = (img.shape[1]/max(old_shape[1],1),img.shape[0]/max(old_shape[0],1)) #(w,h) scale
534
+
535
+ if align is not None:
536
+ img = align_pad(img,align=align)
537
+
538
+ if return_scale:
539
+ return img,r
540
+ else:
541
+ return img
542
+
543
+ def resize_height(img,h,interpolation=cv2.INTER_LINEAR):
544
+ shape = img.shape
545
+ new_h = h
546
+ new_w = int(shape[1]*new_h/shape[0])
547
+ return cv2.resize(img,dsize=(new_w,new_h),interpolation=interpolation)
548
+
549
+ def resize_width(img,w,interpolation=cv2.INTER_LINEAR):
550
+ shape = img.shape
551
+ new_w = w
552
+ new_h = int(shape[0]*new_w/shape[1])
553
+ return cv2.resize(img,dsize=(new_w,new_h),interpolation=interpolation)
554
+
555
+ def resize_short_size(img,size,interpolation=cv2.INTER_LINEAR):
556
+ shape = img.shape
557
+ if shape[0]<shape[1]:
558
+ return resize_height(img,size,interpolation)
559
+ else:
560
+ return resize_width(img,size,interpolation)
561
+
562
+ def resize_long_size(img,size,interpolation=cv2.INTER_LINEAR):
563
+ shape = img.shape
564
+ if shape[0]>shape[1]:
565
+ return resize_height(img,size,interpolation)
566
+ else:
567
+ return resize_width(img,size,interpolation)
568
+ '''
569
+ size:(w,h)
570
+ return:
571
+ img,r
572
+ r = new_size/old_size
573
+ '''
574
+ def resize_and_pad(img,size,interpolation=cv2.INTER_LINEAR,pad_color=(0,0,0),center_pad=True,return_scale=False):
575
+ old_shape = img.shape
576
+ img = resize_img(img,size,keep_aspect_ratio=True,interpolation=interpolation)
577
+ if return_scale:
578
+ r = img.shape[0]/max(old_shape[0],1)
579
+ if img.shape[0] == size[1] and img.shape[1] == size[0]:
580
+ if return_scale:
581
+ return img,r
582
+ return img
583
+ else:
584
+ if len(img.shape)==3:
585
+ channels = img.shape[-1]
586
+ if not isinstance(pad_color,Iterable):
587
+ pad_color = [pad_color]*channels
588
+ res = np.ones([size[1],size[0],channels],dtype=img.dtype)
589
+ pad_color = np.array(list(pad_color),dtype=img.dtype)
590
+ pad_color = pad_color.reshape([1,1,channels])
591
+ else:
592
+ if not isinstance(pad_color,Iterable):
593
+ pad_color = [pad_color]
594
+ res = np.ones([size[1],size[0]],dtype=img.dtype)
595
+ pad_color = np.array(list(pad_color),dtype=img.dtype)
596
+ pad_color = pad_color.reshape([1,1])
597
+ res = res*pad_color
598
+ if center_pad:
599
+ offset_x = (size[0]-img.shape[1])//2
600
+ offset_y = (size[1]-img.shape[0])//2
601
+ else:
602
+ offset_x = 0
603
+ offset_y = 0
604
+
605
+ w = img.shape[1]
606
+ h = img.shape[0]
607
+ res[offset_y:offset_y+h,offset_x:offset_x+w] = img
608
+ if return_scale:
609
+ return res,r
610
+ else:
611
+ return res
612
+
613
+ def rotate_img(img,angle,scale=1.0,border_value=0,dsize=None,center=None,interpolation=cv2.INTER_LINEAR):
614
+ if center is None:
615
+ center = (img.shape[1]//2,img.shape[0]//2)
616
+ if dsize is None:
617
+ dsize=(img.shape[1],img.shape[0])
618
+ M = cv2.getRotationMatrix2D(center,angle,scale)
619
+ else:
620
+ M = wa.getRotationMatrix2D(center,angle,scale,out_offset=(dsize[0]//2,dsize[1]//2))
621
+ img = cv2.warpAffine(img,M,dsize,borderValue=border_value,flags=interpolation)
622
+ return img
623
+
624
+ def rotate_img_file(filepath,angle,scale=1.0):
625
+ img = cv2.imread(filepath)
626
+ center = (img.shape[1]//2,img.shape[0]//2)
627
+ M = cv2.getRotationMatrix2D(center,angle,scale)
628
+ img = cv2.warpAffine(img,M,(img.shape[1],img.shape[0]))
629
+ cv2.imwrite(filepath,img)
630
+
631
+ '''
632
+ box:[ymin,xmin,ymax,xmax], relative coordinate
633
+ crop_size:[heigh,width] absolute pixel size.
634
+ '''
635
+ def crop_and_resize(img,box,crop_size):
636
+ img = crop_img(img,box)
637
+ return resize_img(img,crop_size)
638
+
639
+ '''
640
+ img:[H,W]/[H,W,C]
641
+ box:[N,4] ymin,xmin,ymax,xmax, relative corrdinate
642
+ 从同一个图上切图
643
+ '''
644
+ def crop_and_resize_imgs(img,boxes,crop_size):
645
+ res_imgs = []
646
+ for box in boxes:
647
+ sub_img = crop_and_resize(img,box,crop_size)
648
+ res_imgs.append(sub_img)
649
+
650
+ return np.stack(res_imgs,axis=0)
651
+ '''
652
+ img:[N,H,W]/[N,H,W,C]
653
+ box:[N,4] ymin,xmin,ymax,xmax, relative corrdinate
654
+ box 与 img一对一的进行切图
655
+ return:
656
+ [N]+crop_size
657
+ '''
658
+ def one_to_one_crop_and_resize_imgs(imgs,boxes,crop_size):
659
+ res_imgs = []
660
+ for i,box in enumerate(boxes):
661
+ sub_img = crop_and_resize(imgs[i],box,crop_size)
662
+ res_imgs.append(sub_img)
663
+
664
+ return np.stack(res_imgs,axis=0)
665
+
666
+
667
+
668
+
669
+
670
+ '''
671
+ img:[H,W,C]
672
+ size:(w,h)
673
+ '''
674
+ CENTER_PAD=0
675
+ RANDOM_PAD=1
676
+ TOPLEFT_PAD=2
677
+ def pad_img(img,size,pad_value=127,pad_type=CENTER_PAD,return_pad_value=False):
678
+ '''
679
+ pad_type: 0, center pad
680
+ pad_type: 1, random pad
681
+ pad_type: 2, topleft_pad
682
+
683
+ '''
684
+ if pad_type==0:
685
+ if img.shape[0]<size[1]:
686
+ py0 = (size[1]-img.shape[0])//2
687
+ py1 = size[1]-img.shape[0]-py0
688
+ else:
689
+ py0 = 0
690
+ py1 = 0
691
+ if img.shape[1]<size[0]:
692
+ px0 = (size[0] - img.shape[1]) // 2
693
+ px1 = size[0] - img.shape[1] - px0
694
+ else:
695
+ px0 = 0
696
+ px1 = 0
697
+ elif pad_type==1:
698
+ if img.shape[0]<size[1]:
699
+ py0 = random.randint(0,size[1]-img.shape[0])
700
+ py1 = size[1]-img.shape[0]-py0
701
+ else:
702
+ py0 = 0
703
+ py1 = 0
704
+ if img.shape[1]<size[0]:
705
+ px0 = random.randint(0,size[0]-img.shape[1])
706
+ px1 = size[0] - img.shape[1] - px0
707
+ else:
708
+ px0 = 0
709
+ px1 = 0
710
+ elif pad_type==2:
711
+ if img.shape[0]<size[1]:
712
+ py0 = 0
713
+ py1 = size[1]-img.shape[0]-py0
714
+ else:
715
+ py0 = 0
716
+ py1 = 0
717
+ if img.shape[1]<size[0]:
718
+ px0 = 0
719
+ px1 = size[0] - img.shape[1] - px0
720
+ else:
721
+ px0 = 0
722
+ px1 = 0
723
+ if len(img.shape)==3:
724
+ img = np.pad(img, [[py0, py1], [px0, px1], [0, 0]], constant_values=pad_value)
725
+ else:
726
+ img = np.pad(img, [[py0, py1], [px0, px1]], constant_values=pad_value)
727
+
728
+ if return_pad_value:
729
+ return img,px0,px1,py0,py1
730
+ return img
731
+
732
+ '''
733
+ img:[H,W,C]
734
+ size:(w,h)
735
+ '''
736
+ def pad_imgv2(img,size,pad_color=(0,0,0),center_pad=False):
737
+ if img.shape[0] == size[1] and img.shape[1] == size[0]:
738
+ return img
739
+ else:
740
+ res = np.ones([size[1],size[0],3],dtype=img.dtype)
741
+ pad_color = np.array(list(pad_color),dtype=img.dtype)
742
+ pad_color = pad_color.reshape([1,1,3])
743
+ res = res*pad_color
744
+ if center_pad:
745
+ offset_x = (size[0]-img.shape[1])//2
746
+ offset_y = (size[1]-img.shape[0])//2
747
+ else:
748
+ offset_x = 0
749
+ offset_y = 0
750
+
751
+ w = img.shape[1]
752
+ h = img.shape[0]
753
+ res[offset_y:offset_y+h,offset_x:offset_x+w,:] = img
754
+ return res
755
+
756
+ def pad_imgv2(img,px0,px1,py0,py1,pad_value=127):
757
+ if len(img.shape)==3:
758
+ img = np.pad(img, [[py0, py1], [px0, px1], [0, 0]], constant_values=pad_value)
759
+ else:
760
+ img = np.pad(img, [[py0, py1], [px0, px1]], constant_values=pad_value)
761
+
762
+ return img
763
+
764
+ '''
765
+ img:[H,W]/[H,W,C]
766
+ rect:[N,4] [xmin,ymin,xmax,ymax] absolute coordinate
767
+ '''
768
+ def sub_imagesv2(img,rects):
769
+ res = []
770
+ for rect in rects:
771
+ res.append(sub_imagev2(img,rect))
772
+
773
+ return res
774
+
775
+ def __get_discrete_palette(palette=[(0,(0,0,255)),(0.5,(255,255,255)),(1.0,(255,0,0))],nr=1000):
776
+ res = np.zeros([nr,3],dtype=np.float32)
777
+ pre_p = palette[0]
778
+ for cur_p in palette[1:]:
779
+ end_idx = min(math.ceil(cur_p[0]*nr),nr)
780
+ beg_idx = min(max(math.floor(pre_p[0]*nr),0),end_idx)
781
+ color0 = np.array(pre_p[1],dtype=np.float32)
782
+ color1 = np.array(cur_p[1],dtype=np.float32)
783
+ for i in range(beg_idx,end_idx):
784
+ cur_color = (i-beg_idx)*(color1-color0)/(end_idx-beg_idx)+color0
785
+ res[i] = cur_color
786
+ pre_p = cur_p
787
+
788
+
789
+ res = np.clip(res,0,255)
790
+ res = res.astype(np.uint8)
791
+
792
+ return res
793
+
794
+ def __get_discrete_img(img,nr=1000):
795
+ img = img.astype(np.float32)*(nr-1)
796
+ img = np.clip(img,0,nr-1)
797
+ img = img.astype(np.int32)
798
+ return img
799
+
800
+
801
+ def pseudocolor_img(img,palette=[(0,(0,0,255)),(0.5,(255,255,255)),(1.0,(255,0,0))],auto_norm=True):
802
+ '''
803
+ img: (H,W) #float, value in [0,1] if auto_norm is not True
804
+ '''
805
+ if auto_norm:
806
+ img = normal_image(img,0.0,1.0,dtype=np.float32)
807
+ color_nr = 256
808
+ img = __get_discrete_img(img,nr=color_nr)
809
+ palette = __get_discrete_palette(palette,nr=color_nr)
810
+ H,W = img.shape
811
+ img = np.reshape(img,[-1])
812
+ new_img = palette[img]
813
+ new_img = np.reshape(new_img,[H,W,3])
814
+
815
+ return new_img
816
+