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 +150 -0
- dataflow/cli.py +286 -0
- dataflow/config.py +85 -0
- dataflow/convert/__init__.py +18 -0
- dataflow/convert/base.py +220 -0
- dataflow/convert/coco_to_yolo.py +377 -0
- dataflow/convert/yolo_to_coco.py +444 -0
- dataflow/visualize/__init__.py +18 -0
- dataflow/visualize/base.py +370 -0
- dataflow/visualize/coco.py +370 -0
- dataflow/visualize/yolo.py +345 -0
- dataflow_cv-0.2.0.dist-info/METADATA +202 -0
- dataflow_cv-0.2.0.dist-info/RECORD +17 -0
- dataflow_cv-0.2.0.dist-info/WHEEL +5 -0
- dataflow_cv-0.2.0.dist-info/entry_points.txt +2 -0
- dataflow_cv-0.2.0.dist-info/licenses/LICENSE +21 -0
- dataflow_cv-0.2.0.dist-info/top_level.txt +1 -0
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
|
+
]
|