Files
saw_mill_knot_detection/GUI_README.md

4.0 KiB
Raw Blame History

Custom Annotation GUI

A simple, fully customizable annotation tool built with Gradio (pure Python).

Features

Auto-labeling with your trained RF-DETR model Manual annotation by entering box coordinates Edit/delete annotations easily Navigation between images Export to COCO JSON format 100% Python - easy to modify and extend

Quick Start

1. Install dependencies

/home/dillon/_code/saw_mill_knot_detection/.venv/bin/python -m pip install gradio>=4.0.0

2. Run the GUI

With auto-labeling (requires trained model):

/home/dillon/_code/saw_mill_knot_detection/.venv/bin/python annotation_gui.py \
  --images-dir /path/to/images \
  --model-weights runs/knot_rfdetr_medium/checkpoint_best_total.pth

Manual annotation only:

/home/dillon/_code/saw_mill_knot_detection/.venv/bin/python annotation_gui.py \
  --images-dir /path/to/images

3. Open in browser

Opens automatically at http://localhost:7860

Usage

  1. Auto-Label: Click "🤖 Auto-Label" to detect knots with your model
  2. Adjust threshold: Lower = more detections, Higher = only confident ones
  3. Manual boxes: Enter coordinates (x1, y1, x2, y2) and click " Add Box"
  4. Delete mistakes: Click "🗑️ Delete Last" to remove last box
  5. Navigate: Use "Previous" / "Next" buttons
  6. Export: Click "💾 Export COCO" when done

Customization Examples

Add keyboard shortcuts

# In create_ui(), add:
image_display.keyboard_shortcuts = {
    "d": delete_btn.click,  # Press 'd' to delete
    "n": next_btn.click,    # Press 'n' for next
}

Add interactive drawing

# Replace manual coordinates with image annotator:
from gradio_image_annotation import image_annotator

annotator = image_annotator(
    label="Draw boxes",
    type="numpy"
)

Change box colors by confidence

# In draw_boxes_on_image():
color = "green" if conf > 0.8 else "yellow" if conf > 0.5 else "red"
draw.rectangle([x1, y1, x2, y2], outline=color, width=3)

Add multiple label classes

# Add a dropdown:
label_choice = gr.Dropdown(
    choices=["knot", "crack", "hole"],
    value="knot",
    label="Label Type"
)

# Update box dict:
box = {
    "bbox": [x1, y1, x2, y2],
    "label": label_choice_value,  # from the dropdown
    "confidence": 1.0
}

Save checkpoints automatically

# In _save_annotations(), add:
import shutil
backup_path = self.ann_file.with_suffix('.backup.json')
shutil.copy(self.ann_file, backup_path)

Add image filters/preprocessing

# Add before annotation:
def preprocess_image(img: Image.Image) -> Image.Image:
    from PIL import ImageEnhance
    enhancer = ImageEnhance.Contrast(img)
    return enhancer.enhance(1.5)  # Increase contrast

File Structure

annotation_gui.py
├── AnnotationApp         # Main logic (easy to extend)
│   ├── auto_label_current()   # Modify for different models
│   ├── add_box_manual()        # Customize annotation format
│   ├── export_to_coco()        # Change export format
│   └── draw_boxes_on_image()  # Customize visualization
└── create_ui()           # Gradio interface (add components)

Advantages vs Label Studio

Feature Custom GUI Label Studio
Modify code Easy (pure Python) Complex (React + Python)
Add features ~10-50 lines Hundreds of lines
Custom models Direct integration ⚠️ Need ONNX export
Learning curve Simple Gradio ⚠️ Larger codebase
Setup pip install ⚠️ Docker/complex

Troubleshooting

Port already in use:

python annotation_gui.py --images-dir /path --port 7861

Model not loading:

  • Check the weights path exists
  • Verify it's a valid checkpoint file
  • Try without --model-weights for manual-only mode

Need more features?