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.
- python_wml-3.0.0.dist-info/LICENSE +23 -0
- python_wml-3.0.0.dist-info/METADATA +51 -0
- python_wml-3.0.0.dist-info/RECORD +164 -0
- python_wml-3.0.0.dist-info/WHEEL +5 -0
- python_wml-3.0.0.dist-info/top_level.txt +1 -0
- wml/__init__.py +0 -0
- wml/basic_data_def/__init__.py +2 -0
- wml/basic_data_def/detection_data_def.py +279 -0
- wml/basic_data_def/io_data_def.py +2 -0
- wml/basic_img_utils.py +816 -0
- wml/img_patch.py +92 -0
- wml/img_utils.py +571 -0
- wml/iotoolkit/__init__.py +17 -0
- wml/iotoolkit/aic_keypoint.py +115 -0
- wml/iotoolkit/baidu_mask_toolkit.py +244 -0
- wml/iotoolkit/base_dataset.py +210 -0
- wml/iotoolkit/bboxes_statistics.py +515 -0
- wml/iotoolkit/build.py +0 -0
- wml/iotoolkit/cityscapes_toolkit.py +183 -0
- wml/iotoolkit/classification_data_statistics.py +25 -0
- wml/iotoolkit/coco_data_fwd.py +225 -0
- wml/iotoolkit/coco_keypoints.py +118 -0
- wml/iotoolkit/coco_keypoints_fmt2.py +103 -0
- wml/iotoolkit/coco_toolkit.py +397 -0
- wml/iotoolkit/coco_wholebody.py +269 -0
- wml/iotoolkit/common.py +108 -0
- wml/iotoolkit/crowd_pose.py +146 -0
- wml/iotoolkit/fast_labelme.py +110 -0
- wml/iotoolkit/image_folder.py +95 -0
- wml/iotoolkit/imgs_cache.py +58 -0
- wml/iotoolkit/imgs_reader_mt.py +73 -0
- wml/iotoolkit/labelme_base.py +102 -0
- wml/iotoolkit/labelme_json_to_img.py +49 -0
- wml/iotoolkit/labelme_toolkit.py +117 -0
- wml/iotoolkit/labelme_toolkit_fwd.py +733 -0
- wml/iotoolkit/labelmemckeypoints_dataset.py +169 -0
- wml/iotoolkit/lspet.py +48 -0
- wml/iotoolkit/mapillary_vistas_toolkit.py +269 -0
- wml/iotoolkit/mat_data.py +90 -0
- wml/iotoolkit/mckeypoints_statistics.py +28 -0
- wml/iotoolkit/mot_datasets.py +62 -0
- wml/iotoolkit/mpii.py +108 -0
- wml/iotoolkit/npmckeypoints_dataset.py +164 -0
- wml/iotoolkit/o365_to_coco.py +136 -0
- wml/iotoolkit/object365_toolkit.py +156 -0
- wml/iotoolkit/object365v2_toolkit.py +71 -0
- wml/iotoolkit/pascal_voc_data.py +51 -0
- wml/iotoolkit/pascal_voc_toolkit.py +194 -0
- wml/iotoolkit/pascal_voc_toolkit_fwd.py +473 -0
- wml/iotoolkit/penn_action.py +57 -0
- wml/iotoolkit/rawframe_dataset.py +129 -0
- wml/iotoolkit/rewrite_pascal_voc.py +28 -0
- wml/iotoolkit/semantic_data.py +49 -0
- wml/iotoolkit/split_file_by_type.py +29 -0
- wml/iotoolkit/sports_mot_datasets.py +78 -0
- wml/iotoolkit/vis_objectdetection_dataset.py +70 -0
- wml/iotoolkit/vis_torch_data.py +39 -0
- wml/iotoolkit/yolo_toolkit.py +38 -0
- wml/object_detection2/__init__.py +4 -0
- wml/object_detection2/basic_visualization.py +37 -0
- wml/object_detection2/bboxes.py +812 -0
- wml/object_detection2/data_process_toolkit.py +146 -0
- wml/object_detection2/keypoints.py +292 -0
- wml/object_detection2/mask.py +120 -0
- wml/object_detection2/metrics/__init__.py +3 -0
- wml/object_detection2/metrics/build.py +15 -0
- wml/object_detection2/metrics/classifier_toolkit.py +440 -0
- wml/object_detection2/metrics/common.py +71 -0
- wml/object_detection2/metrics/mckps_toolkit.py +338 -0
- wml/object_detection2/metrics/toolkit.py +1953 -0
- wml/object_detection2/npod_toolkit.py +361 -0
- wml/object_detection2/odtools.py +243 -0
- wml/object_detection2/standard_names.py +75 -0
- wml/object_detection2/visualization.py +956 -0
- wml/object_detection2/wmath.py +34 -0
- wml/semantic/__init__.py +0 -0
- wml/semantic/basic_toolkit.py +65 -0
- wml/semantic/mask_utils.py +156 -0
- wml/semantic/semantic_test.py +21 -0
- wml/semantic/structures.py +1 -0
- wml/semantic/toolkit.py +105 -0
- wml/semantic/visualization_utils.py +658 -0
- wml/threadtoolkit.py +50 -0
- wml/walgorithm.py +228 -0
- wml/wcollections.py +212 -0
- wml/wfilesystem.py +487 -0
- wml/wml_utils.py +657 -0
- wml/wstructures/__init__.py +4 -0
- wml/wstructures/common.py +9 -0
- wml/wstructures/keypoints_train_toolkit.py +149 -0
- wml/wstructures/kps_structures.py +579 -0
- wml/wstructures/mask_structures.py +1161 -0
- wml/wtorch/__init__.py +8 -0
- wml/wtorch/bboxes.py +104 -0
- wml/wtorch/classes_suppression.py +24 -0
- wml/wtorch/conv_module.py +181 -0
- wml/wtorch/conv_ws.py +144 -0
- wml/wtorch/data/__init__.py +16 -0
- wml/wtorch/data/_utils/__init__.py +45 -0
- wml/wtorch/data/_utils/collate.py +183 -0
- wml/wtorch/data/_utils/fetch.py +47 -0
- wml/wtorch/data/_utils/pin_memory.py +121 -0
- wml/wtorch/data/_utils/signal_handling.py +72 -0
- wml/wtorch/data/_utils/worker.py +227 -0
- wml/wtorch/data/base_data_loader_iter.py +93 -0
- wml/wtorch/data/dataloader.py +501 -0
- wml/wtorch/data/datapipes/__init__.py +1 -0
- wml/wtorch/data/datapipes/iter/__init__.py +12 -0
- wml/wtorch/data/datapipes/iter/batch.py +126 -0
- wml/wtorch/data/datapipes/iter/callable.py +92 -0
- wml/wtorch/data/datapipes/iter/listdirfiles.py +37 -0
- wml/wtorch/data/datapipes/iter/loadfilesfromdisk.py +30 -0
- wml/wtorch/data/datapipes/iter/readfilesfromtar.py +60 -0
- wml/wtorch/data/datapipes/iter/readfilesfromzip.py +63 -0
- wml/wtorch/data/datapipes/iter/sampler.py +94 -0
- wml/wtorch/data/datapipes/utils/__init__.py +0 -0
- wml/wtorch/data/datapipes/utils/common.py +65 -0
- wml/wtorch/data/dataset.py +354 -0
- wml/wtorch/data/datasets/__init__.py +4 -0
- wml/wtorch/data/datasets/common.py +53 -0
- wml/wtorch/data/datasets/listdirfilesdataset.py +36 -0
- wml/wtorch/data/datasets/loadfilesfromdiskdataset.py +30 -0
- wml/wtorch/data/distributed.py +135 -0
- wml/wtorch/data/multi_processing_data_loader_iter.py +866 -0
- wml/wtorch/data/sampler.py +267 -0
- wml/wtorch/data/single_process_data_loader_iter.py +24 -0
- wml/wtorch/data/test_data_loader.py +26 -0
- wml/wtorch/dataset_toolkit.py +67 -0
- wml/wtorch/depthwise_separable_conv_module.py +98 -0
- wml/wtorch/dist.py +591 -0
- wml/wtorch/dropblock/__init__.py +6 -0
- wml/wtorch/dropblock/dropblock.py +228 -0
- wml/wtorch/dropblock/dropout.py +40 -0
- wml/wtorch/dropblock/scheduler.py +48 -0
- wml/wtorch/ema.py +61 -0
- wml/wtorch/fc_module.py +73 -0
- wml/wtorch/functional.py +34 -0
- wml/wtorch/iter_dataset.py +26 -0
- wml/wtorch/loss.py +69 -0
- wml/wtorch/nets/__init__.py +0 -0
- wml/wtorch/nets/ckpt_toolkit.py +219 -0
- wml/wtorch/nets/fpn.py +276 -0
- wml/wtorch/nets/hrnet/__init__.py +0 -0
- wml/wtorch/nets/hrnet/config.py +2 -0
- wml/wtorch/nets/hrnet/hrnet.py +494 -0
- wml/wtorch/nets/misc.py +249 -0
- wml/wtorch/nets/resnet/__init__.py +0 -0
- wml/wtorch/nets/resnet/layers/__init__.py +17 -0
- wml/wtorch/nets/resnet/layers/aspp.py +144 -0
- wml/wtorch/nets/resnet/layers/batch_norm.py +231 -0
- wml/wtorch/nets/resnet/layers/blocks.py +111 -0
- wml/wtorch/nets/resnet/layers/wrappers.py +110 -0
- wml/wtorch/nets/resnet/r50_config.py +38 -0
- wml/wtorch/nets/resnet/resnet.py +691 -0
- wml/wtorch/nets/shape_spec.py +20 -0
- wml/wtorch/nets/simple_fpn.py +101 -0
- wml/wtorch/nms.py +109 -0
- wml/wtorch/nn.py +896 -0
- wml/wtorch/ocr_block.py +193 -0
- wml/wtorch/summary.py +331 -0
- wml/wtorch/train_toolkit.py +603 -0
- wml/wtorch/transformer_blocks.py +266 -0
- wml/wtorch/utils.py +719 -0
- 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
|
+
|