Skip to content

影像標註

在 Potato 中配置影像標註,支援邊界框、多邊形、掩碼和關鍵點。用 instance_display 顯示影像,並匯出為 COCO 或 YOLO 格式。

Potato 支援影像標註,涵蓋分類、目標檢測、分割和關鍵點任務。

顯示影像

顯示影像和收集標註是兩項彼此獨立的設定。instance_display 決定標註者看到什麼,annotation_schemes 決定他們回答什麼。把兩者分開,任何內容類型就都可以和任何問題類型搭配:

yaml
instance_display:
  fields:
    - key: image_url          # Field name in your data file
      type: image
      label: "Image to classify"
      display_options:
        max_width: 600
        zoomable: true

image_annotation 方案是用來在影像上繪製的,不是用來顯示影像的。分類任務只需要上面的顯示欄位,再加一個 radio 或 multiselect 方案。

顯示選項

選項說明
max_width渲染的最大寬度,單位為畫素
max_height渲染的最大高度,單位為畫素
zoomable啟用點選放大
object_fit影像如何填充它的容器
alt_text供螢幕閱讀器使用的替代文本

Potato 不認識的選項名會被當成配置錯誤,而不是被靜默忽略,報錯資訊還會提示最接近的真實選項名。

資料格式

在資料檔案中引用影像:

json
{"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 讀取的欄位名上:

yaml
data_files:
  - "data/image_tasks.json"
 
item_properties:
  id_key: id
  text_key: image_url   # The field holding the image URL

影像分類

對整張影像進行分類:

yaml
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

多標籤分類

yaml
annotation_schemes:
  - annotation_type: multiselect
    name: objects
    description: "What objects are visible?"
    labels:
      - Person
      - Car
      - Building
      - Tree
      - Animal
      - Furniture
      - Food
      - Electronic device

影像品質評估

yaml
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 值得多寫幾行,因為標註者用按鍵分配標籤比用滑鼠點選快得多:

yaml
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: true

color 必須是十六進位制(#rgb、#rrggbb 或 #rrggbbaa)。CSS 顏色名和 rgb() 不會被讀取:形狀看上去沒問題,但掩碼是逐畫素繪製的,會退回成紅色。

可用工具

工具說明
bbox矩形邊界框
polygon多點閉合多邊形
polyline多點開放路徑,用於車道線、血管、裂縫、海岸線
ellipse橢圓和圓,用於細胞、細胞核、車輪、人臉
keypoint_set有序骨架,用於人體或動物姿態以及面部關鍵點
cuboid_2d投影到影像上的 3D 框,KITTI 風格
sam魔術棒:點一下物體,由模型完成分割
freeform自由手繪
landmark單點標記
brush用於畫素級掩碼的分割畫筆
eraser擦除掩碼區域
fill對封閉區域做漫水填充

多邊形是閉合的,圍出一塊麵積;折線是開放的,有長度但沒有內部區域。這個區別在匯出時有影響:折線會被寫成 area: 0,永遠不會被當作區域處理。

多邊形標註

用於非矩形區域:

yaml
annotation_schemes:
  - annotation_type: image_annotation
    name: regions
    description: "Outline regions of interest"
    tools:
      - polygon
    labels:
      - name: Building
      - name: Road
      - name: Vegetation
      - name: Water

分割掩碼

做畫素級的工作時,啟用繪製類工具。掩碼以遊程編碼儲存,而不是逐畫素陣列,這正是整圖掩碼仍然很小的原因:

yaml
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: semantic

mask_mode: semantic 會把同一類的所有筆畫合併成一個區域。同類的兩個物體必須分開時,改用 instance。

輸出格式

標註存成一個扁平的 JSON 陣列,所有形狀和掩碼都在同一個列表裡。座標相對影像歸一化到 0 到 1 的範圍,因此影像以不同尺寸提供時標註依然正確:

json
[
  {
    "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]}
  }
]

幾何欄位的名字隨類型而變:

類型幾何欄位形狀
bboxcoordinates{x, y, width, height},已歸一化
polygoncoordinates{x, y} 的列表,已歸一化
landmarkcoordinates{x, y},已歸一化
freeformcoordinates{path, left, top, scaleX, scaleY}
maskrle{counts: [ints], size: [height, width]}

rle.size 是 [height, width],順序就是如此。在 Python 裡與這些結構互相轉換時,請使用 potato.export.cv_utils 中的 normalize_annotation_object() 和 to_client_object(),不要直接讀取欄位。

形狀的來源

被採納的模型檢測結果和手繪的框一旦存下來就別無二致,所以每個形狀都記錄自己的來源。沒有它,用模型做預標註的項目就無法從自己的資料裡算出自己的採納率:

json
{
  "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
}
欄位含義
sourcehuman(在瀏覽器中繪製)、ai(模型提出、標註者採納)、import(隨資料一起匯入)
ai_model端點報告了模型名時,具體是哪個模型
confidence檢測器為這個形狀給出的分數
edited標註者後來移動、縮放或重新標註了一個本來不是自己畫的形狀
carried_over從上一張影像沿用過來,而不是在這張影像上畫的

edited 區分的是原樣採納一個框,和採納之後又做了修正。只有前者才算與模型一致。

稽核已有標註

要稽核已經存在的形狀,應該匯入它們,而不是把它們塞進某個資料欄位。potato import 會把一個 COCO 檔案變成可直接執行的項目,並給每個形狀打上 source: import:

bash
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 指明存放這一對影像的資料欄位:

yaml
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"

影像描述

yaml
annotation_schemes:
  - annotation_type: text
    name: caption
    description: "Write a caption for this image"
    rows: 4
    placeholder: "Describe what you see..."

描述品質稽核

把影像和生成的描述並排顯示,然後給描述評分:

yaml
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

內容稽核

yaml
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:

bash
python -m potato.export -c my-project/config.yaml -f coco -o ./export/

YOLO 和 Pascal VOC 只承載邊界框,因此其他形狀會被簡化成它們的外接框。

完整示例:目標檢測稽核

yaml
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

啟動伺服器:

bash
potato start config.yaml -p 8000

效能提示

  1. 標註前先縮放 - 過大的源影像會拖慢載入,對標註本身卻沒有幫助
  2. 照片用 JPEG - 檔案更小,載入更快
  3. 圖形用 PNG - 圖表和截圖的品質更好
  4. 限制渲染尺寸 - 設定 max_width,免得瀏覽器在每個實例上縮放一張巨圖
  5. 統一預處理 - 在整個資料集上統一尺寸和格式