dataflow-cv 0.2.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.
dataflow/__init__.py ADDED
@@ -0,0 +1,150 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ @Time : 2026/3/8 20:41
5
+ @File : __init__.py
6
+ @Author : zj
7
+ @Description: DataFlow-CV: A data processing library for computer vision datasets
8
+ """
9
+
10
+ __version__ = "0.2.0"
11
+ __author__ = "DataFlow Team"
12
+ __description__ = "A data processing library for computer vision datasets"
13
+
14
+ # Configuration
15
+ from .config import Config
16
+
17
+ # Converters
18
+ from .convert.coco_to_yolo import CocoToYoloConverter
19
+ from .convert.yolo_to_coco import YoloToCocoConverter
20
+
21
+ # Visualizers
22
+ from .visualize.yolo import YoloVisualizer
23
+ from .visualize.coco import CocoVisualizer
24
+
25
+ # Base classes
26
+ from .convert.base import BaseConverter
27
+
28
+ # CLI
29
+ from .cli import cli, main
30
+
31
+ # Convenience functions for common conversions
32
+ def coco_to_yolo(coco_json_path: str, output_dir: str, **kwargs):
33
+ """
34
+ Convert COCO JSON to YOLO format.
35
+
36
+ Args:
37
+ coco_json_path: Path to COCO JSON file
38
+ output_dir: Output directory where labels/ and class.names will be created
39
+ **kwargs: Additional options passed to CocoToYoloConverter.convert()
40
+
41
+ Returns:
42
+ Dictionary with conversion statistics
43
+ """
44
+ converter = CocoToYoloConverter()
45
+ return converter.convert(coco_json_path, output_dir, **kwargs)
46
+
47
+
48
+ def yolo_to_coco(
49
+ image_dir: str,
50
+ yolo_labels_dir: str,
51
+ yolo_class_path: str,
52
+ coco_json_path: str,
53
+ **kwargs
54
+ ):
55
+ """
56
+ Convert YOLO format to COCO JSON.
57
+
58
+ Args:
59
+ image_dir: Directory containing image files
60
+ yolo_labels_dir: Directory containing YOLO label files
61
+ yolo_class_path: Path to YOLO class names file
62
+ coco_json_path: Path to save COCO JSON file
63
+ **kwargs: Additional options passed to YoloToCocoConverter.convert()
64
+
65
+ Returns:
66
+ Dictionary with conversion statistics
67
+ """
68
+ converter = YoloToCocoConverter()
69
+ return converter.convert(
70
+ image_dir, yolo_labels_dir, yolo_class_path, coco_json_path, **kwargs
71
+ )
72
+
73
+
74
+ # Convenience functions for visualization
75
+ def visualize_yolo(
76
+ image_dir: str,
77
+ label_dir: str,
78
+ class_path: str,
79
+ save_dir: str = None,
80
+ **kwargs
81
+ ):
82
+ """
83
+ Visualize YOLO format annotations.
84
+
85
+ Args:
86
+ image_dir: Directory containing image files
87
+ label_dir: Directory containing YOLO label files
88
+ class_path: Path to class names file (e.g., class.names)
89
+ save_dir: Directory to save visualized images (optional)
90
+ **kwargs: Additional options passed to YoloVisualizer.visualize()
91
+
92
+ Returns:
93
+ Dictionary with visualization statistics
94
+ """
95
+ visualizer = YoloVisualizer(**kwargs)
96
+ return visualizer.visualize(image_dir, label_dir, class_path, save_dir)
97
+
98
+
99
+ def visualize_coco(
100
+ image_dir: str,
101
+ annotation_json: str,
102
+ save_dir: str = None,
103
+ **kwargs
104
+ ):
105
+ """
106
+ Visualize COCO format annotations.
107
+
108
+ Args:
109
+ image_dir: Directory containing image files
110
+ annotation_json: Path to COCO JSON annotation file
111
+ save_dir: Directory to save visualized images (optional)
112
+ **kwargs: Additional options passed to CocoVisualizer.visualize()
113
+
114
+ Returns:
115
+ Dictionary with visualization statistics
116
+ """
117
+ visualizer = CocoVisualizer(**kwargs)
118
+ return visualizer.visualize(image_dir, annotation_json, save_dir)
119
+
120
+
121
+ __all__ = [
122
+ # Configuration
123
+ "Config",
124
+
125
+ # Converters
126
+ "CocoToYoloConverter",
127
+ "YoloToCocoConverter",
128
+
129
+ # Visualizers
130
+ "YoloVisualizer",
131
+ "CocoVisualizer",
132
+
133
+ # Base classes
134
+ "BaseConverter",
135
+
136
+ # CLI
137
+ "cli",
138
+ "main",
139
+
140
+ # Convenience functions
141
+ "coco_to_yolo",
142
+ "yolo_to_coco",
143
+ "visualize_yolo",
144
+ "visualize_coco",
145
+
146
+ # Metadata
147
+ "__version__",
148
+ "__author__",
149
+ "__description__",
150
+ ]
dataflow/cli.py ADDED
@@ -0,0 +1,286 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ @Time : 2026/3/8 20:41
5
+ @File : cli.py
6
+ @Author : zj
7
+ @Description: Command-line interface for DataFlow-CV
8
+ """
9
+
10
+ import os
11
+ import click
12
+ from dataflow.convert.coco_to_yolo import CocoToYoloConverter
13
+ from dataflow.convert.yolo_to_coco import YoloToCocoConverter
14
+ from dataflow.visualize.yolo import YoloVisualizer
15
+ from dataflow.visualize.coco import CocoVisualizer
16
+ from dataflow.config import Config
17
+ from dataflow import __version__
18
+
19
+
20
+ @click.group(context_settings={'help_option_names': ['-h', '--help']}, invoke_without_command=True)
21
+ @click.option('--verbose', '-v', is_flag=True, help='Enable verbose output')
22
+ @click.option('--overwrite', is_flag=True, help='Overwrite existing files')
23
+ @click.version_option(version=__version__, prog_name='DataFlow-CV')
24
+ @click.pass_context
25
+ def cli(ctx, verbose, overwrite):
26
+ """DataFlow-CV: Computer vision dataset processing tool."""
27
+ # Store configuration in context
28
+ ctx.ensure_object(dict)
29
+ ctx.obj['verbose'] = verbose
30
+ ctx.obj['overwrite'] = overwrite
31
+
32
+ # Update global config based on CLI options
33
+ if verbose:
34
+ Config.VERBOSE = True
35
+ if overwrite:
36
+ Config.OVERWRITE_EXISTING = True
37
+
38
+ # If no subcommand was invoked, show help
39
+ if ctx.invoked_subcommand is None:
40
+ click.echo(ctx.get_help())
41
+ return
42
+
43
+ if verbose:
44
+ click.echo(f"Verbose mode: {'ON' if verbose else 'OFF'}")
45
+ click.echo(f"Overwrite mode: {'ON' if overwrite else 'OFF'}")
46
+
47
+
48
+ @cli.group()
49
+ @click.pass_context
50
+ def convert(ctx):
51
+ """Convert between different annotation formats."""
52
+ pass
53
+
54
+
55
+ @convert.command(name='coco2yolo')
56
+ @click.argument('coco_json_path', type=click.Path(exists=True, dir_okay=False))
57
+ @click.argument('output_dir', type=click.Path(file_okay=False))
58
+ @click.option('--segmentation', '-s', is_flag=True, help='Handle segmentation annotations')
59
+ @click.pass_context
60
+ def coco2yolo(ctx, coco_json_path, output_dir, segmentation):
61
+ """
62
+ Convert COCO JSON to YOLO format.
63
+
64
+ \b
65
+ COCO_JSON_PATH: Path to COCO JSON annotation file
66
+ OUTPUT_DIR: Directory where labels/ and class.names will be created
67
+ """
68
+ try:
69
+ # Update config for segmentation if needed
70
+ if segmentation:
71
+ Config.YOLO_SEGMENTATION = True
72
+
73
+ click.echo(f"Converting COCO JSON: {coco_json_path}")
74
+ click.echo(f"Output directory: {output_dir}")
75
+
76
+ # Create converter and perform conversion
77
+ converter = CocoToYoloConverter(verbose=ctx.obj['verbose'])
78
+ result = converter.convert(coco_json_path, output_dir)
79
+
80
+ # Print summary
81
+ click.echo("\n" + "="*50)
82
+ click.echo("CONVERSION SUMMARY")
83
+ click.echo("="*50)
84
+ click.echo(f"COCO JSON: {result.get('coco_json_path')}")
85
+ click.echo(f"Output directory: {result.get('output_dir')}")
86
+ click.echo(f"Labels directory: {result.get('labels_dir')}")
87
+ click.echo(f"Classes file: {result.get('classes_file')}")
88
+ click.echo(f"Total images: {result.get('total_images', 0)}")
89
+ click.echo(f"Images processed: {result.get('images_processed', 0)}")
90
+ click.echo(f"Images with annotations: {result.get('images_with_annotations', 0)}")
91
+ click.echo(f"Annotations processed: {result.get('annotations_processed', 0)}")
92
+ click.echo(f"Total categories: {result.get('total_categories', 0)}")
93
+
94
+ click.echo("\n✅ Conversion completed successfully!")
95
+
96
+ except Exception as e:
97
+ click.echo(f"\n❌ Error: {e}", err=True)
98
+ ctx.exit(1)
99
+
100
+
101
+ @convert.command(name='yolo2coco')
102
+ @click.argument('image_dir', type=click.Path(exists=True, file_okay=False))
103
+ @click.argument('yolo_labels_dir', type=click.Path(exists=True, file_okay=False))
104
+ @click.argument('yolo_class_path', type=click.Path(exists=True, dir_okay=False))
105
+ @click.argument('coco_json_path', type=click.Path())
106
+ @click.pass_context
107
+ def yolo2coco(ctx, image_dir, yolo_labels_dir, yolo_class_path, coco_json_path):
108
+ """
109
+ Convert YOLO format to COCO JSON.
110
+
111
+ \b
112
+ IMAGE_DIR: Directory containing image files
113
+ YOLO_LABELS_DIR: Directory containing YOLO label files
114
+ YOLO_CLASS_PATH: Path to YOLO class names file (e.g., class.names)
115
+ COCO_JSON_PATH: Path to save COCO JSON file
116
+ """
117
+ try:
118
+ click.echo(f"Image directory: {image_dir}")
119
+ click.echo(f"YOLO labels directory: {yolo_labels_dir}")
120
+ click.echo(f"YOLO classes file: {yolo_class_path}")
121
+ click.echo(f"COCO JSON output: {coco_json_path}")
122
+
123
+ # Create converter and perform conversion
124
+ converter = YoloToCocoConverter(verbose=ctx.obj['verbose'])
125
+ result = converter.convert(
126
+ image_dir, yolo_labels_dir, yolo_class_path, coco_json_path
127
+ )
128
+
129
+ # Print summary
130
+ click.echo("\n" + "="*50)
131
+ click.echo("CONVERSION SUMMARY")
132
+ click.echo("="*50)
133
+ click.echo(f"Image directory: {result.get('image_dir')}")
134
+ click.echo(f"YOLO labels directory: {result.get('yolo_labels_dir')}")
135
+ click.echo(f"YOLO classes file: {result.get('yolo_class_path')}")
136
+ click.echo(f"COCO JSON: {result.get('coco_json_path')}")
137
+ click.echo(f"Total images: {len(result.get('image_files', []))}")
138
+ click.echo(f"Images processed: {result.get('images_processed', 0)}")
139
+ click.echo(f"Images with annotations: {result.get('images_with_annotations', 0)}")
140
+ click.echo(f"Annotations processed: {result.get('annotations_processed', 0)}")
141
+ click.echo(f"Total classes: {result.get('total_classes', 0)}")
142
+ click.echo(f"Images without labels: {result.get('images_without_labels', 0)}")
143
+
144
+ click.echo("\n✅ Conversion completed successfully!")
145
+
146
+ except Exception as e:
147
+ click.echo(f"\n❌ Error: {e}", err=True)
148
+ ctx.exit(1)
149
+
150
+
151
+ @cli.group()
152
+ @click.pass_context
153
+ def visualize(ctx):
154
+ """Visualize annotations on images."""
155
+ pass
156
+
157
+
158
+ @visualize.command(name='yolo')
159
+ @click.argument('image_dir', type=click.Path(exists=True, file_okay=False))
160
+ @click.argument('label_dir', type=click.Path(exists=True, file_okay=False))
161
+ @click.argument('class_path', type=click.Path(exists=True, dir_okay=False))
162
+ @click.option('--save', type=click.Path(file_okay=False), help='Directory to save visualized images')
163
+ @click.pass_context
164
+ def visualize_yolo(ctx, image_dir, label_dir, class_path, save):
165
+ """
166
+ Visualize YOLO format annotations.
167
+
168
+ \b
169
+ IMAGE_DIR: Directory containing image files
170
+ LABEL_DIR: Directory containing YOLO label files
171
+ CLASS_PATH: Path to class names file (e.g., class.names)
172
+ """
173
+ try:
174
+ click.echo(f"Image directory: {image_dir}")
175
+ click.echo(f"Label directory: {label_dir}")
176
+ click.echo(f"Class file: {class_path}")
177
+ if save:
178
+ click.echo(f"Save directory: {save}")
179
+
180
+ # Create visualizer and perform visualization
181
+ visualizer = YoloVisualizer(verbose=ctx.obj['verbose'])
182
+ result = visualizer.visualize(image_dir, label_dir, class_path, save)
183
+
184
+ # Print summary
185
+ click.echo("\n" + "="*50)
186
+ click.echo("VISUALIZATION SUMMARY")
187
+ click.echo("="*50)
188
+ click.echo(f"Image directory: {result.get('image_dir')}")
189
+ click.echo(f"Label directory: {result.get('label_dir')}")
190
+ click.echo(f"Class file: {result.get('class_path')}")
191
+ click.echo(f"Total images: {result.get('total_images', 0)}")
192
+ click.echo(f"Images processed: {result.get('images_processed', 0)}")
193
+ click.echo(f"Images with annotations: {result.get('images_with_annotations', 0)}")
194
+ click.echo(f"Annotations processed: {result.get('annotations_processed', 0)}")
195
+ click.echo(f"Classes found: {result.get('classes_found', [])}")
196
+ if save:
197
+ click.echo(f"Saved images: {result.get('saved_images', 0)}")
198
+ click.echo(f"Save directory: {result.get('save_dir')}")
199
+
200
+ click.echo("\n✅ Visualization completed successfully!")
201
+
202
+ except Exception as e:
203
+ click.echo(f"\n❌ Error: {e}", err=True)
204
+ ctx.exit(1)
205
+
206
+
207
+ @visualize.command(name='coco')
208
+ @click.argument('image_dir', type=click.Path(exists=True, file_okay=False))
209
+ @click.argument('annotation_json', type=click.Path(exists=True, dir_okay=False))
210
+ @click.option('--save', type=click.Path(file_okay=False), help='Directory to save visualized images')
211
+ @click.pass_context
212
+ def visualize_coco(ctx, image_dir, annotation_json, save):
213
+ """
214
+ Visualize COCO format annotations.
215
+
216
+ \b
217
+ IMAGE_DIR: Directory containing image files
218
+ ANNOTATION_JSON: Path to COCO JSON annotation file
219
+ """
220
+ try:
221
+ click.echo(f"Image directory: {image_dir}")
222
+ click.echo(f"Annotation JSON: {annotation_json}")
223
+ if save:
224
+ click.echo(f"Save directory: {save}")
225
+
226
+ # Create visualizer and perform visualization
227
+ visualizer = CocoVisualizer(verbose=ctx.obj['verbose'])
228
+ result = visualizer.visualize(image_dir, annotation_json, save)
229
+
230
+ # Print summary
231
+ click.echo("\n" + "="*50)
232
+ click.echo("VISUALIZATION SUMMARY")
233
+ click.echo("="*50)
234
+ click.echo(f"Image directory: {result.get('image_dir')}")
235
+ click.echo(f"Annotation JSON: {result.get('annotation_json')}")
236
+ click.echo(f"Total images: {result.get('total_images', 0)}")
237
+ click.echo(f"Images processed: {result.get('images_processed', 0)}")
238
+ click.echo(f"Images with annotations: {result.get('images_with_annotations', 0)}")
239
+ click.echo(f"Annotations processed: {result.get('annotations_processed', 0)}")
240
+ click.echo(f"Categories found: {result.get('categories_found', [])}")
241
+ if save:
242
+ click.echo(f"Saved images: {result.get('saved_images', 0)}")
243
+ click.echo(f"Save directory: {result.get('save_dir')}")
244
+
245
+ click.echo("\n✅ Visualization completed successfully!")
246
+
247
+ except Exception as e:
248
+ click.echo(f"\n❌ Error: {e}", err=True)
249
+ ctx.exit(1)
250
+
251
+
252
+ @cli.command()
253
+ @click.pass_context
254
+ def config(ctx):
255
+ """Show current configuration."""
256
+ click.echo("DataFlow-CV Configuration")
257
+ click.echo("="*50)
258
+
259
+ config_vars = [
260
+ ("YOLO_CLASSES_FILENAME", Config.YOLO_CLASSES_FILENAME),
261
+ ("YOLO_LABELS_DIRNAME", Config.YOLO_LABELS_DIRNAME),
262
+ ("IMAGE_EXTENSIONS", Config.IMAGE_EXTENSIONS),
263
+ ("YOLO_LABEL_EXTENSION", Config.YOLO_LABEL_EXTENSION),
264
+ ("COCO_JSON_EXTENSION", Config.COCO_JSON_EXTENSION),
265
+ ("OVERWRITE_EXISTING", Config.OVERWRITE_EXISTING),
266
+ ("VERBOSE", Config.VERBOSE),
267
+ ("CREATE_DIRS", Config.CREATE_DIRS),
268
+ ("YOLO_NORMALIZE", Config.YOLO_NORMALIZE),
269
+ ("YOLO_SEGMENTATION", Config.YOLO_SEGMENTATION),
270
+ ]
271
+
272
+ for name, value in config_vars:
273
+ click.echo(f"{name:30} = {value}")
274
+
275
+ click.echo("\nCLI Context:")
276
+ for key, value in ctx.obj.items():
277
+ click.echo(f" {key}: {value}")
278
+
279
+
280
+ def main():
281
+ """Main entry point for CLI."""
282
+ cli(obj={})
283
+
284
+
285
+ if __name__ == "__main__":
286
+ main()
dataflow/config.py ADDED
@@ -0,0 +1,85 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ @Time : 2026/3/8 20:41
5
+ @File : config.py
6
+ @Author : zj
7
+ @Description: Configuration settings for DataFlow-CV
8
+ """
9
+
10
+ import os
11
+
12
+
13
+ class Config:
14
+ """Configuration class for DataFlow-CV conversion utilities."""
15
+
16
+ # File and directory names
17
+ YOLO_CLASSES_FILENAME = "class.names" # Default filename for YOLO classes
18
+ YOLO_LABELS_DIRNAME = "labels" # Default directory name for YOLO labels
19
+
20
+ # File extensions
21
+ IMAGE_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff")
22
+ YOLO_LABEL_EXTENSION = ".txt"
23
+ COCO_JSON_EXTENSION = ".json"
24
+
25
+ # Default values
26
+ DEFAULT_IMAGE_WIDTH = 640
27
+ DEFAULT_IMAGE_HEIGHT = 640
28
+ DEFAULT_IMAGE_CHANNELS = 3
29
+
30
+ # Conversion options
31
+ OVERWRITE_EXISTING = False # Whether to overwrite existing files
32
+ VERBOSE = True # Print progress information
33
+ CREATE_DIRS = True # Create missing directories automatically
34
+
35
+ # COCO format defaults
36
+ COCO_DEFAULT_INFO = {
37
+ "year": 2026,
38
+ "version": "1.0",
39
+ "description": "Converted by DataFlow-CV",
40
+ "contributor": "DataFlow Team",
41
+ "url": "https://github.com/zjykzj/DataFlow-CV",
42
+ "date_created": "2026-03-08"
43
+ }
44
+
45
+ # YOLO format defaults
46
+ YOLO_NORMALIZE = True # Normalize coordinates to [0, 1]
47
+ YOLO_SEGMENTATION = False # Whether to handle segmentation masks (polygon format)
48
+
49
+ @classmethod
50
+ def get_image_extensions(cls):
51
+ """Get tuple of valid image extensions."""
52
+ return cls.IMAGE_EXTENSIONS
53
+
54
+ @classmethod
55
+ def get_yolo_label_extension(cls):
56
+ """Get YOLO label file extension."""
57
+ return cls.YOLO_LABEL_EXTENSION
58
+
59
+ @classmethod
60
+ def get_coco_json_extension(cls):
61
+ """Get COCO JSON file extension."""
62
+ return cls.COCO_JSON_EXTENSION
63
+
64
+ @classmethod
65
+ def validate_path(cls, path, is_dir=False, create=False):
66
+ """
67
+ Validate a path and optionally create it.
68
+
69
+ Args:
70
+ path (str): Path to validate
71
+ is_dir (bool): Whether the path should be a directory
72
+ create (bool): Whether to create the directory if it doesn't exist
73
+
74
+ Returns:
75
+ bool: True if path is valid, False otherwise
76
+ """
77
+ if not path:
78
+ return False
79
+
80
+ if is_dir:
81
+ if create and cls.CREATE_DIRS:
82
+ os.makedirs(path, exist_ok=True)
83
+ return os.path.isdir(path) or (create and cls.CREATE_DIRS)
84
+ else:
85
+ return os.path.exists(os.path.dirname(path)) if os.path.dirname(path) else True
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ @Time : 2026/3/8 20:40
5
+ @File : __init__.py
6
+ @Author : zj
7
+ @Description: Conversion module for DataFlow-CV
8
+ """
9
+
10
+ from .base import BaseConverter
11
+ from .coco_to_yolo import CocoToYoloConverter
12
+ from .yolo_to_coco import YoloToCocoConverter
13
+
14
+ __all__ = [
15
+ "BaseConverter",
16
+ "CocoToYoloConverter",
17
+ "YoloToCocoConverter",
18
+ ]