-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix issue #8807 - Save Prediction Results to .csv #8967
base: main
Are you sure you want to change the base?
Conversation
- The following attributes will be saved in a .csv file - Image File Path - ID Class - Confidence - x1: x coordinate of top left point of bb - y1: y coordinate of top left point of bb - x2: x coordinate of bottom right point of bb - y2: y coordinate of bottom right point of bb - width: Width of bb - height: Height of bb
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8967 +/- ##
==========================================
+ Coverage 75.99% 76.13% +0.13%
==========================================
Files 121 121
Lines 15332 15373 +41
==========================================
+ Hits 11652 11704 +52
+ Misses 3680 3669 -11
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
IntroductionThis code snippet demonstrates how to perform object detection on a list of image files using the YOLO model from the Ultralytics library. UsageAssuming you have a list with image file paths, you can utilize the provided code snippet as follows: from ultralytics import YOLO
import os
# Specify the path to the dataset containing images to be predicted
dataset_path = "folder_path\with\images\to\be\predicted"
# Generate a list of absolute image paths within the dataset directory
images_path_list = []
for dirpath, _, filenames in os.walk(dataset_path):
for f in filenames:
images_path_list.append(os.path.abspath(os.path.join(dirpath, f)))
# Load the YOLO model (adjust the model path as needed)
model = YOLO('yolov8n.pt')
# Perform object detection on the provided images
results = model(images_path_list)
# Save detection results as CSV files
for idx, result in enumerate(results):
result.save_detect_csv(f"output/predictions_{idx}.csv") |
@stavros-p thanks for the PR! @Burhan-Q and myself have been thinking of introducing improved offical support for Pandas -> JSON, TXT, CSV etc. outputs, but this would need to incorporate multiple output formats and multiple tasks (i.e. detect, segment, pose, classify, obb) in order to be meaningful. |
@glenn-jocher thanks for the comment! Yes, initially I thought the same. For detection results this is quite straightforward. What do you think for the other (segment, pose, classify, obb, pose)? How and what you would like to save on JSON, TXT, CSV? I would be more than happy to contribute on that :) |
Hey @stavros-p! 😊 Great enthusiasm! For other tasks like segment, pose, classify, obb, and pose, the approach would slightly vary based on the output details each task provides. For example, segmentation might include saving mask details, pose could save keypoints, classify saves class probabilities, and so forth. A generic format could look like this for each task:
The key is to maintain a structured and consistent format that's easy to parse. If you'd like, I can share more specific code examples for each. Your contributions are highly appreciated! Let's make YOLOv8 even better together. 🚀 |
@stavros-p the doc that Glenn pointed me to before is here and covers the I/O tools for |
Hey @Burhan-Q . I am aware of this API :) Yes please free to add commits in this PR. I'd be more than happy to collab with you on that. |
@stavros-p excellent! I will push some changes later today (it'll be a good bit different looking) and we can discuss the what and whys of what changes. I'm of course open to input/feedback if there's anything you feel should be different, so please don't hesitate to share your thoughts. |
… to `save_csv()` method and now uses `to_pandas()`, valid with all tasks
@stavros-p please take a look at the changes I've added when you have the opportunity. This will be compatible with all task types and uses a We will also need to update the documentation to reflect these updates/changes once we've ironed out all of the aspects we want to keep. Additionally, I want to update |
…ult from additional testing.
ultralytics/engine/results.py
Outdated
"top5": r.probs.top5 if probs else None, | ||
"top5conf": r.probs.top5conf if probs else None, | ||
} | ||
for n in range(max(len(lbl_idx or []), 1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This portion of the code presents a potential ambiguity:
for n in range(max(len(lbl_idx or []), 1)) | |
if lbl_idx is None: | |
length = 1 | |
else: | |
length = max(len(lbl_idx), 1) | |
for n in range(length): | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. I think I will abstain from making the call as to which version to use and let @glenn-jocher make the final call for this portion of the code (once we wrap up everything else).
@stavros-p I appreciate your input so far. 🙌 Overall what are your thoughts on how this operates? Do you feel that we should move on to updating the docs and adding tests, or did you have anything else you wished to discuss, review, or recommend? |
Hey @Burhan-Q ! It's my pleasure. I made a commit few hours ago. I've tested the function for all tasks and for multiple cases and it seems to work as expected :) Let me know if you have something else to add there. If not, we could proceed on updating the docs |
@stavros-p I did see that, looks like a solid middle ground choice! 😆 Glad to hear it worked for you as well 🙌 I think we're good to proceed to docs and tests. Want to divide and conquer? I can do either tests or docs, but I have less experience with writing tests. If you have no preference I'd like to get more experience writing tests and then you can tackle the docs. Let me know if that works for you, I'm open to the inverse as well 👍 |
…t` to avoid passing `np.float_` objects
…ults tables for attributes and methods; verified with local `mkdocs` build
@stavros-p I went ahead and did both docs and tests. This was to make it ready to go as some of the changes may be used along with other features that are in the works. Please feel free to share any input you have. I definitely would like to expand the docs some, but for now I'm going with this MVP |
|
Preview
|
image | detections | name | class | conf | id | xyxy | xyxyn | xywh | xywhn | mask-xy | mask-xyn | kp-xy | kp-xyn | kp-conf | xywhr | xyxyxyxy | xyxyxyxyn | top1 | top1conf | top5 | top5conf |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
bus.jpg | 0 | bus | 5 | 0.8733859062 | [22.87796401977539, 231.27442932128906, 804.9771118164062, 756.8328247070312] | [0.028244400396943092, 0.21414299309253693, 0.9937989115715027, 0.700771152973175] | [413.92755126953125, 494.0536193847656, 782.09912109375, 525.5584106445312] | [0.5110216736793518, 0.4574570655822754, 0.9655544757843018, 0.48662814497947693] | |||||||||||||
bus.jpg | 1 | person | 0 | 0.8657410145 | [48.55202865600586, 398.5559387207031, 245.3509521484375, 902.71240234375] | [0.059940777719020844, 0.3690332770347595, 0.3029024004936218, 0.8358448147773743] | [146.9514923095703, 650.6341552734375, 196.79891967773438, 504.1564636230469] | [0.18142159283161163, 0.6024390459060669, 0.24296163022518158, 0.46681153774261475] | |||||||||||||
bus.jpg | 2 | person | 0 | 0.852802515 | [669.4681396484375, 392.1857604980469, 809.7197265625, 877.0387573242188] | [0.8265038728713989, 0.3631349503993988, 0.9996539950370789, 0.8120729327201843] | [739.5939331054688, 634.6122436523438, 140.2515869140625, 484.8529968261719] | [0.9130789041519165, 0.5876039266586304, 0.17315010726451874, 0.44893795251846313] | |||||||||||||
bus.jpg | 3 | person | 0 | 0.8252988458 | [221.5220184326172, 405.79974365234375, 344.97943115234375, 857.54052734375] | [0.2734839618206024, 0.37574049830436707, 0.42590051889419556, 0.7940189838409424] | [283.250732421875, 631.670166015625, 123.45741271972656, 451.74078369140625] | [0.3496922552585602, 0.5848797559738159, 0.15241655707359314, 0.4182785153388977] | |||||||||||||
bus.jpg | 4 | person | 0 | 0.2610270083 | [0.0, 550.5264892578125, 63.009544372558594, 873.4437866210938] | [0.0, 0.5097467303276062, 0.0777895599603653, 0.8087442517280579] | [31.504772186279297, 711.985107421875, 63.009544372558594, 322.91729736328125] | [0.03889477998018265, 0.659245491027832, 0.0777895599603653, 0.2989974915981293] | |||||||||||||
bus.jpg | 5 | stop sign | 11 | 0.2551255822 | [0.058402419090270996, 254.46063232421875, 32.561038970947266, 324.8736572265625] | [7.210174953797832e-05, 0.235611692070961, 0.04019881412386894, 0.30080893635749817] | [16.309720993041992, 289.6671447753906, 32.50263595581055, 70.41302490234375] | [0.020135458558797836, 0.2682103216648102, 0.04012671113014221, 0.06519724428653717] |
NOTE: DataFrame format would be similar, except the image filename would not be repeated in the first column and empty columns could be dropped (if desired) using the method .dropna(axis=1)
on the DataFrame
Hey @Burhan-Q , Sorry for my late response 🙏 I had to be off for some days. I saw the great work you did there both for tests and docs. Please let me know what do you think about the current status of the PR. |
@stavros-p not to worry. I think the PR is in pretty good shape, but I'm seeing other changes that might supersede the changes made here. I think for the time being, we leave this in place and see if it's accepted. Otherwise I'll keep an eye open for other opportunities to include this functionality. |
I have read the CLA Document and I hereby sign the CLA
🛠️ PR Summary
Made with ❤️ by Ultralytics Actions
🌟 Summary
Enhanced detection results storage by adding CSV export functionality.
📊 Key Changes
save_detect_csv(csv_file)
inresults.py
to save detection predictions into a CSV file.🎯 Purpose & Impact
🚀 This addition opens up new possibilities for users to work with and analyze their detection results, making the overall tool more versatile and user-friendly.