影像標註
在 Potato 中配置影像標註,支援邊界框、多邊形、掩碼和關鍵點。用 instance_display 顯示影像,並匯出為 COCO 或 YOLO 格式。
Potato 支援影像標註,涵蓋分類、目標檢測、分割和關鍵點任務。
顯示影像
顯示影像和收集標註是兩項彼此獨立的設定。instance_display 決定標註者看到什麼,annotation_schemes 決定他們回答什麼。把兩者分開,任何內容類型就都可以和任何問題類型搭配:
instance_display:
fields:
- key: image_url # Field name in your data file
type: image
label: "Image to classify"
display_options:
max_width: 600
zoomable: trueimage_annotation 方案是用來在影像上繪製的,不是用來顯示影像的。分類任務只需要上面的顯示欄位,再加一個 radio 或 multiselect 方案。
顯示選項
| 選項 | 說明 |
|---|---|
max_width | 渲染的最大寬度,單位為畫素 |
max_height | 渲染的最大高度,單位為畫素 |
zoomable | 啟用點選放大 |
object_fit | 影像如何填充它的容器 |
alt_text | 供螢幕閱讀器使用的替代文本 |
Potato 不認識的選項名會被當成配置錯誤,而不是被靜默忽略,報錯資訊還會提示最接近的真實選項名。
資料格式
在資料檔案中引用影像:
{"id": "img_001", "image_url": "https://example.com/photo_001.jpg"}
{"id": "img_002", "image_url": "/static/images/photo_002.png"}data_files 是一個路徑列表,item_properties 把你的欄位名對映到 Potato 讀取的欄位名上:
data_files:
- "data/image_tasks.json"
item_properties:
id_key: id
text_key: image_url # The field holding the image URL影像分類
對整張影像進行分類:
annotation_schemes:
- annotation_type: radio
name: category
description: "What is shown in this image?"
labels:
- Cat
- Dog
- Bird
- Other
- annotation_type: multiselect
name: attributes
description: "Select all that apply"
labels:
- Indoor
- Outdoor
- Multiple animals
- Human present多標籤分類
annotation_schemes:
- annotation_type: multiselect
name: objects
description: "What objects are visible?"
labels:
- Person
- Car
- Building
- Tree
- Animal
- Furniture
- Food
- Electronic device影像品質評估
annotation_schemes:
- annotation_type: likert
name: quality
description: "Overall image quality"
size: 5
min_label: "Very poor"
max_label: "Excellent"
- annotation_type: multiselect
name: issues
description: "Select any quality issues"
labels:
- Blurry
- Overexposed
- Underexposed
- Noisy
- Low resolution
- Watermark visible在影像上繪製
image_annotation 方案必須同時提供 tools 和 labels。為每個標籤指定顏色和 key_value 值得多寫幾行,因為標註者用按鍵分配標籤比用滑鼠點選快得多:
annotation_schemes:
- annotation_type: image_annotation
name: object_detection
description: "Draw boxes around objects"
tools:
- bbox
- polygon
labels:
- name: person
color: "#FF6B6B"
key_value: "1"
- name: vehicle
color: "#4ECDC4"
key_value: "2"
- name: animal
color: "#45B7D1"
key_value: "3"
min_annotations: 1
zoom_enabled: true
pan_enabled: truecolor 必須是十六進位制(#rgb、#rrggbb 或 #rrggbbaa)。CSS 顏色名和 rgb() 不會被讀取:形狀看上去沒問題,但掩碼是逐畫素繪製的,會退回成紅色。
可用工具
| 工具 | 說明 |
|---|---|
bbox | 矩形邊界框 |
polygon | 多點閉合多邊形 |
polyline | 多點開放路徑,用於車道線、血管、裂縫、海岸線 |
ellipse | 橢圓和圓,用於細胞、細胞核、車輪、人臉 |
keypoint_set | 有序骨架,用於人體或動物姿態以及面部關鍵點 |
cuboid_2d | 投影到影像上的 3D 框,KITTI 風格 |
sam | 魔術棒:點一下物體,由模型完成分割 |
freeform | 自由手繪 |
landmark | 單點標記 |
brush | 用於畫素級掩碼的分割畫筆 |
eraser | 擦除掩碼區域 |
fill | 對封閉區域做漫水填充 |
多邊形是閉合的,圍出一塊麵積;折線是開放的,有長度但沒有內部區域。這個區別在匯出時有影響:折線會被寫成 area: 0,永遠不會被當作區域處理。
多邊形標註
用於非矩形區域:
annotation_schemes:
- annotation_type: image_annotation
name: regions
description: "Outline regions of interest"
tools:
- polygon
labels:
- name: Building
- name: Road
- name: Vegetation
- name: Water分割掩碼
做畫素級的工作時,啟用繪製類工具。掩碼以遊程編碼儲存,而不是逐畫素陣列,這正是整圖掩碼仍然很小的原因:
annotation_schemes:
- annotation_type: image_annotation
name: segmentation
description: "Paint regions using the brush tool"
tools:
- brush
- eraser
- fill
labels:
- name: road
color: "#45B7D1"
- name: sidewalk
color: "#96CEB4"
brush_size: 20
mask_opacity: 0.5
mask_mode: semanticmask_mode: semantic 會把同一類的所有筆畫合併成一個區域。同類的兩個物體必須分開時,改用 instance。
輸出格式
標註存成一個扁平的 JSON 陣列,所有形狀和掩碼都在同一個列表裡。座標相對影像歸一化到 0 到 1 的範圍,因此影像以不同尺寸提供時標註依然正確:
[
{
"type": "bbox",
"label": "person",
"color": "#FF6B6B",
"coordinates": {"x": 0.125, "y": 0.104, "width": 0.3125, "height": 0.625}
},
{
"type": "polygon",
"label": "vehicle",
"color": "#4ECDC4",
"coordinates": [
{"x": 0.02, "y": 0.04}, {"x": 0.20, "y": 0.04},
{"x": 0.20, "y": 0.21}, {"x": 0.02, "y": 0.21}
]
},
{
"type": "mask",
"label": "road",
"color": "#45B7D1",
"rle": {"counts": [12, 40, 8], "size": [480, 640]}
}
]幾何欄位的名字隨類型而變:
| 類型 | 幾何欄位 | 形狀 |
|---|---|---|
bbox | coordinates | {x, y, width, height},已歸一化 |
polygon | coordinates | {x, y} 的列表,已歸一化 |
landmark | coordinates | {x, y},已歸一化 |
freeform | coordinates | {path, left, top, scaleX, scaleY} |
mask | rle | {counts: [ints], size: [height, width]} |
rle.size 是 [height, width],順序就是如此。在 Python 裡與這些結構互相轉換時,請使用 potato.export.cv_utils 中的 normalize_annotation_object() 和 to_client_object(),不要直接讀取欄位。
形狀的來源
被採納的模型檢測結果和手繪的框一旦存下來就別無二致,所以每個形狀都記錄自己的來源。沒有它,用模型做預標註的項目就無法從自己的資料裡算出自己的採納率:
{
"type": "bbox",
"label": "person",
"coordinates": {"x": 0.125, "y": 0.104, "width": 0.3125, "height": 0.625},
"source": "ai",
"ai_model": "yolov8n",
"confidence": 0.82,
"edited": true
}| 欄位 | 含義 |
|---|---|
source | human(在瀏覽器中繪製)、ai(模型提出、標註者採納)、import(隨資料一起匯入) |
ai_model | 端點報告了模型名時,具體是哪個模型 |
confidence | 檢測器為這個形狀給出的分數 |
edited | 標註者後來移動、縮放或重新標註了一個本來不是自己畫的形狀 |
carried_over | 從上一張影像沿用過來,而不是在這張影像上畫的 |
edited 區分的是原樣採納一個框,和採納之後又做了修正。只有前者才算與模型一致。
稽核已有標註
要稽核已經存在的形狀,應該匯入它們,而不是把它們塞進某個資料欄位。potato import 會把一個 COCO 檔案變成可直接執行的項目,並給每個形狀打上 source: import:
potato import --input instances_val2017.json \
--image-dir /data/val2017 \
--image-url-prefix /files \
--output-dir my-project/ \
--schema-name object_detection
potato start my-project/config.yaml -p 8000標註者隨後就地修正匯入的形狀,匯出時人工與模型的劃分在這一個來回中得以保留。
影像比較
用 pairwise 方案比較兩張影像。items_key 指明存放這一對影像的資料欄位:
annotation_schemes:
- annotation_type: pairwise
name: preference
description: "Which image looks better?"
mode: binary
items_key: images
show_labels: true
labels:
- "Original"
- "Edited"
allow_tie: true
tie_label: "About the same"影像描述
annotation_schemes:
- annotation_type: text
name: caption
description: "Write a caption for this image"
rows: 4
placeholder: "Describe what you see..."描述品質稽核
把影像和生成的描述並排顯示,然後給描述評分:
instance_display:
fields:
- key: image_url
type: image
label: "Image"
- key: generated_caption
type: text
label: "Generated caption"
annotation_schemes:
- annotation_type: likert
name: accuracy
description: "How accurate is this caption?"
size: 5
min_label: "Very inaccurate"
max_label: "Very accurate"
- annotation_type: likert
name: fluency
description: "How natural is the language?"
size: 5
min_label: "Very awkward"
max_label: "Very natural"
- annotation_type: text
name: improved_caption
description: "Suggest a better caption (optional)"
rows: 4
label_requirement:
required: false內容稽核
annotation_schemes:
- annotation_type: radio
name: safe_for_work
description: "Is this image safe for work?"
labels:
- Safe
- Questionable
- Not Safe
- annotation_type: multiselect
name: violation_types
description: "Select all violations (if any)"
labels:
- Violence
- Adult content
- Hate symbols
- Graphic content
- Spam/advertisement交換格式
Potato 能讀取 COCO JSON,包括其中所有的分割編碼和 crowd 區域,並能寫出 COCO、YOLO、Pascal VOC 以及按標籤分開的掩碼 PNG:
python -m potato.export -c my-project/config.yaml -f coco -o ./export/YOLO 和 Pascal VOC 只承載邊界框,因此其他形狀會被簡化成它們的外接框。
完整示例:目標檢測稽核
annotation_task_name: "Object Detection Verification"
task_dir: "."
data_files:
- "data/detections.json"
item_properties:
id_key: id
text_key: image_url
instance_display:
fields:
- key: image_url
type: image
label: "Image"
display_options:
max_width: 1000
zoomable: true
annotation_schemes:
# Correct the boxes
- annotation_type: image_annotation
name: objects
description: "Verify and correct object boxes"
tools:
- bbox
labels:
- name: Person
key_value: "1"
- name: Vehicle
key_value: "2"
- name: Animal
key_value: "3"
- name: Object
key_value: "4"
zoom_enabled: true
pan_enabled: true
# Overall assessment
- annotation_type: radio
name: prediction_quality
description: "How accurate were the predictions?"
labels:
- All correct
- Minor corrections needed
- Major corrections needed
- Mostly incorrect
- annotation_type: number
name: missed_objects
description: "How many objects were missed?"
min: 0
max: 50
- annotation_type: text
name: notes
description: "Any issues or comments?"
rows: 4
label_requirement:
required: false
output_annotation_dir: "output/"
export_annotation_format: jsonl
user_config:
allow_all_users: true啟動伺服器:
potato start config.yaml -p 8000效能提示
- 標註前先縮放 - 過大的源影像會拖慢載入,對標註本身卻沒有幫助
- 照片用 JPEG - 檔案更小,載入更快
- 圖形用 PNG - 圖表和截圖的品質更好
- 限制渲染尺寸 - 設定
max_width,免得瀏覽器在每個實例上縮放一張巨圖 - 統一預處理 - 在整個資料集上統一尺寸和格式