ऑब्जेक्ट डिटेक्शन के लिए bounding box बनाना
Potato में ऑब्जेक्ट डिटेक्शन टास्क बनाइए, तीन लेबल वाले शुरुआती कॉन्फ़िग से ड्राइविंग फ़ुटेज के प्रोडक्शन कॉन्फ़िग तक, और फिर COCO या YOLO में निर्यात कीजिए।
यह ट्यूटोरियल Potato में ऑब्जेक्ट डिटेक्शन का एनोटेशन टास्क बनाता है, तीन लेबल वाले कॉन्फ़िग से शुरू होकर उस COCO या YOLO निर्यात तक जिस पर डिटेक्टर प्रशिक्षित होता है। इमेज टूल और उनके विकल्पों की पूरी सूची के लिए इमेज एनोटेशन दस्तावेज़ देखें।
डेटा फ़ाइल
डेटा फ़ाइल की हर पंक्ति एक इमेज है। Potato को एक पहचानकर्ता चाहिए और एक फ़ील्ड जिसमें इमेज का URL या पाथ हो, और item_properties बताता है कि कौन-सा फ़ील्ड कौन-सा है:
{"id": "img_001", "image_url": "https://example.com/street_001.jpg"}
{"id": "img_002", "image_url": "/static/images/street_002.jpg"}सापेक्ष पाथ media_directory के हिसाब से हल होता है, इसलिए लोकल इमेज के लिए कोई फ़ाइल सर्वर चलाने की ज़रूरत नहीं होती।
सबसे छोटा कॉन्फ़िगरेशन
ड्रॉइंग सतह image_annotation स्कीम के ज़िम्मे है। इसे एक नाम चाहिए, एक विवरण जिसे एनोटेटर निर्देश की तरह पढ़ते हैं, चालू किए जाने वाले टूल, और लेबल का सेट:
annotation_task_name: "Object Detection Annotation"
task_dir: "."
output_annotation_dir: "annotation_output/"
data_files:
- "data/images.json"
item_properties:
id_key: id
text_key: image_url
annotation_schemes:
- annotation_type: image_annotation
name: objects
description: "Draw a box around every car, person, and bicycle"
tools:
- bbox
labels:
- name: car
color: "#FF6B6B"
- name: person
color: "#4ECDC4"
- name: bicycle
color: "#45B7D1"तीन लेबल से शुरुआत सोच-समझकर की गई है। आप जो भी लेबल जोड़ते हैं, वह एक फ़ैसला है जो एनोटेटर को हर ऑब्जेक्ट पर लेना पड़ता है, और एक सीमांत मामला है जिसे सुलझाने का तरीका उसे बताना पड़ता है। इसलिए उन्हीं श्रेणियों से शुरू कीजिए जिनकी मॉडल को सचमुच ज़रूरत है, और बाकी तब जोड़िए जब दिशानिर्देश टिकने लगें।
सर्वर शुरू कीजिए और टास्क खोलिए:
potato start config.yaml -p 8000एनोटेटर क्या करता है
एनोटेटर एक लेबल चुनता है, फिर हर ऑब्जेक्ट के चारों ओर एक आयत खींचता है और कोने तब तक खिसकाता है जब तक बॉक्स कसकर न बैठ जाए:
bounding box टूल से एनोटेटर इमेज पर आयताकार हिस्से बनाकर उन्हें लेबल कर सकते हैं
ज़ूम और पैन डिफ़ॉल्ट रूप से चालू रहते हैं, जो छोटे या दूर के ऑब्जेक्ट के लिए मायने रखता है। जब इमेज एक जैसी हों और अतिरिक्त नियंत्रण सिर्फ़ रास्ते में आते हों, तो दोनों को zoom_enabled: false और pan_enabled: false से बंद किया जा सकता है।
लेबल शॉर्टकट
डिफ़ॉल्ट v7 कीबाइंडिंग प्रोफ़ाइल में टूल अक्षर वाली कुंजियाँ लेते हैं: r बॉक्स टूल चुनता है, p पॉलीगॉन और b ब्रश। लेबल शॉर्टकट हर लेबल पर key_value से तय होते हैं, और अंक सुरक्षित विकल्प हैं, क्योंकि जिस लेबल का key_value किसी टूल की कुंजी से टकराता है, वह दोनों क्रियाएँ एक साथ चला देता है:
annotation_schemes:
- annotation_type: image_annotation
name: objects
description: "Annotate all visible objects"
tools:
- bbox
labels:
- name: person
color: "#FF6B6B"
key_value: "1"
- name: car
color: "#4ECDC4"
key_value: "2"
- name: motorcycle
color: "#45B7D1"
key_value: "3"
- name: bicycle
color: "#96CEB4"
key_value: "4"
- name: traffic_light
color: "#FFEAA7"
key_value: "5"
- name: stop_sign
color: "#DDA0DD"
key_value: "6"रंग जो मिलें उन्हें मान लेने के बजाय सोच-समझकर चुनना ठीक रहता है। भीड़भाड़ वाले ट्रैफ़िक दृश्यों में एनोटेटर यह खोज रहा होता है कि उससे क्या छूट गया, और पास-पास की श्रेणियों पर मिलते-जुलते दो रंग इस खोज को धीमा कर देते हैं। अगर आपके एनोटेटर Potato की 2.8 से पहले वाली कुंजियाँ सीख चुके हैं और आप उन्हें दोबारा प्रशिक्षित नहीं करना चाहते, तो keybinding_profile: legacy सेट कीजिए।
ऑब्जेक्ट के एट्रिब्यूट जोड़ना
Potato में हर बॉक्स के लिए कोई एट्रिब्यूट ब्लॉक नहीं है। image_annotation के लेबल से name, color और key_value पढ़े जाते हैं, और लेबल डिक्शनरी में बाकी सब कुछ छोड़ दिया जाता है। इसलिए नेस्ट की गई attributes: सूची कुछ नहीं करती और बॉक्स बनाने के बाद कोई सवाल सामने नहीं आता।
वही जानकारी दर्ज करने के दो तरीके हैं। पहला, अंतर को लेबल सेट में ही शामिल कर दीजिए, ताकि एट्रिब्यूट उसी का हिस्सा बन जाए जो एनोटेटर चुनता है:
annotation_schemes:
- annotation_type: image_annotation
name: objects
description: "Draw a box around each object"
tools:
- bbox
labels:
- name: person
color: "#FF6B6B"
- name: person_occluded
color: "#C44536"दूसरा, एक अलग स्कीम से पूरी इमेज के बारे में पूछिए। यह किसी एक बॉक्स पर नहीं बल्कि आइटम पर लागू होता है, और यही समझौता है: आपको पता चलता है कि इमेज में कुछ ढका हुआ था, पर यह नहीं कि कौन-सा बॉक्स था:
- annotation_type: multiselect
name: image_conditions
description: "Conditions affecting this image"
labels:
- Heavy occlusion
- Truncated objects
- Low lightVIA से इंपोर्ट ही वह अकेली जगह है जहाँ एट्रिब्यूट बचे रहते हैं: via_importer हर क्षेत्र के region_attributes पढ़कर उन्हें लेबल में मिला देता है। यह इंपोर्ट के समय की अवधारणा है, कॉन्फ़िगरेशन की नहीं।
कम से कम एक बॉक्स अनिवार्य करना
बिना बॉक्स वाली इमेज अस्पष्ट होती है, क्योंकि इसका मतलब यह भी हो सकता है कि एनोटेटर को कुछ नहीं मिला और यह भी कि उसने आइटम छोड़ दिया। min_annotations न्यूनतम सीमा से कम आकृतियों वाला सबमिशन अस्वीकार करके यह अंतर साफ़ करवाता है, इसलिए सचमुच खाली इमेज के लिए एक स्पष्ट नकारात्मक लेबल चाहिए:
annotation_schemes:
- annotation_type: image_annotation
name: objects
description: "Draw a box around every traffic participant"
tools:
- bbox
labels: [...]
min_annotations: 1इमेज कितनी बड़ी दिखे, यह तय करना
ड्रॉइंग सतह रेंडर हुई इमेज के साथ चलती है, इसलिए छोटी दिखने वाली इमेज एनोटेटर को छोटा कैनवस देती है। आकार instance_display तय करता है, और बारीक काम के लिए ज़ूम उपलब्ध रहता है:
instance_display:
fields:
- key: image_url
type: image
label: "Frame"
display_options:
max_width: 1200
max_height: 800
zoomable: trueएक प्रोडक्शन कॉन्फ़िगरेशन
नीचे का ड्राइविंग कॉन्फ़िग वे पाँच श्रेणियाँ रखता है जिनकी एक डिटेक्शन डेटासेट को ज़रूरत होती है। लेबल अंक वाले शॉर्टकट रखते हैं ताकि एनोटेटर का बायाँ हाथ अंकों वाली पंक्ति पर ही रहे, और min_annotations: 1 यहाँ ठीक बैठता है क्योंकि इस कॉर्पस के हर फ़्रेम में कम से कम एक ट्रैफ़िक भागीदार मौजूद है:
annotation_task_name: "Autonomous Driving - Object Detection"
task_dir: "."
output_annotation_dir: "annotation_output/"
data_files:
- "data/driving_frames.json"
item_properties:
id_key: id
text_key: frame_path
annotation_schemes:
- annotation_type: image_annotation
name: objects
description: "Annotate all traffic participants and objects"
tools:
- bbox
min_annotations: 1
labels:
- name: vehicle
color: "#FF6B6B"
key_value: "1"
- name: pedestrian
color: "#4ECDC4"
key_value: "2"
- name: cyclist
color: "#45B7D1"
key_value: "3"
- name: traffic_sign
color: "#FFEAA7"
key_value: "4"
- name: traffic_light
color: "#DDA0DD"
key_value: "5"पाँच श्रेणियाँ पहले से ही उस सीमा पर हैं जिसे अंक वाले शॉर्टकट आराम से संभाल पाते हैं। दस से आगे एनोटेटर फ़्रेम पढ़ने के बजाय कुंजियाँ ढूँढ़ने लगता है, और उसी बिंदु पर एक और लेबल जोड़ने से बेहतर है टास्क को दो हिस्सों में बाँट देना।
एनोटेशन कैसे दिखते हैं
Potato एक इमेज की सारी आकृतियाँ एक सपाट JSON array में रखता है, चाहे उन्हें किसी भी टूल से बनाया गया हो। निर्देशांक इमेज के सापेक्ष 0 से 1 की सीमा में सामान्यीकृत होते हैं, इसलिए बाद में इमेज किसी दूसरे आकार में दिखाई जाए तब भी एनोटेशन सही रहते हैं:
[
{
"type": "bbox",
"label": "vehicle",
"color": "#FF6B6B",
"coordinates": {"x": 0.234, "y": 0.352, "width": 0.120, "height": 0.130}
},
{
"type": "bbox",
"label": "pedestrian",
"color": "#4ECDC4",
"coordinates": {"x": 0.427, "y": 0.370, "width": 0.026, "height": 0.139}
}
]bbox अपनी ज्यामिति coordinates के नीचे {x, y, width, height} के रूप में रखता है। पॉलीगॉन उसी कुंजी के नीचे बिंदुओं की सूची रखते हैं, और मास्क इसके बजाय rle के नीचे run-length encoding रखते हैं।
प्रशिक्षण के लिए निर्यात
डिटेक्टर प्रशिक्षण का कोड COCO या YOLO पढ़ता है, और Potato दोनों लिखता है:
python -m potato.export --config config.yaml --format coco --output ./export/
python -m potato.export --config config.yaml --format yolo --output ./export/दोनों निर्यात सिर्फ़ सिंटैक्स में अलग नहीं हैं। COCO एक ही annotations.json लिखता है जिसमें बॉक्स पिक्सेल में [x, y, width, height] के रूप में होते हैं, और यह इमेज कॉपी नहीं करता, इसलिए file_name के मान वहीं इशारा करते हैं जहाँ इमेज पहले से रखी हैं। YOLO हर इमेज के लिए एक टेक्स्ट फ़ाइल लिखता है जिसमें सामान्यीकृत केंद्र निर्देशांक होते हैं, इमेज और लेबल को train/ और val/ डायरेक्टरी में बाँटता है, और data.yaml तथा classes.txt जोड़ता है ताकि प्रशिक्षण रन को श्रेणियों की सूची अलग से बताए बिना मिल जाए।
बॉक्स को एक जैसा बनाए रखना
बॉक्स ऑब्जेक्ट से सटाकर बनाइए, क्योंकि बॉक्स के अंदर पृष्ठभूमि का हर पिक्सेल वह पिक्सेल है जिसे मॉडल अग्रभूमि कहना सीखता है। मुश्किल मामलों (occlusion, फ़्रेम के किनारे पर कटे ऑब्जेक्ट, प्रतिबिंब) से कैसे निपटना है यह लिखकर रखिए, और पहले हफ़्ते में उदाहरणों का एक बैच साथ मिलकर देखिए, जब दिशानिर्देश बदलना अभी सस्ता है। अध्ययन चलते समय हर एनोटेटर के बॉक्स की संख्या और आकार के बँटवारे पर नज़र रखिए, क्योंकि अचानक आया बदलाव आमतौर पर यह बताता है कि किसी ने कोई नियम अलग तरह से समझना शुरू कर दिया है, न कि यह कि इमेज बदल गईं।
अगले क़दम
- जब बॉक्स टास्क के लिए बहुत मोटे पड़ें, तो polygon एनोटेशन जोड़िए
- pose estimation के लिए keypoint सेट इस्तेमाल कीजिए
- अध्ययन कुछ गिने-चुने एनोटेटर से आगे बढ़े, उससे पहले गुणवत्ता नियंत्रण सेट कीजिए
बाकी इमेज विकल्पों के लिए इमेज एनोटेशन देखें।