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,658 @@
1
+ # Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+
16
+ """A set of functions that are used for visualization.
17
+
18
+ These functions often receive an image, perform some visualization on the image.
19
+ The functions do not return a value, instead they modify the image itself.
20
+
21
+ """
22
+ import collections
23
+ import functools
24
+ # Set headless-friendly backend.
25
+ import matplotlib;
26
+ import matplotlib.pyplot as plt # pylint: disable=g-import-not-at-top
27
+ import numpy as np
28
+ import PIL.Image as Image
29
+ import PIL.ImageColor as ImageColor
30
+ import PIL.ImageDraw as ImageDraw
31
+ import PIL.ImageFont as ImageFont
32
+ import six
33
+ import cv2 as cv
34
+ import cv2
35
+ import sys
36
+
37
+ _TITLE_LEFT_MARGIN = 10
38
+ _TITLE_TOP_MARGIN = 10
39
+ STANDARD_COLORS = [
40
+ 'AliceBlue', 'Chartreuse', 'Aqua', 'Aquamarine', 'Azure', 'Beige', 'Bisque',
41
+ 'BlanchedAlmond', 'BlueViolet', 'BurlyWood', 'CadetBlue', 'AntiqueWhite',
42
+ 'Chocolate', 'Coral', 'CornflowerBlue', 'Cornsilk', 'Crimson', 'Cyan',
43
+ 'DarkCyan', 'DarkGoldenRod', 'DarkGrey', 'DarkKhaki', 'DarkOrange',
44
+ 'DarkOrchid', 'DarkSalmon', 'DarkSeaGreen', 'DarkTurquoise', 'DarkViolet',
45
+ 'DeepPink', 'DeepSkyBlue', 'DodgerBlue', 'FireBrick', 'FloralWhite',
46
+ 'ForestGreen', 'Fuchsia', 'Gainsboro', 'GhostWhite', 'Gold', 'GoldenRod',
47
+ 'Salmon', 'Tan', 'HoneyDew', 'HotPink', 'IndianRed', 'Ivory', 'Khaki',
48
+ 'Lavender', 'LavenderBlush', 'LawnGreen', 'LemonChiffon', 'LightBlue',
49
+ 'LightCoral', 'LightCyan', 'LightGoldenRodYellow', 'LightGray', 'LightGrey',
50
+ 'LightGreen', 'LightPink', 'LightSalmon', 'LightSeaGreen', 'LightSkyBlue',
51
+ 'LightSlateGray', 'LightSlateGrey', 'LightSteelBlue', 'LightYellow', 'Lime',
52
+ 'LimeGreen', 'Linen', 'Magenta', 'MediumAquaMarine', 'MediumOrchid',
53
+ 'MediumPurple', 'MediumSeaGreen', 'MediumSlateBlue', 'MediumSpringGreen',
54
+ 'MediumTurquoise', 'MediumVioletRed', 'MintCream', 'MistyRose', 'Moccasin',
55
+ 'NavajoWhite', 'OldLace', 'Olive', 'OliveDrab', 'Orange', 'OrangeRed',
56
+ 'Orchid', 'PaleGoldenRod', 'PaleGreen', 'PaleTurquoise', 'PaleVioletRed',
57
+ 'PapayaWhip', 'PeachPuff', 'Peru', 'Pink', 'Plum', 'PowderBlue', 'Purple',
58
+ 'Red', 'RosyBrown', 'RoyalBlue', 'SaddleBrown', 'Green', 'SandyBrown',
59
+ 'SeaGreen', 'SeaShell', 'Sienna', 'Silver', 'SkyBlue', 'SlateBlue',
60
+ 'SlateGray', 'SlateGrey', 'Snow', 'SpringGreen', 'SteelBlue', 'GreenYellow',
61
+ 'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'White',
62
+ 'WhiteSmoke', 'Yellow', 'YellowGreen'
63
+ ]
64
+ RGB_STANDARD_COLORS=[ImageColor.getrgb(x) for x in STANDARD_COLORS]
65
+ MIN_RANDOM_STANDARD_COLORS = [
66
+ 'Red', 'Yellow', 'Green', 'MediumSlateBlue', 'Chartreuse',
67
+ 'Aqua', 'Aquamarine', 'Fuchsia', 'Azure', 'Beige', 'Bisque',
68
+ 'BlanchedAlmond', 'BlueViolet', 'BurlyWood', 'CadetBlue', 'AntiqueWhite',
69
+ 'Chocolate', 'Coral', 'CornflowerBlue', 'Cornsilk', 'Crimson', 'Cyan',
70
+ 'DarkCyan', 'DarkGoldenRod', 'DarkKhaki', 'DarkOrange',
71
+ 'DarkOrchid', 'DarkSalmon', 'DarkSeaGreen', 'DarkTurquoise', 'DarkViolet',
72
+ 'DeepPink', 'DeepSkyBlue', 'DodgerBlue', 'FireBrick',
73
+ 'ForestGreen', 'Gainsboro', 'Gold', 'GoldenRod',
74
+ 'Salmon', 'Tan', 'HoneyDew', 'HotPink', 'IndianRed', 'Ivory', 'Khaki',
75
+ 'Lavender', 'LavenderBlush', 'LawnGreen', 'LemonChiffon', 'LightBlue',
76
+ 'LightCoral', 'LightCyan', 'LightGoldenRodYellow', 'LightGrey',
77
+ 'LightGreen', 'LightPink', 'LightSalmon', 'LightSeaGreen', 'LightSkyBlue',
78
+ 'LightSlateGray', 'LightSlateGrey', 'LightSteelBlue', 'LightYellow', 'Lime',
79
+ 'LimeGreen', 'Linen', 'Magenta', 'MediumAquaMarine', 'MediumOrchid',
80
+ 'MediumPurple', 'MediumSeaGreen', 'MediumSpringGreen',
81
+ 'MediumTurquoise', 'MediumVioletRed', 'MintCream', 'MistyRose', 'Moccasin',
82
+ 'NavajoWhite', 'OldLace', 'Olive', 'OliveDrab', 'Orange', 'OrangeRed',
83
+ 'Orchid', 'PaleGoldenRod', 'PaleGreen', 'PaleTurquoise', 'PaleVioletRed',
84
+ 'PapayaWhip', 'PeachPuff', 'Peru', 'Pink', 'Plum', 'PowderBlue', 'Purple',
85
+ 'RosyBrown', 'RoyalBlue', 'SaddleBrown', 'SandyBrown',
86
+ 'SeaGreen', 'SeaShell', 'Sienna', 'Silver', 'SkyBlue', 'SlateBlue',
87
+ 'SlateGray', 'SlateGrey', 'Snow', 'SpringGreen', 'SteelBlue', 'GreenYellow',
88
+ 'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'YellowGreen'
89
+ ]
90
+ RGB_MIN_RANDOM_STANDARD_COLORS =[ImageColor.getrgb(x) for x in MIN_RANDOM_STANDARD_COLORS]
91
+
92
+
93
+ def save_image_array_as_png(image, output_path):
94
+ """Saves an image (represented as a numpy array) to PNG.
95
+
96
+ Args:
97
+ image: a numpy array with shape [height, width, 3].
98
+ output_path: path to which image should be written.
99
+ """
100
+ image_pil = Image.fromarray(np.uint8(image)).convert('RGB')
101
+ with open(output_path, 'wb') as fid:
102
+ image_pil.save(fid, 'PNG')
103
+
104
+
105
+ def encode_image_array_as_png_str(image):
106
+ """Encodes a numpy array into a PNG string.
107
+
108
+ Args:
109
+ image: a numpy array with shape [height, width, 3].
110
+
111
+ Returns:
112
+ PNG encoded image string.
113
+ """
114
+ image_pil = Image.fromarray(np.uint8(image))
115
+ output = six.BytesIO()
116
+ image_pil.save(output, format='PNG')
117
+ png_string = output.getvalue()
118
+ output.close()
119
+ return png_string
120
+
121
+
122
+ def draw_bounding_box_on_image_array(image,
123
+ ymin,
124
+ xmin,
125
+ ymax,
126
+ xmax,
127
+ color='red',
128
+ thickness=4,
129
+ display_str_list=(),
130
+ use_normalized_coordinates=True):
131
+ """Adds a bounding box to an image (numpy array).
132
+
133
+ Bounding box coordinates can be specified in either absolute (pixel) or
134
+ normalized coordinates by setting the use_normalized_coordinates argument.
135
+
136
+ Args:
137
+ image: a numpy array with shape [height, width, 3].
138
+ ymin: ymin of bounding box.
139
+ xmin: xmin of bounding box.
140
+ ymax: ymax of bounding box.
141
+ xmax: xmax of bounding box.
142
+ color: color to draw bounding box. Default is red.
143
+ thickness: line thickness. Default value is 4.
144
+ display_str_list: list of strings to display in box
145
+ (each to be shown on its own line).
146
+ use_normalized_coordinates: If True (default), treat coordinates
147
+ ymin, xmin, ymax, xmax as relative to the image. Otherwise treat
148
+ coordinates as absolute.
149
+ """
150
+ image_pil = Image.fromarray(np.uint8(image)).convert('RGB')
151
+ draw_bounding_box_on_image(image_pil, ymin, xmin, ymax, xmax, color,
152
+ thickness, display_str_list,
153
+ use_normalized_coordinates)
154
+ np.copyto(image, np.array(image_pil))
155
+
156
+
157
+ def draw_bounding_box_on_image(image,
158
+ ymin,
159
+ xmin,
160
+ ymax,
161
+ xmax,
162
+ color='red',
163
+ thickness=4,
164
+ display_str_list=(),
165
+ use_normalized_coordinates=True):
166
+ """Adds a bounding box to an image.
167
+
168
+ Bounding box coordinates can be specified in either absolute (pixel) or
169
+ normalized coordinates by setting the use_normalized_coordinates argument.
170
+
171
+ Each string in display_str_list is displayed on a separate line above the
172
+ bounding box in black text on a rectangle filled with the input 'color'.
173
+ If the top of the bounding box extends to the edge of the image, the strings
174
+ are displayed below the bounding box.
175
+
176
+ Args:
177
+ image: a PIL.Image object.
178
+ ymin: ymin of bounding box.
179
+ xmin: xmin of bounding box.
180
+ ymax: ymax of bounding box.
181
+ xmax: xmax of bounding box.
182
+ color: color to draw bounding box. Default is red.
183
+ thickness: line thickness. Default value is 4.
184
+ display_str_list: list of strings to display in box
185
+ (each to be shown on its own line).
186
+ use_normalized_coordinates: If True (default), treat coordinates
187
+ ymin, xmin, ymax, xmax as relative to the image. Otherwise treat
188
+ coordinates as absolute.
189
+ """
190
+ draw = ImageDraw.Draw(image)
191
+ im_width, im_height = image.size
192
+ if use_normalized_coordinates:
193
+ (left, right, top, bottom) = (xmin * im_width, xmax * im_width,
194
+ ymin * im_height, ymax * im_height)
195
+ else:
196
+ (left, right, top, bottom) = (xmin, xmax, ymin, ymax)
197
+ draw.line([(left, top), (left, bottom), (right, bottom),
198
+ (right, top), (left, top)], width=thickness, fill=color)
199
+ try:
200
+ font = ImageFont.truetype('arial.ttf', 24)
201
+ except IOError:
202
+ font = ImageFont.load_default()
203
+
204
+ # If the total height of the display strings added to the top of the bounding
205
+ # box exceeds the top of the image, stack the strings below the bounding box
206
+ # instead of above.
207
+ display_str_heights = [font.getsize(ds)[1] for ds in display_str_list]
208
+ # Each display_str has a top and bottom margin of 0.05x.
209
+ total_display_str_height = (1 + 2 * 0.05) * sum(display_str_heights)
210
+
211
+ if top > total_display_str_height:
212
+ text_bottom = top
213
+ else:
214
+ text_bottom = bottom + total_display_str_height
215
+ # Reverse list and print from bottom to top.
216
+ for display_str in display_str_list[::-1]:
217
+ text_width, text_height = font.getsize(display_str)
218
+ margin = np.ceil(0.05 * text_height)
219
+ draw.rectangle(
220
+ [(left, text_bottom - text_height - 2 * margin), (left + text_width,
221
+ text_bottom)],
222
+ fill=color)
223
+ draw.text(
224
+ (left + margin, text_bottom - text_height - margin),
225
+ display_str,
226
+ fill='black',
227
+ font=font)
228
+ text_bottom -= text_height - 2 * margin
229
+
230
+
231
+ def draw_bounding_boxes_on_image_array(image,
232
+ boxes,
233
+ color='red',
234
+ thickness=4,
235
+ display_str_list_list=()):
236
+ """Draws bounding boxes on image (numpy array).
237
+
238
+ Args:
239
+ image: a numpy array object.
240
+ boxes: a 2 dimensional numpy array of [N, 4]: (ymin, xmin, ymax, xmax).
241
+ The coordinates are in normalized format between [0, 1].
242
+ color: color to draw bounding box. Default is red.
243
+ thickness: line thickness. Default value is 4.
244
+ display_str_list_list: list of list of strings.
245
+ a list of strings for each bounding box.
246
+ The reason to pass a list of strings for a
247
+ bounding box is that it might contain
248
+ multiple labels.
249
+
250
+ Raises:
251
+ ValueError: if boxes is not a [N, 4] array
252
+ """
253
+ image_pil = Image.fromarray(image)
254
+ draw_bounding_boxes_on_image(image_pil, boxes, color, thickness,
255
+ display_str_list_list)
256
+ np.copyto(image, np.array(image_pil))
257
+
258
+
259
+ def draw_bounding_boxes_on_image(image,
260
+ boxes,
261
+ color='red',
262
+ thickness=4,
263
+ display_str_list_list=()):
264
+ """Draws bounding boxes on image.
265
+
266
+ Args:
267
+ image: a PIL.Image object.
268
+ boxes: a 2 dimensional numpy array of [N, 4]: (ymin, xmin, ymax, xmax).
269
+ The coordinates are in normalized format between [0, 1].
270
+ color: color to draw bounding box. Default is red.
271
+ thickness: line thickness. Default value is 4.
272
+ display_str_list_list: list of list of strings.
273
+ a list of strings for each bounding box.
274
+ The reason to pass a list of strings for a
275
+ bounding box is that it might contain
276
+ multiple labels.
277
+
278
+ Raises:
279
+ ValueError: if boxes is not a [N, 4] array
280
+ """
281
+ boxes_shape = boxes.shape
282
+ if not boxes_shape:
283
+ return
284
+ if len(boxes_shape) != 2 or boxes_shape[1] != 4:
285
+ raise ValueError('Input must be of size [N, 4]')
286
+ for i in range(boxes_shape[0]):
287
+ display_str_list = ()
288
+ if display_str_list_list:
289
+ display_str_list = display_str_list_list[i]
290
+ draw_bounding_box_on_image(image, boxes[i, 0], boxes[i, 1], boxes[i, 2],
291
+ boxes[i, 3], color, thickness, display_str_list)
292
+
293
+
294
+ def _visualize_boxes(image, boxes, classes, scores, category_index, **kwargs):
295
+ return visualize_boxes_and_labels_on_image_array(
296
+ image, boxes, classes, scores, category_index=category_index, **kwargs)
297
+
298
+
299
+ def _visualize_boxes_and_masks(image, boxes, classes, scores, masks,
300
+ category_index, **kwargs):
301
+ return visualize_boxes_and_labels_on_image_array(
302
+ image,
303
+ boxes,
304
+ classes,
305
+ scores,
306
+ category_index=category_index,
307
+ instance_masks=masks,
308
+ **kwargs)
309
+
310
+
311
+ def _visualize_boxes_and_keypoints(image, boxes, classes, scores, keypoints,
312
+ category_index, **kwargs):
313
+ return visualize_boxes_and_labels_on_image_array(
314
+ image,
315
+ boxes,
316
+ classes,
317
+ scores,
318
+ category_index=category_index,
319
+ keypoints=keypoints,
320
+ **kwargs)
321
+
322
+
323
+ def _visualize_boxes_and_masks_and_keypoints(
324
+ image, boxes, classes, scores, masks, keypoints, category_index, **kwargs):
325
+ return visualize_boxes_and_labels_on_image_array(
326
+ image,
327
+ boxes,
328
+ classes,
329
+ scores,
330
+ category_index=category_index,
331
+ instance_masks=masks,
332
+ keypoints=keypoints,
333
+ **kwargs)
334
+
335
+
336
+ def draw_keypoints_on_image_array(image,
337
+ keypoints,
338
+ color='red',
339
+ radius=2,
340
+ points_pair=None,
341
+ use_normalized_coordinates=True):
342
+ """Draws keypoints on an image (numpy array).
343
+
344
+ Args:
345
+ image: a numpy array with shape [height, width, 3].
346
+ keypoints: a numpy array with shape [num_keypoints, 2] or [N,num_keypoits,2] (x,y)
347
+ color: color to draw the keypoints with. Default is red.
348
+ radius: keypoint radius. Default value is 2.
349
+ use_normalized_coordinates: if True (default), treat keypoint values as
350
+ relative to the image. Otherwise treat them as absolute.
351
+ """
352
+ image_pil = Image.fromarray(np.uint8(image)).convert('RGB')
353
+ if len(keypoints.shape) == 2:
354
+ draw_keypoints_on_image(image_pil, keypoints, color, radius,
355
+ points_pair,
356
+ use_normalized_coordinates)
357
+ elif len(keypoints.shape) == 3:
358
+ for i in range(keypoints.shape[0]):
359
+ draw_keypoints_on_image(image_pil, keypoints[i], color, radius,
360
+ points_pair,
361
+ use_normalized_coordinates)
362
+ else:
363
+ print(f"Error keypoints shape {keypoints.shape}")
364
+ np.copyto(image, np.array(image_pil))
365
+ return image
366
+
367
+
368
+ def draw_keypoints_on_image(image,
369
+ keypoints,
370
+ color='red',
371
+ radius=2,
372
+ points_pair=None,
373
+ use_normalized_coordinates=True):
374
+ """Draws keypoints on an image.
375
+
376
+ Args:
377
+ image: a PIL.Image object.
378
+ keypoints: a numpy array with shape [num_keypoints, 2], (x,y)
379
+ color: color to draw the keypoints with. Default is red.
380
+ radius: keypoint radius. Default value is 2.
381
+ points_pair:[[index0,index1],...] or None
382
+ use_normalized_coordinates: if True (default), treat keypoint values as
383
+ relative to the image. Otherwise treat them as absolute.
384
+ """
385
+ draw = ImageDraw.Draw(image)
386
+ im_width, im_height = image.size
387
+ keypoints_x = [k[0] for k in keypoints]
388
+ keypoints_y = [k[1] for k in keypoints]
389
+ if use_normalized_coordinates:
390
+ keypoints_x = tuple([im_width * x if x>=0 else -1 for x in keypoints_x])
391
+ keypoints_y = tuple([im_height * y if y>=0 else -1 for y in keypoints_y])
392
+ i=0
393
+ for keypoint_x, keypoint_y in zip(keypoints_x, keypoints_y):
394
+ if keypoint_x>=0:
395
+ draw.ellipse([(keypoint_x - radius, keypoint_y - radius),
396
+ (keypoint_x + radius, keypoint_y + radius)],
397
+ outline=color, fill=color)
398
+ draw.text((keypoint_x,keypoint_y),f"{i}",fill=color)
399
+ i += 1
400
+
401
+ if points_pair is not None:
402
+ for pair in points_pair:
403
+ index0 = pair[0]
404
+ index1 = pair[1]
405
+ x0 = keypoints_x[index0]
406
+ y0 = keypoints_y[index0]
407
+ x1 = keypoints_x[index1]
408
+ y1 = keypoints_y[index1]
409
+ if x0>=0 and x1 >= 0:
410
+ draw.line((x0,y0,x1,y1),"blue")
411
+
412
+ return image
413
+
414
+
415
+ def draw_mask_on_image_array(image, mask, color='red', alpha=0.4):
416
+ """Draws mask on an image.
417
+
418
+ Args:
419
+ image: uint8 numpy array with shape (img_height, img_height, 3)
420
+ mask: a uint8 numpy array of shape (img_height, img_height) with
421
+ values between either 0 or 1.
422
+ color: color to draw the keypoints with. Default is red.
423
+ alpha: transparency value between 0 and 1. (default: 0.4)
424
+
425
+ Raises:
426
+ ValueError: On incorrect data type for image or masks.
427
+ """
428
+ if image.dtype != np.uint8:
429
+ raise ValueError('`image` not of type np.uint8')
430
+ if mask.dtype != np.uint8:
431
+ raise ValueError('`mask` not of type np.uint8')
432
+ if np.any(np.logical_and(mask != 1, mask != 0)):
433
+ raise ValueError('`mask` elements should be in [0, 1]')
434
+ if image.shape[:2] != mask.shape:
435
+ raise ValueError('The image has spatial dimensions %s but the mask has '
436
+ 'dimensions %s' % (image.shape[:2], mask.shape))
437
+ if isinstance(color,tuple) or isinstance(color,list):
438
+ rgb = color
439
+ else:
440
+ if not isinstance(color,str):
441
+ color = str(color,encoding="utf-8")
442
+ rgb = ImageColor.getrgb(color)
443
+ pil_image = Image.fromarray(image)
444
+
445
+ solid_color = np.expand_dims(
446
+ np.ones_like(mask), axis=2) * np.reshape(list(rgb), [1, 1, 3])
447
+ pil_solid_color = Image.fromarray(np.uint8(solid_color)).convert('RGBA')
448
+ pil_mask = Image.fromarray(np.uint8(255.0*alpha*mask)).convert('L')
449
+ if np.max(mask)==0:
450
+ return image
451
+ pil_image = Image.composite(pil_solid_color, pil_image, pil_mask)
452
+ np.copyto(image, np.array(pil_image.convert('RGB')))
453
+ mask = mask*200
454
+ contours,hierarchy = cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
455
+ cv2.drawContours(image,contours,-1,rgb,2)
456
+ return image
457
+
458
+ def draw_polygon_mask_on_image_array(image, mask, color='red', thickness=2):
459
+ """Draws mask on an image.
460
+
461
+ Args:
462
+ image: uint8 numpy array with shape (img_height, img_height, 3)
463
+ mask: a uint8 numpy array of shape (img_height, img_height) with
464
+ values between either 0 or 1.
465
+ color: color to draw the keypoints with. Default is red.
466
+ alpha: transparency value between 0 and 1. (default: 0.4)
467
+
468
+ Raises:
469
+ ValueError: On incorrect data type for image or masks.
470
+ """
471
+ if isinstance(color,tuple) or isinstance(color,list):
472
+ rgb = color
473
+ else:
474
+ if not isinstance(color,str):
475
+ color = str(color,encoding="utf-8")
476
+ rgb = ImageColor.getrgb(color)
477
+ cv2.drawContours(image,mask,-1,rgb,thickness=thickness)
478
+ return image
479
+
480
+ def visualize_boxes_and_labels_on_image_array(
481
+ image,
482
+ boxes,
483
+ classes,
484
+ scores,
485
+ category_index,
486
+ instance_masks=None,
487
+ instance_boundaries=None,
488
+ keypoints=None,
489
+ use_normalized_coordinates=False,
490
+ max_boxes_to_draw=20,
491
+ min_score_thresh=.5,
492
+ agnostic_mode=False,
493
+ line_thickness=4,
494
+ groundtruth_box_visualization_color='black',
495
+ skip_scores=False,
496
+ skip_labels=False):
497
+ """Overlay labeled boxes on an image with formatted scores and label names.
498
+
499
+ This function groups boxes that correspond to the same location
500
+ and creates a display string for each detection and overlays these
501
+ on the image. Note that this function modifies the image in place, and returns
502
+ that same image.
503
+
504
+ Args:
505
+ image: uint8 numpy array with shape (img_height, img_width, 3)
506
+ boxes: a numpy array of shape [N, 4]
507
+ classes: a numpy array of shape [N]. Note that class indices are 1-based,
508
+ and match the keys in the label map.
509
+ scores: a numpy array of shape [N] or None. If scores=None, then
510
+ this function assumes that the boxes to be plotted are groundtruth
511
+ boxes and plot all boxes as black with no classes or scores.
512
+ category_index: a dict containing category dictionaries (each holding
513
+ category index `id` and category name `name`) keyed by category indices.
514
+ instance_masks: a numpy array of shape [N, image_height, image_width] with
515
+ values ranging between 0 and 1, can be None.
516
+ instance_boundaries: a numpy array of shape [N, image_height, image_width]
517
+ with values ranging between 0 and 1, can be None.
518
+ keypoints: a numpy array of shape [N, num_keypoints, 2], can
519
+ be None
520
+ use_normalized_coordinates: whether boxes is to be interpreted as
521
+ normalized coordinates or not.
522
+ max_boxes_to_draw: maximum number of boxes to visualize. If None, draw
523
+ all boxes.
524
+ min_score_thresh: minimum score threshold for a box to be visualized
525
+ agnostic_mode: boolean (default: False) controlling whether to evaluate in
526
+ class-agnostic mode or not. This mode will display scores but ignore
527
+ classes.
528
+ line_thickness: integer (default: 4) controlling line width of the boxes.
529
+ groundtruth_box_visualization_color: box color for visualizing groundtruth
530
+ boxes
531
+ skip_scores: whether to skip score when drawing a single detection
532
+ skip_labels: whether to skip label when drawing a single detection
533
+
534
+ Returns:
535
+ uint8 numpy array with shape (img_height, img_width, 3) with overlaid boxes.
536
+ """
537
+ # Create a display string (and color) for every box location, group any boxes
538
+ # that correspond to the same location.
539
+ box_to_display_str_map = collections.defaultdict(list)
540
+ box_to_color_map = collections.defaultdict(str)
541
+ box_to_instance_masks_map = {}
542
+ box_to_instance_boundaries_map = {}
543
+ box_to_keypoints_map = collections.defaultdict(list)
544
+ if not max_boxes_to_draw:
545
+ max_boxes_to_draw = boxes.shape[0]
546
+ for i in range(min(max_boxes_to_draw, boxes.shape[0])):
547
+ #print(boxes.shape,scores,i)
548
+ #sys.stdout.flush()
549
+ if scores is None or scores[i] > min_score_thresh:
550
+ box = tuple(boxes[i].tolist())
551
+ if instance_masks is not None:
552
+ box_to_instance_masks_map[box] = instance_masks[i]
553
+ if instance_boundaries is not None:
554
+ box_to_instance_boundaries_map[box] = instance_boundaries[i]
555
+ if keypoints is not None:
556
+ box_to_keypoints_map[box].extend(keypoints[i])
557
+ if scores is None:
558
+ box_to_color_map[box] = groundtruth_box_visualization_color
559
+ else:
560
+ display_str = ''
561
+ if not skip_labels:
562
+ if not agnostic_mode:
563
+ if classes[i] in category_index.keys():
564
+ class_name = category_index[classes[i]]
565
+ else:
566
+ class_name = f'L{classes[i]}'
567
+ display_str = str(class_name)
568
+ if not skip_scores and scores[i]<0.95:
569
+ if not display_str:
570
+ display_str = '{}%'.format(int(100*scores[i]))
571
+ else:
572
+ display_str = '{}: {}%'.format(display_str, int(100*scores[i]))
573
+ box_to_display_str_map[box].append(display_str)
574
+ if agnostic_mode:
575
+ box_to_color_map[box] = 'DarkOrange'
576
+ else:
577
+ box_to_color_map[box] = MIN_RANDOM_STANDARD_COLORS[
578
+ classes[i] % len(MIN_RANDOM_STANDARD_COLORS)]
579
+
580
+ # Draw all boxes onto image.
581
+ for box, color in box_to_color_map.items():
582
+ ymin, xmin, ymax, xmax = box
583
+ if instance_masks is not None:
584
+ draw_mask_on_image_array(
585
+ image,
586
+ box_to_instance_masks_map[box],
587
+ color=color
588
+ )
589
+ if instance_boundaries is not None:
590
+ draw_mask_on_image_array(
591
+ image,
592
+ box_to_instance_boundaries_map[box],
593
+ color='red',
594
+ alpha=1.0
595
+ )
596
+ draw_bounding_box_on_image_array(
597
+ image,
598
+ ymin,
599
+ xmin,
600
+ ymax,
601
+ xmax,
602
+ color=color,
603
+ thickness=line_thickness,
604
+ display_str_list=box_to_display_str_map[box],
605
+ use_normalized_coordinates=use_normalized_coordinates)
606
+ if keypoints is not None:
607
+ draw_keypoints_on_image_array(
608
+ image,
609
+ box_to_keypoints_map[box],
610
+ color=color,
611
+ radius=line_thickness / 2,
612
+ use_normalized_coordinates=use_normalized_coordinates)
613
+
614
+ return image
615
+
616
+
617
+
618
+ def poly_to_mask(poly,value=1.,size=[512,512],image=None,dtype=np.uint8):
619
+
620
+ if image is None:
621
+ image = np.zeros(size,dtype=dtype)
622
+ if not isinstance(poly,np.ndarray):
623
+ poly = np.array(poly,np.int32)
624
+ assert (poly.min()>=0),"error value"
625
+ max = poly.max(axis=0)
626
+ assert (max[0]<=size[0]),"error value"
627
+ assert (max[1]<=size[1]),"error value"
628
+ poly = np.reshape(poly,[1,-1,2])
629
+ cv.fillPoly(image,poly,color=value)
630
+ return image
631
+
632
+ def points_to_mask(points,value=1.,point_size=[3,3],size=(512,512),image=None,dtype=np.uint8):
633
+
634
+ if image is None:
635
+ image = np.zeros(size,dtype=dtype)
636
+
637
+ keypoints_x = np.array([k[1] for k in points])
638
+ keypoints_y = np.array([k[0] for k in points])
639
+
640
+ if isinstance(point_size,int):
641
+ point_size = [point_size,point_size]
642
+
643
+ #assert (keypoints_x.min()>=0),"error value"
644
+ #assert (keypoints_y.min()>=0),"error value"
645
+ #assert (keypoints_x.max()<=size[0]),"error value"
646
+ #assert (keypoints_y.max()<=size[1]),"error value"
647
+
648
+ radius_x = (point_size[0]-1)//2
649
+ radius_y = (point_size[1]-1)//2
650
+
651
+ for keypoint_x, keypoint_y in zip(keypoints_x, keypoints_y):
652
+ if keypoint_x<0 or keypoint_x>=size[0] or keypoint_y<0 or keypoint_y>=size[1]:
653
+ continue
654
+ cv.ellipse(image,center=(keypoint_x,keypoint_y),axes=(radius_x,radius_y),angle=0,startAngle=0,endAngle=360,
655
+ color=value,thickness=-1)
656
+
657
+ return image
658
+