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
@@ -0,0 +1,194 @@
1
+ #coding=utf-8
2
+ import numpy as np
3
+ import matplotlib.image as mpimg
4
+ import xml.etree.ElementTree as ET
5
+ from xml.dom.minidom import Document
6
+ import random
7
+ import os
8
+ import math
9
+ import logging
10
+ import shutil
11
+ from functools import partial
12
+ import wml.wml_utils as wmlu
13
+ import wml.img_utils as wmli
14
+ import copy
15
+ from .common import *
16
+ import wml.object_detection2.bboxes as odb
17
+ from .pascal_voc_toolkit_fwd import *
18
+ from .base_dataset import BaseDataset
19
+
20
+
21
+ class PascalVOCData(BaseDataset):
22
+ def __init__(self, label_text2id=None, shuffle=False,image_sub_dir=None,xml_sub_dir=None,
23
+ has_probs=False,
24
+ absolute_coord=False,
25
+ filter_error=False,
26
+ silent=False,
27
+ filter_empty_files=False,
28
+ keep_no_ann_imgs=False,
29
+ resample_parameters=None,
30
+ ignore_case=True):
31
+ '''
32
+
33
+ :param label_text2id: trans a single label text to id: int func(str)
34
+ :param shuffle:
35
+ :param image_sub_dir:
36
+ :param xml_sub_dir:
37
+ '''
38
+ self.files = None
39
+ super().__init__(label_text2id=label_text2id,
40
+ filter_empty_files=filter_empty_files,
41
+ filter_error=filter_error,
42
+ resample_parameters=resample_parameters,
43
+ shuffle=shuffle,
44
+ silent=silent,
45
+ absolute_coord=absolute_coord,
46
+ keep_no_ann_imgs=keep_no_ann_imgs)
47
+ self.xml_sub_dir = xml_sub_dir
48
+ self.image_sub_dir = image_sub_dir
49
+ self.has_probs = has_probs
50
+
51
+ def __getitem__(self,idx):
52
+ try:
53
+ img_file,xml_file = self.files[idx]
54
+ except Exception as e:
55
+ print(f"ERROR: {e} {self.files[idx]}")
56
+ print(self.files)
57
+ if not os.path.exists(xml_file):
58
+ return img_file,None,np.zeros([0],dtype=np.int32),[],np.zeros([0,4],dtype=np.float32),None,None,None,None
59
+ try:
60
+ data = read_voc_xml(xml_file,
61
+ adjust=None,
62
+ aspect_range=None,
63
+ has_probs=self.has_probs,
64
+ absolute_coord=self.absolute_coord)
65
+ shape, bboxes, labels_names, difficult, truncated,probs = data
66
+
67
+ if self.label_text2id is not None:
68
+ labels = [self.label_text2id(x) for x in labels_names]
69
+ keep = [x is not None for x in labels]
70
+ labels = [x if x is not None else -1 for x in labels]
71
+ labels = np.array(labels,dtype=np.int32)
72
+ difficult = np.array(difficult,dtype=np.int32)
73
+ labels = labels[keep]
74
+ bboxes = bboxes[keep]
75
+ difficult = difficult[keep]
76
+ labels_names = np.array(labels_names)[keep]
77
+ else:
78
+ labels = None
79
+
80
+ except Exception as e:
81
+ print(f"Read {xml_file} {e} faild.")
82
+ return DetData(img_file,None,np.zeros([0],dtype=np.int32),[],np.zeros([0,4],dtype=np.float32),None,None,None,None)
83
+ #使用difficult表示is_crowd
84
+ return DetData(img_file, shape[:2],labels, labels_names, bboxes, None, None, difficult, probs)
85
+
86
+ def find_files_in_dir(self,dir_path,img_suffix=".jpg"):
87
+ if not os.path.exists(dir_path):
88
+ print(f"Data path {dir_path} not exists.")
89
+ return False
90
+ files = getVOCFiles(dir_path,image_sub_dir=self.image_sub_dir,
91
+ xml_sub_dir=self.xml_sub_dir,
92
+ img_suffix=img_suffix,
93
+ silent=self.silent,
94
+ check_xml_file=not self.keep_no_ann_imgs)
95
+
96
+ return files
97
+
98
+ def get_labels(self,fs):
99
+ img_file,xml_file = fs
100
+ data = read_voc_xml(xml_file,
101
+ adjust=None,
102
+ aspect_range=None,
103
+ has_probs=self.has_probs,
104
+ absolute_coord=self.absolute_coord)
105
+ shape, bboxes, labels_names, difficult, truncated,probs = data
106
+ labels = [self.label_text2id(x) for x in labels_names]
107
+ return labels,labels_names
108
+
109
+ def get_items(self):
110
+ '''
111
+ :return:
112
+ full_path,img_size,category_ids,category_names,boxes,binary_masks,area,is_crowd,num_annotations_skipped
113
+ '''
114
+ for i in range(len(self.files)):
115
+ yield self.__getitem__(i)
116
+
117
+ def get_boxes_items(self):
118
+ '''
119
+ :return:
120
+ full_path,img_size,category_ids,boxes,is_crowd
121
+ '''
122
+ for img_file, xml_file in self.files:
123
+ shape, bboxes, labels_names, difficult, truncated,probs = read_voc_xml(xml_file,
124
+ adjust=None,
125
+ aspect_range=None,
126
+ has_probs=False)
127
+ labels = [self.label_text2id(x) for x in labels_names]
128
+ #使用difficult表示is_crowd
129
+ yield DetBboxesData(img_file,shape[:2], labels, bboxes, difficult)
130
+
131
+ if __name__ == "__main__":
132
+ #data_statistics("/home/vghost/ai/mldata/qualitycontrol/rdatasv3")
133
+ import wml.object_detection2.visualization as odv
134
+ import wml.img_utils as wmli
135
+ import matplotlib.pyplot as plt
136
+
137
+ text = []
138
+ for i in range(ord('a'), ord('z') + 1):
139
+ text.append(chr(i))
140
+ for i in range(ord('A'), ord('Z') + 1):
141
+ text.append(chr(i))
142
+ for i in range(ord('0'), ord('9') + 1):
143
+ text.append(chr(i))
144
+ '''
145
+ 0:53
146
+ 1:54
147
+ ...
148
+ 9:62
149
+ '''
150
+ text.append('/')
151
+ text.append('\\')
152
+ text.append('-')
153
+ text.append('+')
154
+ text.append(":")
155
+ text.append("WORD")
156
+ text.append("WD0") # up
157
+ text.append("WD3") # right
158
+ text.append("WD1") # down
159
+ text.append("WD2") # left
160
+ text.append("##") # left
161
+
162
+ text_to_id = {}
163
+ id_to_text = {}
164
+
165
+ for i, t in enumerate(text):
166
+ text_to_id[t] = i + 1
167
+ id_to_text[i + 1] = t
168
+
169
+ text_to_id[" "] = 69
170
+
171
+ def name_to_id(name):
172
+ return text_to_id[name]
173
+
174
+ data = PascalVOCData(label_text2id=name_to_id,shuffle=True)
175
+ data.read_data("/home/vghost/ai/mldata2/ocrdata/rdatasv20/train")
176
+ MIN_IMG_SIZE = 768
177
+ for x in data.get_items():
178
+ full_path, category_ids, category_names, boxes, binary_mask, area, is_crowd, num_annotations_skipped = x
179
+ img = wmli.imread(full_path)
180
+ if img.shape[0]<MIN_IMG_SIZE or img.shape[1]<MIN_IMG_SIZE:
181
+ img = wmli.resize_img(img,[MIN_IMG_SIZE,MIN_IMG_SIZE],keep_aspect_ratio=True)
182
+
183
+
184
+ def text_fn(classes, scores):
185
+ return id_to_text[classes]
186
+
187
+ odv.bboxes_draw_on_imgv2(
188
+ img=img, classes=category_ids, scores=None, bboxes=boxes, color_fn=None,
189
+ text_fn=text_fn, thickness=2,
190
+ show_text=True,
191
+ fontScale=0.8)
192
+ plt.figure()
193
+ plt.imshow(img)
194
+ plt.show()
@@ -0,0 +1,473 @@
1
+ #coding=utf-8
2
+ import numpy as np
3
+ import matplotlib.image as mpimg
4
+ import xml.etree.ElementTree as ET
5
+ from xml.dom.minidom import Document
6
+ import random
7
+ import os
8
+ import math
9
+ import wml.wml_utils
10
+ import logging
11
+ import shutil
12
+ from functools import partial
13
+ import wml.wml_utils as wmlu
14
+ import wml.img_utils as wmli
15
+ import copy
16
+ from .common import resample, get_shape_from_img
17
+ import wml.object_detection2.bboxes as odb
18
+
19
+
20
+
21
+ '''
22
+ 读取VOC xml文件
23
+ file_path: xml文件路径
24
+ adjust:左,上,右,下向中间的收缩像素大小
25
+ return:
26
+ shape: image size
27
+ boxes: [N,4] relative coordinate,(ymin,xmin,ymax,xmax)
28
+ '''
29
+ def read_voc_xml(file_path, adjust=None, aspect_range=None, has_probs=False,absolute_coord=False):
30
+ tree = ET.parse(file_path)
31
+ root = tree.getroot()
32
+
33
+ size = root.find('size')
34
+ shape = [int(size.find('height').text),
35
+ int(size.find('width').text),
36
+ int(size.find('depth').text)]
37
+ if shape[0] < 5 or shape[1] < 5:
38
+ _shape = get_shape_from_img(file_path)
39
+ print(f"Force update img shape, old={shape}, new={_shape}.")
40
+ shape = _shape
41
+
42
+ if adjust is not None:
43
+ shape[0] = shape[0] - (adjust[1] + adjust[3])
44
+ shape[1] = shape[1] - (adjust[0] + adjust[2])
45
+
46
+ bboxes = []
47
+ labels_text = []
48
+ difficult = []
49
+ truncated = []
50
+ probs = []
51
+ for obj in root.findall('object'):
52
+ label = obj.find('name').text
53
+ # 文件中difficult用0,1表示
54
+ if obj.find('difficult') is not None:
55
+ dif = int(obj.find('difficult').text)
56
+ else:
57
+ dif = 0
58
+ if "*" in label:
59
+ dif = 1
60
+ label = label.replace("*","")
61
+ if has_probs and obj.find("prob") is not None:
62
+ prob = float(obj.find("prob").text)
63
+ else:
64
+ prob = 1.0
65
+
66
+ if obj.find('truncated') is not None:
67
+ trun = int(obj.find('truncated').text)
68
+ else:
69
+ trun = 0
70
+ bbox = obj.find('bndbox')
71
+ box_ok = True
72
+ if adjust is None:
73
+ ymin, xmin, ymax, xmax = [float(bbox.find('ymin').text),
74
+ float(bbox.find('xmin').text),
75
+ float(bbox.find('ymax').text),
76
+ float(bbox.find('xmax').text)]
77
+ if math.fabs(ymax - ymin) < 1e-8 or math.fabs(xmax - xmin) < 1e-8:
78
+ logging.warning("zero size box({},{},{},{}), {}".format(ymin, xmin, ymax, xmax, file_path))
79
+ continue
80
+ elif absolute_coord:
81
+ box = (max(0., ymin),
82
+ max(0., xmin),
83
+ ymax,
84
+ xmax
85
+ )
86
+ pass
87
+ else:
88
+ box = (max(0., ymin / shape[0]),
89
+ max(0., xmin / shape[1]),
90
+ min(1., ymax / shape[0]),
91
+ min(1., xmax / shape[1])
92
+ )
93
+
94
+ else:
95
+ ymin = float(bbox.find('ymin').text) - float(adjust[1])
96
+ xmin = float(bbox.find('xmin').text) - float(adjust[0])
97
+ ymax = float(bbox.find('ymax').text) - float(adjust[1])
98
+ xmax = float(bbox.find('xmax').text) - float(adjust[0])
99
+ if math.fabs(ymax - ymin) < 1e-8 or math.fabs(xmax - xmin) < 1e-8:
100
+ logging.warning("zero size box({},{},{},{}), {}".format(ymin, xmin, ymax, xmax, file_path))
101
+ continue
102
+ elif absolute_coord:
103
+ box = (max(0., ymin),
104
+ max(0., xmin),
105
+ ymax,
106
+ xmax
107
+ )
108
+ pass
109
+ else:
110
+ box = (max(0., ymin / shape[0]),
111
+ max(0., xmin / shape[1]),
112
+ min(1., ymax / shape[0]),
113
+ min(1., xmax / shape[1])
114
+ )
115
+ if aspect_range is not None:
116
+ if float(box[2] - box[0]) / (box[3] - box[1]) > aspect_range[1] or float(box[2] - box[0]) / (
117
+ box[3] - box[1]) < aspect_range[0]:
118
+ logging.warning("large aspect.")
119
+ box_ok = False
120
+
121
+ if not box_ok:
122
+ logging.warning("Ignore one box")
123
+ continue
124
+ bboxes.append(box)
125
+ labels_text.append(label)
126
+ difficult.append(dif)
127
+ truncated.append(trun)
128
+ probs.append(prob)
129
+
130
+ assert len(bboxes) == len(labels_text), "error size"
131
+ assert len(bboxes) == len(difficult), "error size"
132
+ assert len(bboxes) == len(truncated), "error size"
133
+ #shape, bboxes, labels_names, difficult, truncated,probs
134
+ if len(bboxes)>0:
135
+ bboxes = np.array(bboxes,dtype=np.float32)
136
+ else:
137
+ bboxes = np.zeros([0,4],dtype=np.float32)
138
+ return shape, bboxes, labels_text, difficult, truncated, probs
139
+
140
+ def read_voc_xml_xy(file_path, has_probs=False):
141
+ data = read_voc_xml(file_path=file_path,
142
+ has_probs=has_probs,
143
+ absolute_coord=True,
144
+ )
145
+ shape, bboxes, labels_text, difficult, truncated, probs = data
146
+ bboxes = odb.npchangexyorder(bboxes)
147
+ return shape, bboxes, labels_text, difficult, truncated, probs
148
+
149
+ def create_text_element(doc,name,value):
150
+ if not isinstance(value,str):
151
+ value = str(value)
152
+ res = doc.createElement(name)
153
+ value = doc.createTextNode(value)
154
+ res.appendChild(value)
155
+ return res
156
+
157
+ '''
158
+ save_path:xml文件保存路径
159
+ file_path:图像文件路径
160
+ shape:[h,w,d]
161
+ boxes:[N,4] (y0,x0,y1,x1)
162
+ '''
163
+ def write_voc_xml(xml_path,img_path,shape, bboxes, labels_text, difficult=None, truncated=None,probs=None,is_relative_coordinate=True):
164
+
165
+ if shape is None or shape[0] < 5 or shape[1] < 5:
166
+ _shape = get_shape_from_img(xml_path,img_path)
167
+ print(f"Force update img shape, old={shape}, new={_shape}.")
168
+ shape = list(_shape)
169
+
170
+ if len(bboxes)>0 and is_relative_coordinate and np.max(bboxes)>1.01:
171
+ print(f"Use relative coordinate and max bboxes value is {np.max(bboxes)}.")
172
+
173
+ if len(shape)==2:
174
+ shape = list(shape)+[1]
175
+
176
+ if difficult is None:
177
+ difficult = ["0"] * len(labels_text)
178
+ if truncated is None:
179
+ truncated = ["0"] * len(labels_text)
180
+
181
+ doc = Document()
182
+ objectlist = doc.createElement("annotation")
183
+ doc.appendChild(objectlist)
184
+
185
+ folder = doc.createElement("folder")
186
+ #folder_value = doc.createTextNode(os.path.basename(os.path.dirname(img_path)).decode("utf-8"))
187
+ folder_value = doc.createTextNode(os.path.basename(os.path.dirname(img_path)))
188
+ folder.appendChild(folder_value)
189
+ objectlist.appendChild(folder)
190
+
191
+ filename = doc.createElement("filename")
192
+ #filename_value = doc.createTextNode(os.path.basename(img_path).decode("utf-8"))
193
+ filename_value = doc.createTextNode(os.path.basename(img_path))
194
+ filename.appendChild(filename_value)
195
+ objectlist.appendChild(filename)
196
+
197
+ path = doc.createElement("path")
198
+ #path_value = doc.createTextNode(img_path.decode("utf-8"))
199
+ path_value = doc.createTextNode(img_path)
200
+ path.appendChild(path_value)
201
+ objectlist.appendChild(path)
202
+
203
+ source = doc.createElement("source")
204
+ database = doc.createElement("database")
205
+ database_value = doc.createTextNode("Unknown")
206
+ database.appendChild(database_value)
207
+ source.appendChild(database)
208
+ objectlist.appendChild(source)
209
+
210
+ size = doc.createElement("size")
211
+ size.appendChild(create_text_element(doc,"width",str(shape[1])))
212
+ size.appendChild(create_text_element(doc,"height",str(shape[0])))
213
+ size.appendChild(create_text_element(doc,"depth",str(shape[2])))
214
+ objectlist.appendChild(size)
215
+
216
+ objectlist.appendChild(create_text_element(doc,"segmented","0"))
217
+
218
+ if probs is not None:
219
+ for (box, label, dif, trun,prob) in zip(bboxes, labels_text, difficult, truncated,probs):
220
+ object = doc.createElement("object")
221
+ object.appendChild(create_text_element(doc, "name", str(label)))
222
+ object.appendChild(create_text_element(doc, "pose", "Unspecified"))
223
+ object.appendChild(create_text_element(doc, "truncated", trun))
224
+ object.appendChild(create_text_element(doc, "difficult", dif))
225
+ object.appendChild(create_text_element(doc, "confidence", prob))
226
+ bndbox = doc.createElement("bndbox")
227
+ if is_relative_coordinate:
228
+ bndbox.appendChild(create_text_element(doc, "xmin", int(box[1] * shape[1])))
229
+ bndbox.appendChild(create_text_element(doc, "ymin", int(box[0] * shape[0])))
230
+ bndbox.appendChild(create_text_element(doc, "xmax", int(box[3] * shape[1])))
231
+ bndbox.appendChild(create_text_element(doc, "ymax", int(box[2] * shape[0])))
232
+ else:
233
+ bndbox.appendChild(create_text_element(doc, "xmin", int(box[1])))
234
+ bndbox.appendChild(create_text_element(doc, "ymin", int(box[0])))
235
+ bndbox.appendChild(create_text_element(doc, "xmax", int(box[3])))
236
+ bndbox.appendChild(create_text_element(doc, "ymax", int(box[2])))
237
+ object.appendChild(bndbox)
238
+ objectlist.appendChild(object)
239
+ else:
240
+ for (box,label,dif,trun) in zip(bboxes,labels_text,difficult,truncated):
241
+ object = doc.createElement("object")
242
+ object.appendChild(create_text_element(doc,"name",str(label)))
243
+ object.appendChild(create_text_element(doc,"pose","Unspecified"))
244
+ object.appendChild(create_text_element(doc,"truncated",trun))
245
+ object.appendChild(create_text_element(doc,"difficult",dif))
246
+ bndbox = doc.createElement("bndbox")
247
+ try:
248
+ if is_relative_coordinate:
249
+ bndbox.appendChild(create_text_element(doc,"xmin",int(box[1]*shape[1])))
250
+ bndbox.appendChild(create_text_element(doc,"ymin",int(box[0]*shape[0])))
251
+ bndbox.appendChild(create_text_element(doc,"xmax",int(box[3]*shape[1])))
252
+ bndbox.appendChild(create_text_element(doc,"ymax",int(box[2]*shape[0])))
253
+ else:
254
+ bndbox.appendChild(create_text_element(doc, "xmin", int(box[1])))
255
+ bndbox.appendChild(create_text_element(doc, "ymin", int(box[0])))
256
+ bndbox.appendChild(create_text_element(doc, "xmax", int(box[3])))
257
+ bndbox.appendChild(create_text_element(doc, "ymax", int(box[2])))
258
+ except Exception as e:
259
+ print(f"ERROR: {xml_path} {e} {box}")
260
+ object.appendChild(bndbox)
261
+ objectlist.appendChild(object)
262
+
263
+ with open(xml_path,'w') as f:
264
+ #f.write(doc.toprettyxml(indent='\t', encoding='utf-8'))
265
+ f.write(doc.toprettyxml(indent='\t'))
266
+
267
+ def write_voc_xml_xy(xml_path,img_path,shape, bboxes, labels_text, difficult=None, truncated=None,probs=None):
268
+ bboxes = odb.npchangexyorder(bboxes)
269
+ write_voc_xml(xml_path=xml_path,
270
+ img_path=img_path,
271
+ shape=shape,
272
+ bboxes=bboxes,
273
+ labels_text=labels_text,
274
+ difficult=difficult,
275
+ truncated=truncated,
276
+ probs=probs,
277
+ is_relative_coordinate=False,
278
+ )
279
+
280
+ '''
281
+ file_path:图像文件路径
282
+ save_path: xml path or None
283
+ bboxes:相对坐标
284
+ '''
285
+ def writeVOCXml(file_path,bboxes, labels, save_path=None,difficult=None, truncated=None,probs=None,img_shape=None,is_relative_coordinate=True):
286
+ if isinstance(bboxes,np.ndarray):
287
+ bboxes = bboxes.tolist()
288
+ if isinstance(labels,np.ndarray):
289
+ labels = labels.tolist()
290
+ if isinstance(difficult,np.ndarray):
291
+ difficult = difficult.tolist()
292
+ if isinstance(truncated, np.ndarray):
293
+ truncated = truncated.tolist()
294
+
295
+ if img_shape is None:
296
+ img = mpimg.imread(file_path)
297
+ img_shape = img.shape
298
+
299
+ if save_path is None:
300
+ dir_path = os.path.dirname(file_path)
301
+ base_name = os.path.basename(file_path)
302
+ base_name = wml_utils.base_name(base_name)+".xml"
303
+ save_path = os.path.join(dir_path,base_name)
304
+
305
+ write_voc_xml(save_path,file_path,img_shape,bboxes,labels,difficult,truncated,probs=probs,
306
+ is_relative_coordinate=is_relative_coordinate)
307
+
308
+ '''
309
+ 与上一个版本的区别为 img shape 为输入值,不需要读图获取
310
+ file_path: image path
311
+ save_path: xml path or None
312
+ '''
313
+ def writeVOCXmlV2(file_path,shape,bboxes, labels, save_path=None,difficult=None, truncated=None,probs=None,
314
+ is_relative_coordinate=True):
315
+ if isinstance(bboxes,np.ndarray):
316
+ bboxes = bboxes.tolist()
317
+ if isinstance(labels,np.ndarray):
318
+ labels = labels.tolist()
319
+ if isinstance(difficult,np.ndarray):
320
+ difficult = difficult.tolist()
321
+ if isinstance(truncated, np.ndarray):
322
+ truncated = truncated.tolist()
323
+
324
+ if save_path is None:
325
+ dir_path = os.path.dirname(file_path)
326
+ base_name = os.path.basename(file_path)
327
+ base_name = wml_utils.base_name(base_name)+".xml"
328
+ save_path = os.path.join(dir_path,base_name)
329
+
330
+ write_voc_xml(save_path,file_path,shape,bboxes,labels,difficult,truncated,probs=probs,
331
+ is_relative_coordinate=is_relative_coordinate)
332
+
333
+ '''
334
+ file_path:图像文件路径
335
+ bboxes:相对坐标
336
+ '''
337
+ def writeVOCXmlByImg(img,img_save_path,bboxes, labels, difficult=None, truncated=None,probs=None,is_relative_coordinate=True):
338
+ if isinstance(bboxes,np.ndarray):
339
+ bboxes = bboxes.tolist()
340
+ if isinstance(labels,np.ndarray):
341
+ labels = labels.tolist()
342
+ if isinstance(difficult,np.ndarray):
343
+ difficult = difficult.tolist()
344
+ if isinstance(truncated, np.ndarray):
345
+ truncated = truncated.tolist()
346
+
347
+ img_shape = img.shape
348
+
349
+ dir_path = os.path.dirname(img_save_path)
350
+ base_name = os.path.basename(img_save_path)
351
+ base_name = wml_utils.base_name(base_name)+".xml"
352
+ save_path = os.path.join(dir_path,base_name)
353
+ wmli.imwrite(img_save_path,img)
354
+ write_voc_xml(save_path,img_save_path,img_shape,bboxes,labels,difficult,truncated,probs=probs,
355
+ is_relative_coordinate=is_relative_coordinate)
356
+
357
+ '''
358
+ return:[(image_file0,xml_file0),(image_file1,xml_file1),...]
359
+ '''
360
+ def getVOCFiles(dir_path,image_sub_dir="JPEGImages",xml_sub_dir="Annotations",img_suffix=".jpg",shuffe=False,auto_sub_dir=False,silent=False,
361
+ check_xml_file=True):
362
+ if auto_sub_dir:
363
+ jpeg_dir = os.path.join(dir_path,"JPEGImages")
364
+ if not os.path.exists(jpeg_dir):
365
+ jpeg_dir = dir_path
366
+ xml_dir = os.path.join(dir_path,"Annotations")
367
+ if not os.path.exists(xml_dir):
368
+ xml_dir = dir_path
369
+ else:
370
+ if image_sub_dir is not None:
371
+ jpeg_dir = os.path.join(dir_path,image_sub_dir)
372
+ else:
373
+ jpeg_dir = dir_path
374
+ if xml_sub_dir is not None:
375
+ xml_dir = os.path.join(dir_path,xml_sub_dir)
376
+ else:
377
+ xml_dir = dir_path
378
+ inputfilenames = wml_utils.recurse_get_filepath_in_dir(jpeg_dir,suffix=img_suffix)
379
+
380
+ img_file_paths = []
381
+ xml_file_paths = []
382
+ for file in inputfilenames:
383
+ base_name = wml_utils.base_name(file)+".xml"
384
+ if xml_sub_dir is not None:
385
+ xml_path = os.path.join(xml_dir,base_name)
386
+ else:
387
+ xml_path = os.path.join(os.path.dirname(file),base_name)
388
+ if (check_xml_file and os.path.exists(xml_path)) or not check_xml_file:
389
+ img_file_paths.append(file)
390
+ xml_file_paths.append(xml_path)
391
+ elif not silent:
392
+ print("ERROR, xml file dosen't exists: ",file,xml_path)
393
+
394
+ res = []
395
+ for x in zip(img_file_paths,xml_file_paths):
396
+ res.append(list(x))
397
+ if shuffe:
398
+ random.shuffle(res)
399
+ return res
400
+
401
+ def getVOCFilesV2(dir_path):
402
+ img_files = wmlu.recurse_get_filepath_in_dir(dir_path,".jpg")
403
+ res = []
404
+ for f in img_files:
405
+ xml_path = wmlu.change_suffix(f,"xml")
406
+ if os.path.exists(xml_path) and os.path.exists(f):
407
+ res.append([f,xml_path])
408
+ return res
409
+
410
+ def filterVOCFilesByName(voc_files,file_names):
411
+ res = []
412
+ for img_file,xml_file in voc_files:
413
+ base_name = wmlu.base_name(img_file)
414
+ if base_name not in file_names:
415
+ continue
416
+ res.append((img_file,xml_file))
417
+ return res
418
+
419
+ def removeUnmatchVOCFiles(dir_path,image_sub_dir="JPEGImages",xml_sub_dir="Annotations",img_suffix=".jpg",shuffe=False):
420
+ if image_sub_dir is not None:
421
+ jpeg_dir = os.path.join(dir_path,image_sub_dir)
422
+ else:
423
+ jpeg_dir = dir_path
424
+ if xml_sub_dir is not None:
425
+ xml_dir = os.path.join(dir_path,xml_sub_dir)
426
+ else:
427
+ xml_dir = dir_path
428
+ inputfilenames = wml_utils.recurse_get_filepath_in_dir(jpeg_dir,suffix=img_suffix)
429
+
430
+ total_removed_jpgs = 0
431
+ total_removed_xmls = 0
432
+
433
+ good_xml_names=[]
434
+ for file in inputfilenames:
435
+ base_name = wmlu.base_name(file)
436
+ xml_path = wmlu.change_suffix(file,"xml")
437
+ if os.path.exists(xml_path):
438
+ good_xml_names.append(base_name)
439
+ else:
440
+ print(f"remove {file}")
441
+ total_removed_jpgs += 1
442
+ os.remove(file)
443
+
444
+ for file in wml_utils.recurse_get_filepath_in_dir(xml_dir,suffix="xml"):
445
+ base_name = wmlu.base_name(file)
446
+ if base_name not in good_xml_names:
447
+ total_removed_xmls += 1
448
+ print(f"remove {file}")
449
+ os.remove(file)
450
+
451
+ print(f"Total remove {total_removed_jpgs} images, total remove {total_removed_xmls} xmls.")
452
+
453
+
454
+ def split_voc_files(files,nr=1):
455
+ '''
456
+
457
+ Args:
458
+ files: List((xml_file,img_file))
459
+
460
+ Returns:
461
+ files0,files1: len(labels) of files0 < nr, len(labels) of files1 > =nr
462
+
463
+ '''
464
+ files0 = []
465
+ files1 = []
466
+ for xml_file,img_file in files:
467
+ shape, bboxes, labels_text, difficult, truncated, probs = read_voc_xml(xml_file)
468
+ if len(labels_text)<nr:
469
+ files0.append((xml_file,img_file))
470
+ else:
471
+ files1.append((xml_file,img_file))
472
+
473
+ return files0,files1