Supervision: Toolkit Computer Vision dari Roboflow

# Supervision: Toolkit Computer Vision dari Roboflow Dalam proyek computer vision, setelah model mendeteksi objek, Anda masih perlu melakukan banyak hal: **menggambar bounding box, memfilter deteksi,...

By Ruby Abdullah · · tutorial
SupervisionComputer VisionObject DetectionRoboflowPython

Supervision: Toolkit Computer Vision dari Roboflow

Dalam proyek computer vision, setelah model mendeteksi objek, Anda masih perlu melakukan banyak hal: menggambar bounding box, memfilter deteksi, menghitung objek, dan melacak pergerakan. Semua ini membutuhkan kode yang cukup banyak dan repetitif jika ditulis dari nol.

Supervision dari Roboflow hadir sebagai toolkit Python yang menyederhanakan semua pekerjaan pasca-deteksi ini. Dengan API yang konsisten, Supervision bekerja dengan berbagai model deteksi seperti YOLO, Detectron2, dan SAM, memungkinkan Anda fokus pada logika aplikasi bukan boilerplate code.

Apa Itu Supervision?

Supervision adalah library Python open-source dari Roboflow untuk memudahkan pekerjaan computer vision. Fitur utamanya meliputi:

  • Detections Object: Representasi universal untuk hasil deteksi dari berbagai model
  • Annotators: Berbagai tipe annotator visual (bounding box, mask, label, trace, halo)
  • Filtering: Filter deteksi berdasarkan confidence, kelas, zona, dan kriteria lainnya
  • Polygon Zones: Definisi zona poligon untuk counting dan analisis area
  • Line Counters: Penghitung objek yang melewati garis virtual
  • Object Tracking: Integrasi ByteTrack untuk pelacakan objek lintas frame
  • Video Processing: Utilitas untuk memproses video frame-by-frame
  • FPS Monitor: Monitoring performa real-time

Instalasi

Instalasi Dasar

pip install supervision

Instalasi dengan Dependensi Model

# Dengan YOLO (Ultralytics)

pip install supervision ultralytics

Dengan Detectron2

pip install supervision detectron2

Dengan SAM (Segment Anything)

pip install supervision segment-anything

Verifikasi Instalasi

import supervision as sv

print(f"Supervision version: {sv.version}")

Detections Object

sv.Detections adalah objek inti di Supervision yang merepresentasikan hasil deteksi secara universal.

Membuat Detections dari Berbagai Model

import supervision as sv

import numpy as np

Dari Ultralytics YOLO

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

results = model("image.jpg")

detections = sv.Detections.fromultralytics(results[0])

print(f"Jumlah deteksi: {len(detections)}")

print(f"Bounding boxes: {detections.xyxy}")

print(f"Confidence: {detections.confidence}")

print(f"Class IDs: {detections.classid}")

Dari Detectron2

from detectron2.engine import DefaultPredictor

from detectron2.config import getcfg

cfg = getcfg()

cfg.mergefromfile("config.yaml")

predictor = DefaultPredictor(cfg)

outputs = predictor(image)

detections = sv.Detections.fromdetectron2(outputs)

Dari SAM (Segment Anything)

from segmentanything import sammodelregistry, SamAutomaticMaskGenerator

sam = sammodelregistryvith.pth"">"vith"

maskgenerator = SamAutomaticMaskGenerator(sam)

masks = maskgenerator.generate(image)

detections = sv.Detections.fromsam(masks)

Membuat Detections Manual

# Buat detections secara manual

detections = sv.Detections(

xyxy=np.array([

[100, 200, 300, 400],

[150, 250, 350, 450]

]),

confidence=np.array([0.95, 0.87]),

classid=np.array([0, 1])

)

Annotators: Visualisasi Deteksi

Supervision menyediakan berbagai annotator untuk memvisualisasikan hasil deteksi.

Bounding Box Annotator

import supervision as sv

import cv2

image = cv2.imread("image.jpg")

Annotator bounding box

bboxannotator = sv.BoxAnnotator(

thickness=2,

color=sv.ColorPalette.fromhex(["#FF0000", "#00FF00", "#0000FF"])

)

annotatedimage = bboxannotator.annotate(

scene=image.copy(),

detections=detections

)

cv2.imwrite("annotatedbbox.jpg", annotatedimage)

Label Annotator

# Label annotator untuk menampilkan teks

labelannotator = sv.LabelAnnotator(

textscale=0.5,

textthickness=1,

textpadding=5

)

Buat label dengan nama kelas dan confidence

labels = [

f"{classnames[classid]} {confidence:.2f}"

for classid, confidence

in zip(detections.classid, detections.confidence)

]

annotatedimage = labelannotator.annotate(

scene=annotatedimage,

detections=detections,

labels=labels

)

Mask Annotator

# Untuk model yang menghasilkan segmentation mask

maskannotator = sv.MaskAnnotator(

opacity=0.4

)

annotatedimage = maskannotator.annotate(

scene=image.copy(),

detections=detections

)

Trace Annotator (untuk Tracking)

# Trace annotator menampilkan jejak pergerakan objek

traceannotator = sv.TraceAnnotator(

thickness=2,

tracelength=50 # Panjang jejak dalam frame

)

annotatedimage = traceannotator.annotate(

scene=image.copy(),

detections=detections

)

Halo Annotator

# Halo annotator memberikan efek halo di sekitar objek

haloannotator = sv.HaloAnnotator(

opacity=0.5,

kernelsize=40

)

annotatedimage = haloannotator.annotate(

scene=image.copy(),

detections=detections

)

Menggabungkan Beberapa Annotator

# Gabungkan beberapa annotator

bboxannotator = sv.BoxAnnotator()

labelannotator = sv.LabelAnnotator()

maskannotator = sv.MaskAnnotator(opacity=0.3)

Terapkan berurutan

annotated = image.copy()

annotated = maskannotator.annotate(scene=annotated, detections=detections)

annotated = bboxannotator.annotate(scene=annotated, detections=detections)

annotated = labelannotator.annotate(

scene=annotated,

detections=detections,

labels=labels

)

cv2.imwrite("fullyannotated.jpg", annotated)

Filtering Detections

Filter Berdasarkan Confidence

# Filter deteksi dengan confidence > 0.5

highconfidence = detections[detections.confidence > 0.5]

print(f"Deteksi high confidence: {len(highconfidence)}")

Filter dengan range confidence

medium = detections[

(detections.confidence > 0.3) & (detections.confidence < 0.7)

]

Filter Berdasarkan Kelas

# Filter hanya kelas tertentu (misalnya: person = 0, car = 2)

persons = detections[detections.classid == 0]

cars = detections[detections.classid == 2]

Filter beberapa kelas sekaligus

vehicles = detections[np.isin(detections.classid, [2, 3, 5, 7])]

Filter Berdasarkan Area

# Filter berdasarkan luas bounding box

areas = detections.boxarea

largeobjects = detections[areas > 10000]

smallobjects = detections[areas < 1000]

Filter Berdasarkan Zona

# Definisikan zona poligon

zonepolygon = np.array([

[100, 100],

[500, 100],

[500, 400],

[100, 400]

])

zone = sv.PolygonZone(polygon=zonepolygon)

Filter deteksi yang berada dalam zona

inzone = detections[zone.trigger(detections=detections)]

print(f"Objek dalam zona: {len(inzone)}")

Polygon Zones

Polygon Zones memungkinkan Anda mendefinisikan area kustom untuk monitoring dan counting.

import supervision as sv

import numpy as np

import cv2

Definisikan zona sebagai poligon

parkingzone = np.array([

[200, 300], [600, 300], [650, 500], [150, 500]

])

Buat polygon zone

zone = sv.PolygonZone(polygon=parkingzone)

zoneannotator = sv.PolygonZoneAnnotator(

zone=zone,

color=sv.Color.GREEN,

thickness=2,

textthickness=2,

textscale=1

)

Proses frame

isinzone = zone.trigger(detections=detections)

countinzone = np.sum(isinzone)

Annotate

annotated = zoneannotator.annotate(scene=image.copy())

print(f"Objek di parkiran: {countinzone}")

Multiple Zones

# Definisikan beberapa zona

zonespolygons = [

np.array([[100, 100], [400, 100], [400, 300], [100, 300]]), # Zona A

np.array([[500, 100], [800, 100], [800, 300], [500, 300]]), # Zona B

np.array([[100, 400], [800, 400], [800, 600], [100, 600]]), # Zona C

]

colors = [sv.Color.RED, sv.Color.GREEN, sv.Color.BLUE]

zones = []

zoneannotators = []

for polygon, color in zip(zonespolygons, colors):

zone = sv.PolygonZone(polygon=polygon)

zones.append(zone)

zoneannotators.append(

sv.PolygonZoneAnnotator(zone=zone, color=color)

)

Proses setiap zona

for i, zone in enumerate(zones):

zone.trigger(detections=detections)

annotated = zoneannotators[i].annotate(scene=annotated)

Line Counters

Line counters menghitung objek yang melewati garis virtual.

import supervision as sv

import numpy as np

Definisikan garis virtual

linestart = sv.Point(x=0, y=400)

lineend = sv.Point(x=800, y=400)

linezone = sv.LineZone(

start=linestart,

end=lineend

)

linezoneannotator = sv.LineZoneAnnotator(

thickness=2,

textthickness=2,

textscale=1

)

Proses frame (dalam loop video)

linezone.trigger(detections=detections)

Dapatkan hitungan

print(f"Masuk: {linezone.incount}")

print(f"Keluar: {linezone.outcount}")

Annotate

annotated = linezoneannotator.annotate(

frame=image.copy(),

linecounter=linezone

)

ByteTrack Object Tracking

ByteTrack memungkinkan pelacakan objek konsisten antar frame video.

import supervision as sv

Inisialisasi tracker

tracker = sv.ByteTrack(

trackactivationthreshold=0.25,

losttrackbuffer=30,

minimummatchingthreshold=0.8,

framerate=30

)

Dalam loop video processing

def processframe(frame, model):

results = model(frame)

detections = sv.Detections.fromultralytics(results[0])

# Update tracker

detections = tracker.updatewithdetections(detections)

# Sekarang detections memiliki trackerid

print(f"Tracker IDs: {detections.trackerid}")

return detections

Tracking dengan Trace

tracker = sv.ByteTrack()

traceannotator = sv.TraceAnnotator(

thickness=2,

tracelength=50

)

bboxannotator = sv.BoxAnnotator()

labelannotator = sv.LabelAnnotator()

def processframe(frame, model):

results = model(frame)

detections = sv.Detections.fromultralytics(results[0])

detections = tracker.updatewithdetections(detections)

# Buat label dengan tracker ID

labels = [

f"#{trackerid} {classnames[classid]}"

for trackerid, classid

in zip(detections.trackerid, detections.classid)

]

# Annotate

annotated = frame.copy()

annotated = traceannotator.annotate(scene=annotated, detections=detections)

annotated = bboxannotator.annotate(scene=annotated, detections=detections)

annotated = labelannotator.annotate(

scene=annotated, detections=detections, labels=labels

)

return annotated

Integrasi dengan YOLO

import supervision as sv

from ultralytics import YOLO

import cv2

Muat model

model = YOLO("yolov8n.pt")

Setup annotators

bboxannotator = sv.BoxAnnotator()

labelannotator = sv.LabelAnnotator()

Proses gambar

image = cv2.imread("street.jpg")

results = model(image)

detections = sv.Detections.fromultralytics(results[0])

Filter hanya kendaraan

vehicleclasses = [2, 3, 5, 7] # car, motorcycle, bus, truck

vehicles = detections[np.isin(detections.classid, vehicleclasses)]

Buat label

labels = [

f"{model.names[classid]} {conf:.2f}"

for classid, conf in zip(vehicles.classid, vehicles.confidence)

]

Annotate

annotated = bboxannotator.annotate(scene=image.copy(), detections=vehicles)

annotated = labelannotator.annotate(

scene=annotated, detections=vehicles, labels=labels

)

cv2.imwrite("vehiclesdetected.jpg", annotated)

print(f"Total kendaraan terdeteksi: {len(vehicles)}")

Video Processing

Memproses Video dengan VideoSink

import supervision as sv

from ultralytics import YOLO

model = YOLO("yolov8n.pt")

tracker = sv.ByteTrack()

bboxannotator = sv.BoxAnnotator()

labelannotator = sv.LabelAnnotator()

Informasi video

videoinfo = sv.VideoInfo.fromvideopath("inputvideo.mp4")

print(f"Resolution: {videoinfo.width}x{videoinfo.height}")

print(f"FPS: {videoinfo.fps}")

print(f"Total frames: {videoinfo.totalframes}")

Proses video

with sv.VideoSink(

targetpath="outputvideo.mp4",

videoinfo=videoinfo

) as sink:

for frame in sv.getvideoframesgenerator(

sourcepath="inputvideo.mp4"

):

# Deteksi

results = model(frame)

detections = sv.Detections.fromultralytics(results[0])

detections = tracker.updatewithdetections(detections)

# Annotate

labels = [

f"#{tid} {model.names[cid]}"

for tid, cid in zip(

detections.trackerid, detections.classid

)

]

annotated = bboxannotator.annotate(

scene=frame.copy(), detections=detections

)

annotated = labelannotator.annotate(

scene=annotated, detections=detections, labels=labels

)

sink.writeframe(annotated)

Callback-Based Video Processing

def callback(frame: np.ndarray, index: int) -> np.ndarray:

results = model(frame)

detections = sv.Detections.fromultralytics(results[0])

detections = tracker.updatewithdetections(detections)

annotated = bboxannotator.annotate(

scene=frame.copy(), detections=detections

)

return annotated

sv.processvideo(

sourcepath="input.mp4",

targetpath="output.mp4",

callback=callback

)

FPS Monitor

import supervision as sv

import time

fpsmonitor = sv.FPSMonitor(samplesize=30)

for frame in sv.getvideoframesgenerator("video.mp4"):

fpsmonitor.tick()

# Proses frame...

results = model(frame)

detections = sv.Detections.fromultralytics(results[0])

# Tampilkan FPS

fps = fpsmonitor.fps

print(f"FPS: {fps:.1f}")

# Tambahkan FPS ke frame

cv2.putText(

frame,

f"FPS: {fps:.1f}",

(10, 30),

cv2.FONTHERSHEYSIMPLEX,

1,

(0, 255, 0),

2

)

Contoh Praktis: Sistem Penghitung Kendaraan dengan Zone-Based Tracking

Berikut adalah contoh lengkap membangun sistem penghitung kendaraan yang menggunakan polygon zone dan object tracking.

import supervision as sv

from ultralytics import YOLO

import numpy as np

import cv2

Konfigurasi

MODELPATH = "yolov8n.pt"

VIDEOPATH = "trafficvideo.mp4"

OUTPUTPATH = "trafficcounted.mp4"

Kelas kendaraan dalam COCO dataset

VEHICLECLASSES = {

2: "car",

3: "motorcycle",

5: "bus",

7: "truck"

}

class VehicleCounter:

def init(self, videopath: str, modelpath: str):

self.model = YOLO(modelpath)

self.videoinfo = sv.VideoInfo.fromvideopath(videopath)

# Inisialisasi tracker

self.tracker = sv.ByteTrack(

trackactivationthreshold=0.25,

losttrackbuffer=30,

minimummatchingthreshold=0.8,

framerate=self.videoinfo.fps

)

# Definisikan zona counting (sesuaikan dengan video Anda)

# Zona masuk (atas)

self.entryzonepolygon = np.array([

[100, 200], [700, 200], [700, 300], [100, 300]

])

# Zona keluar (bawah)

self.exitzonepolygon = np.array([

[100, 400], [700, 400], [700, 500], [100, 500]

])

# Buat zona

self.entryzone = sv.PolygonZone(

polygon=self.entryzonepolygon

)

self.exitzone = sv.PolygonZone(

polygon=self.exitzonepolygon

)

# Line counter (garis horizontal di tengah)

self.linezone = sv.LineZone(

start=sv.Point(x=50, y=350),

end=sv.Point(x=750, y=350)

)

# Annotators

self.bboxannotator = sv.BoxAnnotator(thickness=2)

self.labelannotator = sv.LabelAnnotator(

textscale=0.5,

textthickness=1

)

self.traceannotator = sv.TraceAnnotator(

thickness=2,

tracelength=60

)

self.entryzoneannotator = sv.PolygonZoneAnnotator(

zone=self.entryzone,

color=sv.Color.GREEN,

thickness=2

)

self.exitzoneannotator = sv.PolygonZoneAnnotator(

zone=self.exitzone,

color=sv.Color.RED,

thickness=2

)

self.lineannotator = sv.LineZoneAnnotator(

thickness=2,

textthickness=2,

textscale=0.8

)

# Statistik

self.vehiclecounts = {name: 0 for name in VEHICLECLASSES.values()}

self.trackedids = set()

def processframe(self, frame: np.ndarray, frameindex: int) -> np.ndarray:

# Deteksi objek

results = self.model(frame, verbose=False)

detections = sv.Detections.fromultralytics(results[0])

# Filter hanya kendaraan

vehiclemask = np.isin(

detections.classid,

list(VEHICLECLASSES.keys())

)

detections = detections[vehiclemask]

# Filter confidence rendah

detections = detections[detections.confidence > 0.3]

# Update tracker

detections = self.tracker.updatewithdetections(detections)

# Update zona dan line counter

self.entryzone.trigger(detections=detections)

self.exitzone.trigger(detections=detections)

self.linezone.trigger(detections=detections)

# Hitung kendaraan unik

if detections.trackerid is not None:

for tid, cid in zip(detections.trackerid, detections.classid):

if tid not in self.trackedids:

self.trackedids.add(tid)

vehicletype = VEHICLECLASSES.get(cid, "unknown")

self.vehiclecounts[vehicletype] += 1

# Buat label

labels = []

if detections.trackerid is not None:

labels = [

f"#{tid} {VEHICLECLASSES.get(cid, '?')} {conf:.2f}"

for tid, cid, conf in zip(

detections.trackerid,

detections.classid,

detections.confidence

)

]

# Annotate frame

annotated = frame.copy()

annotated = self.traceannotator.annotate(

scene=annotated, detections=detections

)

annotated = self.bboxannotator.annotate(

scene=annotated, detections=detections

)

annotated = self.labelannotator.annotate(

scene=annotated, detections=detections, labels=labels

)

annotated = self.entryzoneannotator.annotate(scene=annotated)

annotated = self.exitzoneannotator.annotate(scene=annotated)

annotated = self.lineannotator.annotate(

frame=annotated, linecounter=self.linezone

)

# Overlay statistik

self.drawstats(annotated, frameindex)

return annotated

def drawstats(self, frame: np.ndarray, frameindex: int):

"""Gambar statistik di atas frame."""

# Background semi-transparan

overlay = frame.copy()

cv2.rectangle(overlay, (10, 10), (300, 180), (0, 0, 0), -1)

cv2.addWeighted(overlay, 0.6, frame, 0.4, 0, frame)

# Judul

cv2.putText(

frame, "Vehicle Counter",

(20, 35), cv2.FONTHERSHEYSIMPLEX, 0.7, (255, 255, 255), 2

)

# Detail per kendaraan

yoffset = 60

total = 0

for vehicletype, count in self.vehiclecounts.items():

cv2.putText(

frame,

f"{vehicletype}: {count}",

(20, yoffset),

cv2.FONTHERSHEYSIMPLEX,

0.5,

(200, 200, 200),

1

)

yoffset += 25

total += count

# Total

cv2.putText(

frame,

f"Total: {total}",

(20, yoffset + 5),

cv2.FONTHERSHEYSIMPLEX,

0.6,

(0, 255, 0),

2

)

# Line counter

cv2.putText(

frame,

f"In: {self.linezone.incount} | Out: {self.linezone.outcount}",

(20, yoffset + 30),

cv2.FONTHERSHEYSIMPLEX,

0.5,

(255, 255, 0),

1

)

def run(self, outputpath: str):

"""Jalankan proses counting pada video."""

print(f"Video: {self.videoinfo.width}x{self.videoinfo.height}")

print(f"FPS: {self.videoinfo.fps}")

print(f"Total frames: {self.videoinfo.totalframes}")

print("Memproses video...")

fpsmonitor = sv.FPSMonitor(samplesize=30)

with sv.VideoSink(

targetpath=outputpath,

videoinfo=self.videoinfo

) as sink:

for index, frame in enumerate(

sv.getvideoframesgenerator(VIDEOPATH)

):

fpsmonitor.tick()

annotated = self.processframe(frame, index)

sink.writeframe(annotated)

# Progress report setiap 100 frame

if index % 100 == 0:

fps = fpsmonitor.fps

progress = (index / self.videoinfo.totalframes) * 100

print(

f"Frame {index}/{self.videoinfo.totalframes} "

f"({progress:.1f}%) - FPS: {fps:.1f}"

)

# Laporan final

print("\n=== Hasil Penghitungan ===")

total = 0

for vehicletype, count in self.vehiclecounts.items():

print(f" {vehicletype}: {count}")

total += count

print(f" Total kendaraan: {total}")

print(f" Unique tracked IDs: {len(self.trackedids)}")

print(f" Line In: {self.linezone.incount}")

print(f" Line Out: {self.linezone.outcount}")

Jalankan

if name == "main":

counter = VehicleCounter(

videopath=VIDEOPATH,

modelpath=MODELPATH

)

counter.run(outputpath=OUTPUTPATH)

Menjalankan Vehicle Counter

# Install dependensi

pip install supervision ultralytics opencv-python numpy

Download model YOLO (otomatis saat pertama kali)

Siapkan video traffic Anda

Jalankan

python vehiclecounter.py

Konfigurasi Zona untuk Video Anda

Untuk mendefinisikan zona yang sesuai dengan video Anda, gunakan utilitas dari Supervision:

import supervision as sv

import cv2

Ambil frame pertama dari video

framegenerator = sv.getvideoframesgenerator("trafficvideo.mp4")

firstframe = next(framegenerator)

Tampilkan dan catat koordinat zona

cv2.imshow("First Frame", firstframe)

cv2.waitKey(0)

cv2.destroyAllWindows()

Gunakan koordinat yang dicatat untuk polygon zona

Tips dan Best Practices

  • Pilih Model yang Tepat: Gunakan model yang lebih ringan (YOLOv8n) untuk real-time dan model lebih besar (YOLOv8x) untuk akurasi
  • Tuning Tracker: Sesuaikan parameter ByteTrack seperti trackactivationthreshold dan losttrack_buffer berdasarkan skenario
  • Filter Awal: Selalu filter deteksi berdasarkan confidence dan kelas sebelum tracking untuk mengurangi noise
  • Zona yang Akurat: Definisikan polygon zone dengan teliti sesuai area yang dimonitor
  • Batch Processing: Untuk video panjang, gunakan batch processing dan simpan hasil secara periodik
  • Kesimpulan

    Supervision dari Roboflow adalah toolkit yang sangat berguna untuk menyederhanakan workflow computer vision. Dengan abstraksi yang konsisten untuk berbagai model deteksi, annotator visual yang kaya, dan fitur tracking yang powerful, Supervision memungkinkan Anda membangun aplikasi computer vision production-ready dengan kode yang bersih dan maintainable. Integrasi seamless dengan YOLO, Detectron2, dan SAM membuatnya menjadi pilihan utama untuk proyek computer vision modern.

    Artikel Terkait

    Florence-2: Model Vision Multi-Task dari Microsoft

    Florence-2: Model Vision Multi-Task dari Microsoft Daftar Isi Pendahuluan Prasyarat Instalasi Memuat Model Florence-2

    Tutorial Lengkap Ultralytics: Object Detection dengan YOLO

    Tutorial Lengkap Ultralytics: Object Detection dengan YOLO Ultralytics adalah framework Python yang menyediakan implemen...

    Panduan Lengkap DETR: Object Detection dengan Transformers

    Panduan Lengkap DETR: Object Detection dengan Transformers DETR (DEtection TRansformer) adalah pendekatan revolusioner u...

    Tutorial Surya OCR: Document AI untuk Text Detection, OCR, dan Layout Analysis

    Tutorial Surya OCR: Document AI untuk Text Detection, OCR, dan Layout Analysis Surya adalah library Document AI open-sou...