4.0 KiB
4.0 KiB
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
- Auto-Label: Click "🤖 Auto-Label" to detect knots with your model
- Adjust threshold: Lower = more detections, Higher = only confident ones
- Manual boxes: Enter coordinates (x1, y1, x2, y2) and click "➕ Add Box"
- Delete mistakes: Click "🗑️ Delete Last" to remove last box
- Navigate: Use "Previous" / "Next" buttons
- 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-weightsfor manual-only mode
Need more features?
- Check Gradio docs: https://www.gradio.app/docs/
- Add custom components easily
- Fork and modify the code freely!