otonomarac
COMPLETE • LIVE DEMOA 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.
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.
Three points where the obvious choice was the wrong one Bariz tercihin yanlış olduğu üç nokta
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.
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
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.
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)
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.
# 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
What it outputsNe üretiyor
REAL RUNS • PLATES PIXELATED