visiontext 0.33.4__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.
Files changed (65) hide show
  1. visiontext/__init__.py +1 -0
  2. visiontext/__main__.py +33 -0
  3. visiontext/audiotools.py +83 -0
  4. visiontext/bboxes.py +250 -0
  5. visiontext/cacheutils.py +66 -0
  6. visiontext/cli/__init__.py +0 -0
  7. visiontext/cli/collect_env_details.py +92 -0
  8. visiontext/cli/compare_jpeg_decoder_performance.py +48 -0
  9. visiontext/cli/download_hf_dataset.py +59 -0
  10. visiontext/cli/export_sqlite_to_csv.py +57 -0
  11. visiontext/cli/gui_lib_example.py +113 -0
  12. visiontext/cli/gui_scroll_example.py +33 -0
  13. visiontext/cli/index_tar.py +55 -0
  14. visiontext/cli/profile_gpu.py +51 -0
  15. visiontext/cli/spek.py +36 -0
  16. visiontext/cli/start_debugger.py +11 -0
  17. visiontext/colormaps.py +196 -0
  18. visiontext/configutils.py +41 -0
  19. visiontext/denormalize.py +83 -0
  20. visiontext/distutils.py +173 -0
  21. visiontext/examples/__init__.py +0 -0
  22. visiontext/examples/cc0images/__init__.py +0 -0
  23. visiontext/examples/cc0images/lowres/__init__.py +0 -0
  24. visiontext/font.py +85 -0
  25. visiontext/gui/__init__.py +0 -0
  26. visiontext/gui/gui_base.py +177 -0
  27. visiontext/gui/gui_config.py +70 -0
  28. visiontext/gui/gui_modules.py +66 -0
  29. visiontext/gui/message_box.py +66 -0
  30. visiontext/htmltools.py +238 -0
  31. visiontext/image_downloader.py +445 -0
  32. visiontext/images.py +596 -0
  33. visiontext/imports.py +128 -0
  34. visiontext/iotools/__init__.py +0 -0
  35. visiontext/iotools/feature_compression.py +169 -0
  36. visiontext/iotools/pth.py +20 -0
  37. visiontext/iotools/single_tar_lookup.py +228 -0
  38. visiontext/iotools/tar_lookup.py +371 -0
  39. visiontext/mathutils.py +154 -0
  40. visiontext/nlp/__init__.py +3 -0
  41. visiontext/nlp/lemmatizer.py +183 -0
  42. visiontext/nlp/nltktools.py +131 -0
  43. visiontext/nlp/regextools.py +15 -0
  44. visiontext/nlp/spacytools.py +43 -0
  45. visiontext/pandatools.py +154 -0
  46. visiontext/plots.py +12 -0
  47. visiontext/profiling/__init__.py +8 -0
  48. visiontext/profiling/code_profiler.py +65 -0
  49. visiontext/profiling/hardware_profiler.py +285 -0
  50. visiontext/sqlalchemist/__init__.py +31 -0
  51. visiontext/sqlalchemist/db_opener.py +61 -0
  52. visiontext/sqlalchemist/sqlalchemist.py +400 -0
  53. visiontext/terminal.py +51 -0
  54. visiontext/testdata/__init__.py +0 -0
  55. visiontext/torchutils.py +186 -0
  56. visiontext/visualize_logits.py +82 -0
  57. visiontext/visualize_ratios.py +141 -0
  58. visiontext/webdataset_pipeline.py +208 -0
  59. visiontext/webdataset_pipeline_separate_metadata.py +346 -0
  60. visiontext-0.33.4.dist-info/METADATA +132 -0
  61. visiontext-0.33.4.dist-info/RECORD +65 -0
  62. visiontext-0.33.4.dist-info/WHEEL +5 -0
  63. visiontext-0.33.4.dist-info/licenses/LICENSE +201 -0
  64. visiontext-0.33.4.dist-info/top_level.txt +1 -0
  65. visiontext-0.33.4.dist-info/zip-safe +1 -0
visiontext/__init__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.33.4"
visiontext/__main__.py ADDED
@@ -0,0 +1,33 @@
1
+ import importlib
2
+ import importlib.util
3
+ import shutil
4
+ import sys
5
+
6
+
7
+ def main():
8
+ lib_module_name = __file__.replace("\\", "/").split("/")[-2]
9
+ if len(sys.argv) <= 1:
10
+ print(f"Usage: {lib_module_name} <module> <*args>\n")
11
+ from packg.packaging import get_modules_for_autocomplete
12
+ from packg.strings import format_pseudo_table
13
+
14
+ output_modules = get_modules_for_autocomplete(lib_module_name, run_dir=None)
15
+ terminal_width = shutil.get_terminal_size().columns
16
+ print(format_pseudo_table(output_modules, max_width=terminal_width))
17
+ sys.exit(1)
18
+ target_module = sys.argv[1]
19
+ args = sys.argv[2:]
20
+ # load the spec to modify sys.argv before importing, otherwise it's too late
21
+ module_to_load = f"{lib_module_name}.{target_module}"
22
+ spec = importlib.util.find_spec(module_to_load)
23
+ if spec is None:
24
+ raise ValueError(f"Module {module_to_load} not found")
25
+ origin = spec.origin
26
+ sys.argv = [origin] + args
27
+ # import the module and run the main function
28
+ module = importlib.import_module(module_to_load)
29
+ module.main()
30
+
31
+
32
+ if __name__ == "__main__":
33
+ main()
@@ -0,0 +1,83 @@
1
+ from tempfile import NamedTemporaryFile
2
+ from typing import Tuple
3
+
4
+ import numpy as np
5
+ from loguru import logger
6
+ from pydub import AudioSegment
7
+ from scipy.io import wavfile
8
+ from scipy.signal import spectrogram
9
+
10
+ from packg import Const
11
+ from packg.typext import PathType
12
+
13
+
14
+ class AudioConvertC(Const):
15
+ NONE = "none"
16
+ MONO = "mono"
17
+ STEREO = "stereo"
18
+
19
+
20
+ def load_audio_file(
21
+ input_file: PathType, verbose: bool = False, convert=AudioConvertC.STEREO
22
+ ) -> Tuple[int, np.ndarray]:
23
+ """
24
+ Load audio file and return frequency and data.
25
+
26
+ Args:
27
+ input_file:
28
+ verbose: print debug info
29
+ convert: convert to either stereo (shape (N, 2)) or mono (shape (N,)) or leave as is.
30
+
31
+ Returns:
32
+ tuple of frequency int and data numpy array of shape (N, 2) (stereo) or (N,) (mono)
33
+
34
+ """
35
+ file_format = input_file.name.split(".")[-1]
36
+ if verbose:
37
+ logger.info(f"Reading file {input_file} detected format {file_format}")
38
+ audio = AudioSegment.from_file(input_file, format=file_format)
39
+
40
+ # convert to wav
41
+ with NamedTemporaryFile(suffix=".wav") as tmpfile:
42
+ audio.export(tmpfile, format="wav")
43
+ frequency, data = wavfile.read(tmpfile)
44
+
45
+ # convert to stereo or mono as needed
46
+ if convert == AudioConvertC.STEREO and len(data.shape) == 1:
47
+ data = np.stack([data, data], axis=-1) # mono to stereo
48
+ elif convert == AudioConvertC.MONO and len(data.shape) == 2:
49
+ data = data.mean(-1) # stereo to mono
50
+
51
+ if verbose:
52
+ logger.info(f"Got frequency {frequency} shape {data.shape} after conversion '{convert}'")
53
+
54
+ return frequency, data
55
+
56
+
57
+ def check_audio_quality(frequency, data, eps=1e-6) -> bool:
58
+ """
59
+ logic: a good quality music file will have audio at 20khz. a bad one will not.
60
+ """
61
+ # dmin, dmax = data.min(), data.max()
62
+ # dnorm = (data - dmin) / (dmax - dmin)
63
+ # print_ndarray_lovely(data) # raw mono audio
64
+ # example data shape 11,796,960 freq 48000 => 246 seconds
65
+
66
+ freqs, time, spec = spectrogram(data, fs=frequency, nperseg=256, noverlap=128)
67
+
68
+ # print_ndarray_lovely(freqs) # frequency bins
69
+ # select all bins within 19 and 21 khz
70
+ freqs_to_use = np.less_equal(19000, freqs) & np.less_equal(freqs, 21000)
71
+ # example: 129 equally spaced values from 0 ... 24000
72
+
73
+ # print_ndarray_lovely(time) # time bins
74
+ # print_ndarray_lovely(spec) # spec shape (n_freq, n_time)
75
+ smin, smax = spec.min(), spec.max()
76
+ snorm = (spec - smin) / (smax - smin)
77
+
78
+ srel = snorm[freqs_to_use]
79
+ return srel.max() > eps
80
+ # now we want to normalize with something between mean (1-norm) and max (inf-norm)
81
+ # srel_norm_freq = np.linalg.norm(srel, ord=np.inf, axis=0)
82
+ # srel_norm_all = np.linalg.norm(srel_norm_freq, ord=np.inf, axis=0)
83
+ # return srel_norm_all
visiontext/bboxes.py ADDED
@@ -0,0 +1,250 @@
1
+ from typing import Dict, List, Optional, Tuple, Union
2
+
3
+ from matplotlib import colors as mpl_colors
4
+ from PIL import Image, ImageDraw, ImageFont
5
+
6
+ from packg.maths import clip_rectangle_coords
7
+ from visiontext.colormaps import (
8
+ create_colorgetter_from_colormap,
9
+ create_colormap_for_dark_background,
10
+ )
11
+ from visiontext.font import get_dejavusans_font_path
12
+
13
+
14
+ def create_bbox_images(
15
+ bx: int,
16
+ by: int,
17
+ bw: int,
18
+ bh: int,
19
+ w: int,
20
+ h: int,
21
+ box_color=(0, 0, 255, 255),
22
+ bbox_width: int = 5,
23
+ mask_opacity: int = 64,
24
+ ) -> Dict[str, Image.Image]:
25
+ """
26
+ Create box overlay images, originally used in the OVAD visualizer e.g.:
27
+ https://lmb.informatik.uni-freiburg.de/resources/datasets/ovad/?imgnum=14#top
28
+
29
+ This function creates transparent PNGs that can be overlayed on top of an image to show or
30
+ highlight a bounding box.
31
+ """
32
+ # create one image with transparent background and one with half transparent
33
+ img = Image.new("RGBA", (w, h), (0, 0, 0, 0))
34
+ draw = ImageDraw.Draw(img)
35
+ img2 = Image.new("RGBA", (w, h), (0, 0, 0, mask_opacity))
36
+ draw2 = ImageDraw.Draw(img2)
37
+
38
+ # boxes should be approximately the same width after scaling the image
39
+ # so we have to scale the box thickness now
40
+ target_w = 800
41
+ rel_w = w / target_w # if small image, create smaller boxes
42
+ rel_bbox_width = round(bbox_width * rel_w)
43
+
44
+ # the inside of the thick drawn box will be the true bbox
45
+ # this means that the box can clip outside the image and become almost invisible
46
+ # to avoid that, we move the edges of the box outwards and then clip them
47
+ x1 = bx - rel_bbox_width
48
+ y1 = by - rel_bbox_width
49
+ x2 = bx + bw + rel_bbox_width
50
+ y2 = by + bh + rel_bbox_width
51
+ (x1, y1, x2, y2) = clip_rectangle_coords((x1, y1, x2, y2), w, h)
52
+
53
+ for bbox_step in range(rel_bbox_width):
54
+ rectangle_coords = (
55
+ x1 + bbox_step,
56
+ y1 + bbox_step,
57
+ x2 - bbox_step,
58
+ y2 - bbox_step,
59
+ )
60
+ # a 2nd clip should now not be necessary anymore and we assert instead
61
+ assert (
62
+ rectangle_coords[0] >= 0
63
+ and rectangle_coords[1] >= 0
64
+ and rectangle_coords[2] <= w
65
+ and rectangle_coords[3] <= h
66
+ ), f"{rectangle_coords} outside {w}x{h}"
67
+
68
+ draw.rectangle(rectangle_coords, fill=(0, 0, 0, 0), outline=box_color)
69
+ draw2.rectangle(rectangle_coords, fill=(0, 0, 0, 0), outline=box_color)
70
+
71
+ return {"box": img, "box-mask": img2}
72
+
73
+
74
+ def convert_bbox_abs_to_rel(bx, by, bw, bh, image_w, image_h):
75
+ """
76
+ Convert bounding box coordinates to relative coordinates.
77
+
78
+ Args:
79
+ bx: x coordinate of the top-left corner of the bounding box
80
+ by: y coordinate of the top-left corner of the bounding box
81
+ bw: width of the bounding box
82
+ bh: height of the bounding box
83
+ image_w: width of the image
84
+ image_h: height of the image
85
+
86
+ Returns:
87
+ Tuple of relative coordinates (x, y, w, h)
88
+
89
+ """
90
+ x = bx / image_w
91
+ y = by / image_h
92
+ w = bw / image_w
93
+ h = bh / image_h
94
+ return x, y, w, h
95
+
96
+
97
+ def convert_bbox_rel_to_abs(x, y, w, h, image_w, image_h):
98
+ """
99
+ Convert bounding box coordinates to absolute coordinates.
100
+
101
+ Args:
102
+ x: x coordinate of the top-left corner of the bounding box
103
+ y: y coordinate of the top-left corner of the bounding box
104
+ w: width of the bounding box
105
+ h: height of the bounding box
106
+ image_w: width of the image
107
+ image_h: height of the image
108
+
109
+ Returns:
110
+ Tuple of absolute coordinates (bx, by, bw, bh)
111
+
112
+ """
113
+ bx = x * image_w
114
+ by = y * image_h
115
+ bw = w * image_w
116
+ bh = h * image_h
117
+ return bx, by, bw, bh
118
+
119
+
120
+ def get_bbox_bounds(
121
+ box_x: float,
122
+ box_y: float,
123
+ box_w: float,
124
+ box_h: float,
125
+ image_w: int,
126
+ image_h: int,
127
+ min_w=32,
128
+ min_h=32,
129
+ create_squares=False,
130
+ ):
131
+ """
132
+ Get the bounding box boundaries for cropping the image.
133
+ Increase the box size if it is too small.
134
+
135
+ Args:
136
+ box_x: absolute box coordinates for the given image
137
+ box_y:
138
+ box_w:
139
+ box_h:
140
+ image_w: image size
141
+ image_h:
142
+ min_w: minimum box size
143
+ min_h:
144
+ create_squares: if True, try to create a square bounding box instead of a rectangle
145
+
146
+ Returns:
147
+ Cropping parameters tuple (x1, y1, x2, y2)
148
+
149
+ """
150
+ # Calculate the center coordinates of the bounding box
151
+ center_x = box_x + (box_w / 2)
152
+ center_y = box_y + (box_h / 2)
153
+
154
+ # Calculate the new width and height of the bounding box
155
+ new_w = max(box_w, min_w)
156
+ new_h = max(box_h, min_h)
157
+
158
+ if create_squares:
159
+ new_w = max(new_w, new_h)
160
+ new_h = max(new_w, new_h)
161
+ pass
162
+
163
+ # Calculate the new x and y coordinates of the top-left corner of the bounding box
164
+ new_x = center_x - (new_w / 2)
165
+ new_y = center_y - (new_h / 2)
166
+
167
+ # Adjust the new x coordinate if the box is too close to the left border
168
+ if new_x < 0:
169
+ new_x = 0
170
+ new_x2 = min(new_x + new_w, image_w)
171
+ else:
172
+ new_x2 = min(new_x + new_w, image_w)
173
+ if new_x2 > image_w:
174
+ new_x2 = image_w
175
+ new_x = max(new_x2 - new_w, 0)
176
+
177
+ # Adjust the new y coordinate if the box is too close to the top border
178
+ if new_y < 0:
179
+ new_y = 0
180
+ new_y2 = min(new_y + new_h, image_h)
181
+ else:
182
+ new_y2 = min(new_y + new_h, image_h)
183
+ if new_y2 > image_h:
184
+ new_y2 = image_h
185
+ new_y = max(new_y2 - new_h, 0)
186
+
187
+ # Again make sure all bounds are respected
188
+ new_x = max(new_x, 0)
189
+ new_y = max(new_y, 0)
190
+ new_x2 = min(new_x2, image_w)
191
+ new_y2 = min(new_y2, image_h)
192
+
193
+ # Return the cropping boundaries as integers
194
+ return int(new_x), int(new_y), int(new_x2), int(new_y2)
195
+
196
+
197
+ def draw_bounding_boxes_pil(
198
+ image: Image.Image,
199
+ boxes: List[Tuple[float, float, float, float]], # x, y, w, h
200
+ labels: Tuple[List[str], str, None] = "numbers",
201
+ colors: Optional[List[Tuple[int, int, int]]] = None,
202
+ width: int = 3,
203
+ font_size: int = 14,
204
+ cmap: Optional[Union[str, mpl_colors.Colormap]] = None,
205
+ ):
206
+ draw = ImageDraw.Draw(image)
207
+ font = ImageFont.truetype(get_dejavusans_font_path(), font_size)
208
+
209
+ if colors is None:
210
+ if cmap is None:
211
+ cmap = create_colormap_for_dark_background(add_brightness=0.5)
212
+ # automatically generate a bunch of colors from the colormap
213
+ getter = create_colorgetter_from_colormap(cmap)
214
+ colors = [tuple(getter(i / len(boxes))) for i in range(len(boxes))]
215
+
216
+ if isinstance(labels, str):
217
+ if labels == "numbers":
218
+ labels = [str(i) for i in range(len(boxes))]
219
+ else:
220
+ raise ValueError(f"Unknown label type: {labels}")
221
+
222
+ for i, (box, color) in enumerate(zip(boxes, colors)):
223
+ x, y, w, h = box
224
+ x1, y1, x2, y2 = get_bbox_bounds(x, y, w, h, image.width, image.height, min_w=0, min_h=0)
225
+ draw.rectangle([(x1, y1), (x2, y2)], outline=color, width=width)
226
+
227
+ text_args = dict(font=font, stroke_width=2)
228
+ if labels is not None:
229
+ label = labels[i]
230
+
231
+ # # removed in pillow 10...
232
+ # text_width, text_height = draw.textsize(label, **text_args)
233
+
234
+ # new version with textbbox
235
+ tx0, ty0, tx1, ty1 = draw.textbbox((0, 0), label, **text_args)
236
+ text_width = tx1 - tx0
237
+ text_height = ty1 - ty0
238
+
239
+ text_x = min(x1 + width + 2, image.width - text_width)
240
+ text_y = min(y1 + width + 2, image.height - text_height)
241
+ draw.text(
242
+ (text_x, text_y),
243
+ label,
244
+ fill=color,
245
+ anchor="lt",
246
+ stroke_fill="black",
247
+ **text_args,
248
+ )
249
+
250
+ return image
@@ -0,0 +1,66 @@
1
+ import os
2
+ from pathlib import Path
3
+ from typing import Optional
4
+
5
+ import lmdb
6
+ import msgpack
7
+ from platformdirs import user_cache_path
8
+
9
+ from packg.strings import hash_object
10
+ from packg.typext import PathType
11
+
12
+
13
+ class CachePlugin:
14
+ """
15
+ Helper to create a cache for a class.
16
+
17
+ cache_name and cache_kwargs define a unique filename.
18
+ cache_kwargs must be jsonable
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ cache_name: str,
24
+ cache_kwargs: Optional[dict] = None,
25
+ cache_dir: Optional[PathType] = None,
26
+ map_size=10 * 1024**3, # 10 GB max size of database, increase if necessary
27
+ verbose: bool = False,
28
+ ):
29
+ if cache_dir is None:
30
+ cache_dir = user_cache_path("python_visiontext")
31
+ if cache_kwargs is None:
32
+ kwargs_str = "none"
33
+ else:
34
+ kwargs_str = hash_object(cache_kwargs)
35
+
36
+ lmdb_file = Path(cache_dir) / "cache_plugin" / f"{cache_name}~{kwargs_str}.lmdb"
37
+ os.makedirs(lmdb_file.parent, exist_ok=True)
38
+ self.db: lmdb.Environment = lmdb.open(lmdb_file.as_posix(), map_size=map_size)
39
+ self.lmdb_file = lmdb_file
40
+ if verbose:
41
+ print(f"Using cache file: {self.lmdb_file}")
42
+
43
+ def get_values(self, list_of_keys):
44
+ outputs = []
45
+ with self.db.begin(write=False) as txn:
46
+ for key in list_of_keys:
47
+ bkey = msgpack.packb(key)
48
+ bvalue = txn.get(bkey)
49
+ if bvalue is None:
50
+ outputs.append(None)
51
+ else:
52
+ value = msgpack.unpackb(bvalue)
53
+ outputs.append(value)
54
+ return outputs
55
+
56
+ def put_values(self, list_of_keys, list_of_values):
57
+ assert len(list_of_keys) == len(
58
+ list_of_values
59
+ ), f"Got {len(list_of_keys)} keys and {len(list_of_values)} values."
60
+ if len(list_of_keys) == 0:
61
+ return
62
+ with self.db.begin(write=True) as txn:
63
+ for key, value in zip(list_of_keys, list_of_values):
64
+ bkey = msgpack.packb(key)
65
+ bvalue = msgpack.packb(value)
66
+ txn.put(bkey, bvalue)
File without changes
@@ -0,0 +1,92 @@
1
+ # source: github lightning-ai pytorch-lightning
2
+ #
3
+ # Copyright The Lightning AI team.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """Diagnose your system and show basic information.
17
+
18
+ This server mainly to get detail info for better bug reporting.
19
+
20
+ """
21
+
22
+ import os
23
+ import platform
24
+ import sys
25
+
26
+ import pkg_resources
27
+ import torch
28
+
29
+ sys.path += [os.path.abspath(".."), os.path.abspath("")]
30
+
31
+
32
+ LEVEL_OFFSET = "\t"
33
+ KEY_PADDING = 20
34
+
35
+
36
+ def info_system() -> dict:
37
+ return {
38
+ "OS": platform.system(),
39
+ "architecture": platform.architecture(),
40
+ "version": platform.version(),
41
+ "release": platform.release(),
42
+ "processor": platform.processor(),
43
+ "python": platform.python_version(),
44
+ }
45
+
46
+
47
+ def info_cuda() -> dict:
48
+ return {
49
+ "GPU": [torch.cuda.get_device_name(i) for i in range(torch.cuda.device_count())] or None,
50
+ "available": torch.cuda.is_available(),
51
+ "version": torch.version.cuda,
52
+ }
53
+
54
+
55
+ def info_packages() -> dict:
56
+ """Get name and version of all installed packages."""
57
+ packages = {}
58
+ for dist in pkg_resources.working_set:
59
+ package = dist.as_requirement()
60
+ packages[package.key] = package.specs[0][1]
61
+ return packages
62
+
63
+
64
+ def nice_print(details: dict, level: int = 0) -> list:
65
+ lines = []
66
+ for k in sorted(details):
67
+ key = f"* {k}:" if level == 0 else f"- {k}:"
68
+ if isinstance(details[k], dict):
69
+ lines += [level * LEVEL_OFFSET + key]
70
+ lines += nice_print(details[k], level + 1)
71
+ elif isinstance(details[k], (set, list, tuple)):
72
+ lines += [level * LEVEL_OFFSET + key]
73
+ lines += [(level + 1) * LEVEL_OFFSET + "- " + v for v in details[k]]
74
+ else:
75
+ template = "{:%is} {}" % KEY_PADDING
76
+ key_val = template.format(key, details[k])
77
+ lines += [(level * LEVEL_OFFSET) + key_val]
78
+ return lines
79
+
80
+
81
+ def main() -> None:
82
+ details = {"System": info_system(), "CUDA": info_cuda(), "Packages": info_packages()}
83
+ details["Lightning"] = {
84
+ k: v for k, v in details["Packages"].items() if "torch" in k or "lightning" in k
85
+ }
86
+ lines = nice_print(details)
87
+ text = os.linesep.join(lines)
88
+ print(f"<details>\n <summary>Current environment</summary>\n\n{text}\n\n</details>")
89
+
90
+
91
+ if __name__ == "__main__":
92
+ main()
@@ -0,0 +1,48 @@
1
+ from pathlib import Path
2
+ from timeit import default_timer
3
+
4
+ from visiontext.examples import cc0images
5
+ from visiontext.images import JPEGDecoderConst, decode_jpeg
6
+
7
+ image_shapes_highres = [(5184, 3456, 3), (2038, 3057, 3), (2560, 2048, 3)]
8
+ image_shapes_lowres = [(500, 333, 3), (333, 500, 3), (500, 400, 3)]
9
+
10
+
11
+ def main():
12
+ src_dir_base = Path(cc0images.__file__).parent
13
+
14
+ for src_dir, image_shapes, n_trials in [
15
+ (src_dir_base, image_shapes_highres, 2),
16
+ (src_dir_base / "lowres", image_shapes_lowres, 100),
17
+ ]:
18
+ print(f"Test images in {src_dir}")
19
+ images_f = list(sorted(src_dir.glob("*.jpg")))
20
+
21
+ if len(images_f) != len(image_shapes):
22
+ raise ValueError(
23
+ f"Expected {len(image_shapes)} images in {src_dir}, got {len(images_f)}"
24
+ )
25
+ images_b = [Path(image_f).read_bytes() for image_f in images_f]
26
+
27
+ for decoder in JPEGDecoderConst.values():
28
+ if decoder == JPEGDecoderConst.PILLOW_IMAGE:
29
+ continue
30
+ t0 = default_timer()
31
+ for n in range(n_trials):
32
+ for i, image_b in enumerate(images_b):
33
+ arr = decode_jpeg(image_b, method=decoder)
34
+ if n == 0:
35
+ # only test shape for first trial to not disturb the performance test
36
+ ex_s = image_shapes[i]
37
+ act_s = arr.shape
38
+ if ex_s != act_s:
39
+ raise ValueError(
40
+ f"Expected shape {ex_s} for {images_f[i]}, got {act_s}"
41
+ )
42
+ tdelta = default_timer() - t0
43
+ tper_ms = (tdelta / n_trials / len(images_f)) * 1000
44
+ print(f" Decoder {decoder} took {tper_ms:.2f} ms per image on average")
45
+
46
+
47
+ if __name__ == "__main__":
48
+ main()
@@ -0,0 +1,59 @@
1
+ """
2
+ download a dataset from huggingface.
3
+
4
+ potentially useful args:
5
+ -o name=DatasetConfigName
6
+ -o use_auth_token=True
7
+ -o split="train"
8
+ """
9
+
10
+ from pathlib import Path
11
+
12
+ from attrs import define
13
+ from loguru import logger
14
+
15
+ from packg.log import SHORTEST_FORMAT, configure_logger, get_logger_level_from_args
16
+ from packg.paths import get_packg_data_dir
17
+ from typedparser import TypedParser, VerboseQuietArgs, add_argument
18
+ from visiontext.configutils import load_dotlist
19
+
20
+
21
+ @define
22
+ class Args(VerboseQuietArgs):
23
+ base_dir: Path | None = add_argument(
24
+ shortcut="-d", type=str, help="Base dir", default=get_packg_data_dir()
25
+ )
26
+ dataset_name: str = add_argument(positional=True, type=str, help="Dataset name")
27
+ options: list[str] | None = add_argument(shortcut="-o", action="append", help="dataset kwargs")
28
+ subdir: str | None = add_argument(
29
+ shortcut="-s", type=str, help="Subdir (none=auto)", default=None
30
+ )
31
+
32
+
33
+ def main():
34
+ parser = TypedParser.create_parser(Args, description=__doc__)
35
+ args: Args = parser.parse_args()
36
+ configure_logger(level=get_logger_level_from_args(args), format=SHORTEST_FORMAT)
37
+ logger.info(f"{args}")
38
+
39
+ dict_dotlist = load_dotlist(args.options)
40
+ subdir = args.subdir
41
+ if subdir is None:
42
+ subdir = args.dataset_name.replace("/", "__")
43
+
44
+ logger.info(f"Downloading dataset {args.dataset_name} to {args.base_dir / subdir}")
45
+ try:
46
+ from datasets import load_dataset
47
+ except ImportError as e:
48
+ logger.error(f"datasets is not installed. Please install it with `pip install datasets`.")
49
+ raise e
50
+ dataset = load_dataset(
51
+ args.dataset_name,
52
+ streaming=False, # this downloads to disk
53
+ cache_dir=(args.base_dir / subdir).as_posix(),
54
+ **dict_dotlist,
55
+ )
56
+
57
+
58
+ if __name__ == "__main__":
59
+ main()
@@ -0,0 +1,57 @@
1
+ import os
2
+ import sqlite3
3
+ from pathlib import Path
4
+
5
+ import pandas as pd
6
+ from attrs import define
7
+ from loguru import logger
8
+
9
+ from packg.log import SHORTEST_FORMAT, configure_logger, get_logger_level_from_args
10
+ from typedparser import TypedParser, VerboseQuietArgs, add_argument
11
+
12
+
13
+ @define
14
+ class Args(VerboseQuietArgs):
15
+ sqlite_file: Path = add_argument(positional=True, help="sqlite file")
16
+ run_export: bool = add_argument(action="store_true", help="Run the export", shortcut="-e")
17
+
18
+
19
+ def main():
20
+ parser = TypedParser.create_parser(Args, description=__doc__)
21
+ args: Args = parser.parse_args()
22
+ configure_logger(level=get_logger_level_from_args(args), format=SHORTEST_FORMAT)
23
+ logger.info(f"{args}")
24
+
25
+ conn = sqlite3.connect(args.sqlite_file)
26
+
27
+ tables = pd.read_sql_query("SELECT name FROM sqlite_master WHERE type='table';", conn)
28
+ print("Tables in the database:")
29
+ print(tables)
30
+
31
+ # For each table, display the first few rows
32
+ for table_name in tables["name"]:
33
+ print(f"\nTable: {table_name}")
34
+ df = pd.read_sql_query(f"SELECT * FROM {table_name} LIMIT 5;", conn)
35
+ print(df)
36
+ cursor = conn.execute(f"SELECT COUNT(*) FROM {table_name}")
37
+ count = cursor.fetchone()[0]
38
+ print(f"Count: {count}")
39
+
40
+ if args.run_export:
41
+ export_dir = Path(f"{args.sqlite_file}_export")
42
+ if export_dir.is_dir():
43
+ logger.warning(f"Export directory already exists: {export_dir}")
44
+ os.makedirs(export_dir, exist_ok=True)
45
+ for table_name in tables["name"]:
46
+ print(f"\nTable: {table_name}")
47
+ df = pd.read_sql_query(f"SELECT * FROM {table_name}", conn)
48
+ print(df.shape)
49
+ csv_file = export_dir / f"{table_name}.csv"
50
+ df.to_csv(csv_file, sep=",", index=False)
51
+ print(f"Exported to: {csv_file}")
52
+
53
+ conn.close()
54
+
55
+
56
+ if __name__ == "__main__":
57
+ main()