Skip to content

Commit c974e6b

Browse files
TuturBababgruening
andauthored
Yolo class (#1790)
* Modify write_yolo_yaml to accept class names * Refactor YOLOv8 script for improved clarity * Modify YOLO training XML for input formats and parameters Updated input image formats and corrected parameter attributes. * Remove class_name parameter from YOLO prediction Removed class_name parameter from inputs and tests for YOLO prediction. * Update YOLO tool version in XML configuration * Update YOLO training tool version for galaxy6 * Enhance input image parameter for TIFF support Updated input image parameter to support TIFF format and added a validator for RGB channel count. * Clean up yolo_prediction.xml by removing comments Removed commented-out test cases for segment and detect modes. * Enhance input_images parameter with help and validation Updated input_images parameter to include a help message and validation for RGB channels. * Update yolo_prediction.xml * Fix help text for input images in yolo_training.xml * Revise input images parameter help and validation Updated help text and validation for input images in YOLO training configuration. * Fix validator expression for input image formats * Modify input_images parameter for TIFF support Updated input_images parameter to support TIFF files with 1 or 3 channels and improved validation message. * Apply suggestion from @bgruening --------- Co-authored-by: Björn Grüning <bjoern@gruenings.eu>
1 parent 1ec1ff3 commit c974e6b

4 files changed

Lines changed: 43 additions & 65 deletions

File tree

tools/image_processing/yolo/preprocessing.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,27 @@ def copy_pairs(pairs, image_src, label_src, image_dst, label_dst):
3838
copy_file(os.path.join(label_src, lbl), os.path.join(label_dst, lbl))
3939

4040

41-
def write_yolo_yaml(output_dir):
42-
43-
yolo_yaml_path = os.path.join(output_dir, "yolo.yml")
44-
with open(yolo_yaml_path, 'w') as f:
45-
f.write(f"path: {output_dir}\n")
46-
f.write("train: train\n")
47-
f.write("val: valid\n")
48-
f.write("test: test\n")
49-
f.write("\n")
50-
f.write("names: ['dataset']\n")
41+
def write_yolo_yaml(output_dir, classes):
42+
yaml_path = os.path.join(output_dir, "yolo.yml")
43+
with open(yaml_path, "w") as f:
44+
f.write("train: train/images\n")
45+
f.write("val: valid/images\n")
46+
f.write("test: test/images\n\n")
47+
f.write(f"nc: {len(classes)}\n\n")
48+
f.write("names:\n")
49+
for i, name in enumerate(classes):
50+
f.write(f" {i}: {name}\n")
51+
print("\n--- YAML CONTENT ---")
52+
with open(yaml_path, "r") as f:
53+
print(f.read())
5154

5255

5356
def main():
5457
parser = argparse.ArgumentParser()
5558
parser.add_argument("-i", "--images", required=True)
5659
parser.add_argument("-y", "--labels", required=True)
5760
parser.add_argument("-o", "--output", required=True)
61+
parser.add_argument("-c", "--classes", required=False, default="")
5862
parser.add_argument("-p", "--train_percent", type=int, default=70)
5963
args = parser.parse_args()
6064

@@ -68,8 +72,8 @@ def main():
6872
copy_pairs(train_pairs, args.images, args.labels, os.path.join(args.output, "train/images"), os.path.join(args.output, "train/labels"))
6973
copy_pairs(val_pairs, args.images, args.labels, os.path.join(args.output, "valid/images"), os.path.join(args.output, "valid/labels"))
7074
copy_pairs(test_pairs, args.images, args.labels, os.path.join(args.output, "test/images"), os.path.join(args.output, "test/labels"))
71-
72-
write_yolo_yaml(args.output)
75+
classes_list = [c.strip() for c in args.classes.split(",")]
76+
write_yolo_yaml(args.output, classes_list)
7377

7478

7579
if __name__ == "__main__":

tools/image_processing/yolo/yolo_prediction.xml

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<tool id="yolo_predict" name="Perform YOLO image labeling" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="24.2">
1+
<tool id="yolo_predict" name="Perform YOLO image labeling" version="@TOOL_VERSION@+galaxy5" profile="24.2">
22
<description>with ultralytics</description>
33
<macros>
44
<import>macros.xml</import>
@@ -16,8 +16,6 @@
1616
ln -s '$filename' './input_images/${filename.element_identifier}.${filename.ext}' &&
1717
#end for
1818
19-
cp '$class_name' './models/class_name.txt' &&
20-
2119
cp '$model' './models/model.pt' &&
2220
2321
python '$__tool_directory__/yolov8.py'
@@ -29,26 +27,25 @@
2927
--image_size='$image_size'
3028
--mode='$mode'
3129
--foldername='overlaid_images'
32-
--class_names_file='$class_name'
33-
--num_classes=`wc -l < ./models/class_name.txt`
3430
--confidence='$confidence'
3531
--iou='$iou'
3632
--max_det='$max_det'
3733
--headless
3834
]]>
3935
</command>
4036
<inputs>
41-
<param name="input_images" type="data" format="jpg,png" multiple="true" label="Input images"/>
42-
<param name="class_name" type="data" format="txt" label="YOLO class name file" />
43-
<param name="model" type="data" format="data" label="Model file" />
44-
<param name="mode" type="select" label="Prediction mode">
45-
<option value="segment">segment</option>
46-
<option value="detect">detect</option>
47-
</param>
48-
<param name="image_size" type="integer" value="1000" min="16" label="Image size" help="All input images will be re-sized to squares with sides of this length (in pixels). This value governs the trade-offs of speed (smaller values) vs accuracy (larger values)." />
49-
<param name="confidence" type="float" value="0.5" min="0.0" max="1.0" label="Confidence" help="Confidence value (0-1) for each detected bounding box." />
50-
<param name="iou" type="float" value="0.7" min="0.1" max="1.0" label="IoU" help="Intersection over Union threshold for non-maximum suppression." />
51-
<param name="max_det" type="integer" value="300" min="100" max="1000" label="Max. number of detections" help="Maximum number of detections allowed per image. Limits the total number of objects the model can detect in a single inference, preventing excessive outputs in dense scenes." />
37+
<param name="input_images" type="data" format="jpg,png,tiff,tif" multiple="true" label="Input images">
38+
<validator type="expression" message="PNG/JPG acceptés, TIFF uniquement si 3 canaux (RGB)">value is not None and (value.ext in ('png', 'jpg', 'jpeg') or (value.ext in ('tiff', 'tif') and getattr(value.metadata, 'channels', 0) == 3))</validator>
39+
</param>
40+
<param name="model" type="data" format="data" label="Model file" />
41+
<param name="mode" type="select" label="Prediction mode">
42+
<option value="segment">segment</option>
43+
<option value="detect">detect</option>
44+
</param>
45+
<param name="image_size" type="integer" value="1000" min="16" label="Image size" help="All input images will be re-sized to squares with sides of this length (in pixels). This value governs the trade-offs of speed (smaller values) vs accuracy (larger values)." />
46+
<param name="confidence" type="float" value="0.5" min="0.0" max="1.0" label="Confidence" help="Confidence value (0-1) for each detected bounding box." />
47+
<param name="iou" type="float" value="0.7" min="0.1" max="1.0" label="IoU" help="Intersection over Union threshold for non-maximum suppression." />
48+
<param name="max_det" type="integer" value="300" min="100" max="1000" label="Max. number of detections" help="Maximum number of detections allowed per image. Limits the total number of objects the model can detect in a single inference, preventing excessive outputs in dense scenes." />
5249
</inputs>
5350
<outputs>
5451
<collection name="txt_results" format="txt" type="list" label="YOLO bounding box and annotation (text)">
@@ -71,16 +68,13 @@
7168
<param name="iou" value="0.7" />
7269
<param name="max_det" value="100" />
7370
<param name="mode" value="segment" />
74-
<param name="class_name" value="class_name.txt" />
75-
7671
<output_collection name="txt_results" type="list" count="1">
7772
<element name="pred-test01.jpg">
7873
<assert_contents>
7974
<has_n_lines n="100"/>
8075
</assert_contents>
8176
</element>
8277
</output_collection>
83-
8478
<output_collection name="mask_results" type="list" count="1">
8579
<element name="pred-test01.jpg">
8680
<assert_contents>
@@ -99,14 +93,9 @@
9993
</assert_contents>
10094
</element>
10195
</output_collection>
102-
10396
</test>
104-
<!--new version's test-->
105-
<!-- SEGMENT MODE TEST -->
106-
10797
<test expect_num_outputs="3">
10898
<param name="input_images" value="bus.jpg" />
109-
<param name="class_name" value="yolo-test-classes.txt" />
11099
<param name="model" location="https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8n-seg.pt" />
111100
<param name="mode" value="segment" />
112101
<param name="image_size" value="640" />
@@ -123,12 +112,8 @@
123112
<element name="bus.jpg" file="bus_seg.jpg" compare="sim_size" />
124113
</output_collection>
125114
</test>
126-
127-
<!-- DETECT MODE TEST -->
128-
129115
<test expect_num_outputs="2">
130116
<param name="input_images" value="bus.jpg" />
131-
<param name="class_name" value="yolo-test-classes.txt" />
132117
<param name="model" location="https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8n-seg.pt" />
133118
<param name="mode" value="detect" />
134119
<param name="image_size" value="640" />

tools/image_processing/yolo/yolo_training.xml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
-i './input_images'
3333
-y './input_yolo'
3434
-o ./training
35+
-c '$class_names'
3536
-p '$num_train' &&
3637
3738
#if $model_choice.pretrained == 'personal'
@@ -43,7 +44,7 @@
4344
python '$__tool_directory__/yolov8.py'
4445
--train --yaml_path='./training/yolo.yml'
4546
--model_path='./models'
46-
--model_name='yolo_model'
47+
--model_name='yolo_model'
4748
--run_dir='./runs'
4849
--image_size='$training_params.image_size'
4950
--epochs='$training_params.epochs'
@@ -66,7 +67,10 @@
6667
]]>
6768
</command>
6869
<inputs>
69-
<param name="input_images" type="data" format="jpg" multiple="true" label="Input images"/>
70+
<param name="input_images" type="data" format="jpg,png,tiff" multiple="true" label="Input Images"
71+
help="Upload the images to use for training (JPG, PNG, or TIFF format). or TIFF files, only 3-channel RGB images are supported. Each image must have a corresponding YOLO annotation file with the same base filename." >
72+
<validator type="expression" message="PNG/JPG acceptés, TIFF uniquement si 3 canaux (RGB)">value is not None and (value.ext in ('png', 'jpg') or (value.ext in ('tiff') and getattr(value.metadata, 'channels', 0) == 3))</validator>
73+
</param>
7074
<param name="input_yolo" type="data" format="txt" multiple="true" label="Input YOLO txt files" help="The YOLO text files, each text file must correspond to one input image (same name, different extension)." />
7175
<conditional name="model_choice">
7276
<param name="pretrained" type="select" label="Choose pretrained YOLO model or your own">
@@ -82,6 +86,7 @@
8286
<when value="https://github.com/ultralytics/assets/releases/download/v8.3.0/yolo11n.pt"/>
8387
<when value="https://github.com/ultralytics/assets/releases/download/v8.3.0/yolov8n.pt"/>
8488
</conditional>
89+
<param name="class_names" type="text" optional="true" label="List class name comma separated"/>
8590
<section name="training_params" title="Training Parameters">
8691
<param name="num_train" type="integer" value="70" min="50" max="90" label="How do you want to split your images for training?" help="Proportion of training images wrt valid and test images (in percents)." />
8792
<param name="epochs" type="integer" value="100" min="10" max="1000" label="Number of epochs for taining." />
@@ -141,7 +146,7 @@
141146
<has_size min="10000"/>
142147
<has_image_channels channels="4"/>
143148
<has_image_height height="1200"/>
144-
<has_image_width height="3600"/>
149+
<has_image_width width="3600"/>
145150
</assert_contents>
146151
</output>
147152
</test>
@@ -181,7 +186,7 @@
181186
<has_size min="10000"/>
182187
<has_image_channels channels="4"/>
183188
<has_image_height height="1200"/>
184-
<has_image_width height="3600"/>
189+
<has_image_width width="3600"/>
185190
</assert_contents>
186191
</output>
187192
</test>
@@ -221,7 +226,7 @@
221226
<has_size min="10000"/>
222227
<has_image_channels channels="4"/>
223228
<has_image_height height="1200"/>
224-
<has_image_width height="3600"/>
229+
<has_image_width width="3600"/>
225230
</assert_contents>
226231
</output>
227232
</test>

tools/image_processing/yolo/yolov8.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
parser = argparse.ArgumentParser(
1919
description='train/predict dataset with YOLOv8',
2020
epilog="""USAGE EXAMPLE:\n\n~~~~Prediction~~~~\n\
21-
python yolov8.py --test_path=/g/group/user/data --model_path=/g/cba/models --model_name=yolov8n --save_dir=/g/group/user/results --iou=0.7 --confidence=0.5 --image_size=320 --run_dir=/g/group/user/runs --foldername=batch --headless --num_classes=1 max_det=1 --class_names_file=/g/group/user/class_names.txt\n\
21+
python yolov8.py --test_path=/g/group/user/data --model_path=/g/cba/models --model_name=yolov8n --save_dir=/g/group/user/results --iou=0.7 --confidence=0.5 --image_size=320 --run_dir=/g/group/user/runs --foldername=batch --headless --num_classes=1 max_det=1 \n\
2222
\n~~~~Training~~~~ \n\
23-
python yolov8.py --train --yaml_path=/g/group/user/example.yaml --model_path=/g/cba/models --model_name=yolov8n --run_dir=/g/group/user/runs/ --image_size=320 --epochs=150 --scale=0.3 --hsv_v=0.5 --model_format=pt --degrees=180 --class_names_file=/g/group/user/class_names.txt""", formatter_class=RawTextHelpFormatter)
23+
python yolov8.py --train --yaml_path=/g/group/user/example.yaml --model_path=/g/cba/models --model_name=yolov8n --run_dir=/g/group/user/runs/ --image_size=320 --epochs=150 --scale=0.3 --hsv_v=0.5 --model_format=pt --degrees=180 """, formatter_class=RawTextHelpFormatter)
2424
parser.add_argument("--dir_path",
2525
help=(
2626
"Path to the training data directory."
@@ -76,9 +76,6 @@
7676
parser.add_argument("--model_format",
7777
help="Format of the YOLO model i.e pt, yaml etc.",
7878
default='pt', type=str)
79-
parser.add_argument("--class_names_file",
80-
help="Path to the text file containing class names.",
81-
type=str)
8279
# For training the model and prediction
8380
parser.add_argument("--mode",
8481
help=(
@@ -299,7 +296,7 @@ def predict(model, source_datapath, **kwargs):
299296
iou_value = 0.5
300297

301298
if "num_classes" in kwargs:
302-
class_array = list(range(kwargs['num_classes']))
299+
class_array = list(model.names.keys())
303300
else:
304301
class_array = [0, 1]
305302

@@ -373,14 +370,7 @@ def save_yolo_bounding_boxes_to_txt(predictions, save_dir):
373370
validateModel(model)
374371
else:
375372
t = time.time()
376-
train_save_path = os.path.expanduser('~/runs/' + args.mode + '/')
377-
if os.path.isfile(os.path.join(train_save_path,
378-
"train", "weights", "best.pt")) and (args.model_name == 'sam'):
379-
model = YOLO(os.path.join(train_save_path,
380-
"train", "weights", "best.pt"))
381-
else:
382-
model = YOLO(os.path.join(args.model_path,
383-
args.model_name + ".pt"))
373+
model = YOLO(os.path.join(args.model_path, args.model_name + ".pt"))
384374
model.info(verbose=True)
385375
elapsed = time.time() - t
386376
print(colored(f"\nYOLO model loaded in : '{elapsed}' sec \n", 'white', 'on_yellow'))
@@ -487,12 +477,6 @@ def save_yolo_bounding_boxes_to_txt(predictions, save_dir):
487477
print(colored(f"TYX mask stack saved as : '{mask_save_as}'", 'magenta'))
488478
print(colored(f"Tracking results saved in : '{args.save_dir}' \n", 'green'))
489479
elif (args.mode == "segment"):
490-
# Read class names from the file
491-
with open(args.class_names_file, 'r') as f:
492-
class_names = [line.strip() for line in f.readlines()]
493-
# Create a mapping from class names to indices
494-
class_to_index = {class_name: i for i, class_name in enumerate(class_names)}
495-
496480
# Save polygon coordinates
497481
for result in predictions:
498482
# Create binary mask

0 commit comments

Comments
 (0)