OCA.DEV
arrow_back ALL PROJECTSTÜM PROJELER

otonomarac

COMPLETE • LIVE DEMO

A perception pipeline that takes a single forward-facing camera and answers: what is in the scene, how it moves between frames, how far away it is, where the drivable area is, and whether a collision is close. The output is a two-panel video — the annotated camera view on the left, a live bird's-eye map on the right. Tek bir ileri bakan kameradan alıp şunu cevaplayan bir algı pipeline'ı: sahnede ne var, kareler arasında nasıl hareket ediyor, ne kadar uzakta, sürülebilir alan nerede ve çarpışma yakın mı. Çıktı iki panelli bir video — solda işaretlenmiş kamera görüntüsü, sağda canlı kuşbakışı harita.

8 weeks, start to demo hafta, baştan demoya
7 pipeline layers pipeline katmanı
2,827 lines in src/perception satır, src/perception
CPU free Spaces tier ücretsiz Spaces katmanı
DETECT → TRACK → DEPTH → BEV

Gaps in the map are directions no camera saw — every vehicle casts an occlusion shadow. Map distances are measured from the calibration reference row, not the vehicle's nose. Haritadaki boşluklar hiçbir kameranın görmediği yönler — her araç bir örtme gölgesi bırakıyor. Harita mesafeleri aracın burnundan değil, kalibrasyon referans satırından ölçülüyor.

otonomarac LAYER FLOW
3 PARALLEL BRANCHES • 1 FUSION POINT
The otonomarac layer flow: one video frame fans out to detection, depth and segmentation, merges at a fusion layer, and splits again into bird's-eye projection and risk before being rendered Video frame Detection YOLO • COCO classes Depth Depth Anything V2 Segmentation drivable area • lanes Tracking ByteTrack • stable IDs Fusion layer (id, class, position, depth) BEV projection homography • ground plane Risk closing speed • TTC Rendered output video
Why three branches Detection, depth and segmentation do not depend on each other, so they read the same frame independently and only meet at fusion. Tespit, derinlik ve segmentasyon birbirine bağlı değil; aynı kareyi bağımsız okuyup yalnızca füzyonda buluşuyorlar.
The critical link Speed and time-to-collision are both derived from track history, so tracker ID stability is the single point everything downstream depends on. Hız da çarpışmaya kalan süre de takip geçmişinden çıkıyor; bu yüzden takip ID kararlılığı, aşağı akıştaki her şeyin bağlı olduğu tek nokta.
No custom training Pre-trained weights throughout. The work is in the geometry, the fusion and the measurement, not in a new model. Baştan sona önceden eğitilmiş ağırlıklar. İş yeni bir modelde değil; geometride, füzyonda ve ölçümde.
otonomarac THE THREE DECISIONS THAT MATTERED

Three points where the obvious choice was the wrong one Bariz tercihin yanlış olduğu üç nokta

STAGE 01 / src/perception/depth.py

Median, not mean Ortalama değil, medyan

Depth Anything gives a value per pixel, but an object needs one number. A bounding box always contains some background pixels — sky through a windscreen, road under a bumper — and averaging lets a handful of them drag the estimate. The median does not move. The sample is taken from the lower-centre of the box, which is the part most likely to be the object itself. Depth Anything piksel başına bir değer veriyor ama bir nesne için tek sayı gerekiyor. Sınırlayıcı kutunun içinde her zaman arka plan pikselleri bulunur — camdan görünen gökyüzü, tamponun altındaki yol — ve ortalama alınca birkaç tanesi tahmini sürükler. Medyan kıpırdamaz. Örnek, kutunun alt-orta bölgesinden alınıyor; orası nesnenin kendisi olma ihtimali en yüksek kısım.

RELATIVE DEPTH NUMPY MEDIAN LOWER-CENTRE PATCH
def fuse(detections, disparity_map, config, camera=None):
    """Her tespite derinlik degeri yazar (yerinde degistirir).

    Ornek bolgesindeki degerlerin **medyani** alinir, ortalamasi degil:
    kutu icinde arka plana ait birkac piksel her zaman bulunur ve ortalama
    bunlardan etkilenir, medyan etkilenmez.
    """
    shape = disparity_map.shape[:2]

    for det in detections:
        region = sample_region(det, shape, config, camera)
        if region is None:
            det.depth = None
            continue

        x1, y1, x2, y2 = region
        patch = disparity_map[y1:y2, x1:x2]
        if patch.size == 0:
            det.depth = None
            continue

        det.depth = relative_distance(float(np.median(patch)))

    return detections
STAGE 02 / src/perception/bev.py

The car's own bonnet is not road Aracın kendi kaputu yol değildir

The projection takes the bottom edge of a box as the point where the object touches the ground, then maps it through a homography. But the bonnet fills the lower band of every dashcam frame, so a contact point that lands there is describing bodywork, not road — and the homography would happily turn it into a confident position on the map. Those points are dropped instead. İzdüşüm, kutunun alt kenarını nesnenin zemine değdiği nokta sayıp homografiyle haritaya taşıyor. Ama kaput her dashcam karesinin alt bandını dolduruyor; oraya düşen bir temas noktası yolu değil kaportayı tarif ediyor — ve homografi bunu memnuniyetle haritada kendinden emin bir konuma çevirirdi. Bu noktalar onun yerine düşürülüyor.

cv2.perspectiveTransform HOOD GUARD GROUND CONTACT POINT
def project(self, detections, shape):
    """Her tespitin zemine degme noktasini haritaya tasir.

    Kaputun altina dusen temas noktalari gecersiz sayilir: o piksel yolu
    degil aracin kendi kaputunu gosterir, dolayisiyla homografi oradan
    anlamli bir zemin konumu uretemez.
    """
    height = shape[0]
    hood_row = height * self.camera.hood_top \
        if self.camera.hood_top is not None else height

    usable, contacts = [], []
    for det in detections:
        cx, cy = det.bottom_center
        if cy > hood_row:
            det.bev_xy = None
            continue
        usable.append(det)
        contacts.append((cx, cy))

    ground = self.to_ground(np.array(contacts), shape)
STAGE 03 / src/perception/risk.py

A slope is not a speed until the fit is good Uyum iyi olmadan eğim bir hız değildir

Closing speed comes from fitting a line to the distance history, and time-to-collision follows from distance over that speed. The trap is that a line can be fitted to anything. If the residual is large the distance is not changing smoothly, which means the slope is measuring tracker jitter rather than motion — so the estimate is refused rather than reported. Objects moving away or standing still get no TTC at all, because there is none. Yaklaşma hızı, mesafe geçmişine bir doğru uydurmaktan geliyor; çarpışmaya kalan süre de mesafenin bu hıza bölümü. Tuzak şu: her şeye bir doğru uydurulabilir. Artık büyükse mesafe düzgün değişmiyordur, yani eğim hareketi değil takip titremesini ölçüyordur — bu yüzden tahmin raporlanmak yerine reddediliyor. Uzaklaşan ya da duran nesnelere hiç TTC verilmiyor, çünkü yok.

FIT-QUALITY GATE np.polyfit SLIDING WINDOW
# Yalnizca son `history_seconds` icindeki gozlemler. Daha eskisi,
# nesnenin o zamandan beri hizlanmis olabilecegi icin yaniltir.
window = [(t, d) for t, d in history if now - t <= self.config.history_seconds]

# Mesafenin zamana gore egimi. Negatif egim = mesafe azaliyor = yaklasiyor.
coeffs = np.polyfit(times, dists, 1)
slope = float(coeffs[0])
closing = -slope

# Fit kalitesi kapisi: artik buyukse mesafe duzgun degismiyor demektir
# ve egimden cikarilan "hiz" gercek hareket degil gurultudur.
residual = float(np.sqrt(np.mean((dists - np.polyval(coeffs, times)) ** 2)))
if residual > self.config.max_fit_residual_ratio * max(distance, 1.0):
    return Motion(track_id, distance, None, None, RiskLevel.NONE, len(window))

if closing < self.config.min_closing_speed:
    # Uzaklasiyor ya da duragan: TTC tanimsiz, risk yok.
    return Motion(track_id, distance, closing, None, RiskLevel.NONE, len(window))

ttc = distance / closing
YOLO ByteTrack Depth Anything V2 Homography OpenCV Gradio

What it outputsNe üretiyor

REAL RUNS • PLATES PIXELATED
Drivable area and lane paint drawn back onto a Maltepe street scene
Drivable area + lane paint The segmentation layer drawn back onto the camera frame. Green is drivable surface, blue is the region the network rejects, and the magenta line is the bonnet edge the projection has to stay above. Segmentasyon katmanı kamera karesine geri çizilmiş hâlde. Yeşil sürülebilir yüzey, mavi ağın reddettiği bölge, macenta çizgi de izdüşümün üstünde kalması gereken kaput kenarı.
Homography calibration quadrilateral on the road, with the warped bird's-eye result beside it
Bird's-eye calibration The yellow quadrilateral marks four ground-plane points; the panel on the right is what the homography turns them into. Map distances are measured from the calibration reference row, not from the car's nose. Sarı dörtgen zemin düzleminde dört noktayı işaretliyor; sağdaki panel homografinin bunları neye çevirdiği. Harita mesafeleri aracın burnundan değil, kalibrasyon referans satırından ölçülüyor.
A sweep of candidate calibration reference rows drawn across the bottom of the frame
The bonnet artefact Candidate reference rows swept across the bottom of the frame. The car's own bonnet fills the lower band of every frame, so a row chosen too low projects the bodywork into the map as if it were road. Karenin altında taranan aday referans satırları. Aracın kendi kaputu her karenin alt bandını dolduruyor; fazla aşağıdan seçilen bir satır, kaportayı yolmuş gibi haritaya yansıtıyor.
Four night-time dashcam frames at 200, 600, 1000 and 1400 seconds
Where it degrades Night footage sampled at four timestamps. Rain on the glass, headlight bloom and low contrast are where the pipeline loses objects — the failure analysis reports by how much rather than leaving these frames out. Dört zaman damgasından örneklenmiş gece kaydı. Camdaki yağmur, far parlaması ve düşük kontrast pipeline'ın nesne kaybettiği yerler — hata analizi bu kareleri dışarıda bırakmak yerine ne kadar kaybettiğini raporluyor.

Read furtherDevamını oku