Ultralytics YOLO27: Bekleme listesine katıl.
Get Started
Üretimde Ultralytics YOLO·Takip Et ve İş Hatları Oluştur·Ders 6/9
Dersorta düzey

Sayım, Isı Haritaları ve Hız Tahmini

Takibin üzerine çizgi sayacı, bölge doluluk ölçümü, ısı haritaları ve hız tahminleri kur; ardından bunları dürüstçe kalibre et.

Üretimdeki görüntü işleme sistemlerinin çoğu model.predict() değildir. Bunlar, nesnelerin geçtiği bir çizgi, nesnelerin bulunduğu bir bölge ve pikselleri metreye dönüştüren bir ölçek gibi birkaç geometrik işlemle bir takipçinin birleşimidir. Sonuçların yanlış gittiği yer geometridir: bu dersteki örnek klipte bir hız tahmin aracı, yanlış tahmin edilmiş tek bir sayı nedeniyle yürüyen yayaların gerçek hızlarının dörtte biri olan 1 km/sa hızla yürüdüğünü bildiriyor.

Sonuç

Gerçek bir videoda çizgi sayacı, bölge sayımı, ısı haritası ve hız tahmini oluştur; hız tahminini bilinen bir referansla kalibre et.

Hızlı Başlangıç
Nasıl ilerleyeceğini zaten biliyorsan, işte kısa sürüm.
  1. Çizgi geçişi: solutions.ObjectCounter(region=[p1, p2]); izin merkezinin çizgiyi geçmesi GİRİŞ veya ÇIKIŞ sayacını artırır.

  2. Bölge doluluğu: Takip edilen her kutu için yapılan tek bir noktanın çokgen içinde olup olmadığı testi, o anda içeride olanları verir.

  3. Isı haritası: solutions.Heatmap, takip edilen nesnelerin zaman geçirdiği yerleri biriktirir.

  4. Hız: Piksel yer değiştirmesi × piksel başına metre ÷ zaman. Sahnedeki ölçeği ölç ve gerçek FPS değerini doğrula.

Uygulamalı

Takip ve Geometri#

ultralytics.solutions içindeki her çözüm sınıfı, dahili olarak Takip modunu çalıştırır ve ardından izin geçmişine kendi geometrisini uygular. Ek paketleri bir kez pip install "ultralytics[solutions]" ile yükle.

SınıfGeometriTemel sonuçlar
ObjectCounter2 nokta = çizgi, 3 veya daha fazla nokta = çokgenin_count, out_count, classwise_count
RegionCounterBir veya daha fazla adlandırılmış çokgenregion_counts
HeatmapKutu alanlarını zaman içinde biriktirirplot_im (bölge verilirse sayımları da içerir)
SpeedEstimatorİzin yer değiştirmesi × meter_per_pixelspeed_dict (iz kimliği başına km/sa)

Çözümler varsayılan olarak tracker="tracktrack.yaml" kullanır; önceki derste doğruladığın takipçiyi geçir.

Çizgi Geçişlerini Say#

Ultralytics YOLO ile depo konveyöründeki paketlerin sayılması: her kutunun bir iz kimliği vardır (#013 ile #018 arasında) ve kutular camgöbeği sayım çizgisini geçerken GİRİŞ sayacı 12 değerini gösterir

Sayım çizgisi bir doğru parçasıdır. Bir nesne, kutusunun merkezi iki kare arasında çizgiyi geçtiğinde bir kez sayılır; GİRİŞ veya ÇIKIŞ olacağını nesnenin geldiği taraf belirler. Yukarıdaki konveyörde bu nedenle takip gerekir: kimlik olmadan #015 numaralı kutu çizgiye dokunduğu her karede yeniden sayılırdı.

import cv2

from ultralytics import solutions
from ultralytics.utils.downloads import safe_download

video = safe_download("https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4")
cap = cv2.VideoCapture(str(video))  # 640x360, 30 FPS, 62 frames
w, h, fps = (int(cap.get(p)) for p in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))
writer = cv2.VideoWriter("counted.mp4", cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))

counter = solutions.ObjectCounter(
    model="yolo26n.pt",
    region=[(0, 180), (640, 180)],  # two points: a horizontal line across the middle of the frame
    classes=[0],  # person
    tracker="bytetrack.yaml",
    verbose=False,
)

while True:
    ok, frame = cap.read()
    if not ok:
        break
    results = counter(frame)  # detect + track + count in one call
    writer.write(results.plot_im)

cap.release()
writer.release()
print(f"in={results.in_count} out={results.out_count} classwise={results.classwise_count}")
in=2 out=2 classwise={'person': {'IN': 2, 'OUT': 2}}

Klipteki iki saniye içinde dört kişi meydanın ortasından geçti: her yönde ikişer kişi. Varsayılan TrackTrack yapılandırmasıyla aynı betik in=0 out=1 sonucunu verir; çünkü daha az iz, daha az geçiş demektir. Bir sayıya güvenmeden önce counted.mp4 dosyasını aç ve her geçişi gözünle doğrula.

Ultralytics YOLO ile bölünmüş yolda çizgi geçiş sayacı: takip edilen otomobiller ve bir kamyon camgöbeği çizgiyi geçiyor, yön okları gösteriliyor ve araç sayısı 24 giriş, 18 çıkış olarak veriliyor

Yolda aynı çizgi trafiği yönüne göre ayırır: yukarı doğru geçen araçlar GİRİŞ, aşağı doğru geçenler ÇIKIŞ olarak sayılır. Çizgiyi nesnelerin düzgün ve dik açıyla geçtiği bir yere; kadraj kenarlarından, engelleyicilerden ve kutuların çok küçük kaldığı yolun uzak ucundan uzağa yerleştir.

Bir Bölgedeki Doluluğu Say#

Çokgen bir bölge, "Şu anda içeride kaç nesne var?" sorusunu yanıtlar. Bölge sayımı kılavuzunda kullanıma hazır bir RegionCounter bulunur; temelinde, takip edilen her kutu için yapılan tek bir noktanın çokgen içinde olup olmadığı testi vardır:

from shapely.geometry import Point, Polygon

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
zone = Polygon([(100, 100), (500, 100), (500, 300), (100, 300)])  # pixel coordinates

peak = 0
for r in model.track(video, stream=True, tracker="bytetrack.yaml", classes=[0], verbose=False):
    if not r.boxes.is_track:
        continue
    inside = sum(zone.contains(Point(cx, cy)) for cx, cy in r.boxes.xywh[:, :2].tolist())
    peak = max(peak, inside)
print(f"peak occupancy: {peak} people inside the zone")
peak occupancy: 10 people inside the zone

xywh[:, :2] her kutunun merkezidir. Kuyruklar ve bekleme süresi için bölgeye giriş zamanını her kimlik bazında sakla.

Hızı Tahmin Et#

Otoyolda hız tahmini: takip edilen her otomobil ve kamyon, tahmini hızıyla km/sa cinsinden (48 ile 65 arasında) etiketlenmiş ve kısa bir hareket izi bırakıyor

Yukarıdaki her etiket, aracın arkasındaki izden gelir: izin bilinen sayıda kare boyunca piksel cinsinden aldığı mesafe. Hız = piksel mesafesi × piksel başına metre ÷ geçen süre. Sonucun doğru olup olmadığını iki girdi belirler:

  1. Piksel başına metre. Sahnedeki bilinen bir uzunluğu (yer karosu, şerit işareti, park yeri) nesnelerin hareket ettiği derinlikte ölç. Açılı kameralar için bunun yerine zemin düzlemini dört noktalı homografiyle eşle.
  2. Gerçek çekim hızı. Hız FPS ile ölçeklenir; yeniden kodlanan veya yavaşlatılan görüntüler tüm hızları aynı oranda değiştirir.

Bu döngü, her kutunun alt orta noktasını (nesnenin zemine temas ettiği yeri) ölçer ve her iz için 10 kare üzerinden ortalama alır:

from collections import defaultdict, deque

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
fps = 30  # the real capture rate, not the playback rate
pixels_per_meter = 33  # example: a 1.2 m floor feature spans 40 px; measure your own scene

prev = {}  # track ID -> last bottom-center point
window = defaultdict(lambda: deque(maxlen=10))  # about 0.3 s of speeds per track at 30 FPS
for r in model.track(video, stream=True, tracker="bytetrack.yaml", classes=[0], verbose=False):
    if not r.boxes.is_track:
        continue
    for (x1, y1, x2, y2), tid in zip(r.boxes.xyxy.tolist(), r.boxes.id.int().tolist()):
        cx, cy = (x1 + x2) / 2, y2  # bottom-center sits on the ground plane
        if tid in prev:
            px, py = prev[tid]
            meters = ((cx - px) ** 2 + (cy - py) ** 2) ** 0.5 / pixels_per_meter
            window[tid].append(meters * fps * 3.6)  # km/h
        prev[tid] = (cx, cy)

smoothed = sorted(sum(s) / len(s) for s in window.values() if len(s) == s.maxlen)
print(f"{len(smoothed)} tracks; median {smoothed[len(smoothed) // 2]:.1f} km/h")
29 tracks; median 2.1 km/h

İnsanlar 4–5 km/sa hızla yürür; dolayısıyla 2.1 km/sa, örnekteki ölçeğin bu sahne için yanlış olduğunu gösterir: pixels_per_meter değeri burada ölçülmedi. Bilinen bir hızı medyanla karşılaştırarak yaptığın bu makullük kontrolü, önemli olan alışkanlıktır.

solutions.SpeedEstimator, aynı fikri üretim kullanımı için uygular: her izin kutu merkezini max_hist kare boyunca ölçer, meter_per_pixel ile dönüştürür ve her kimlik için tek bir hız belirler (üst sınır: max_speed):

import cv2

from ultralytics import solutions
from ultralytics.utils.downloads import safe_download

video = safe_download("https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4")
cap = cv2.VideoCapture(str(video))
speed = solutions.SpeedEstimator(
    model="yolo26n.pt",
    classes=[0],
    tracker="bytetrack.yaml",
    fps=30,  # the real capture rate, not the playback rate
    meter_per_pixel=0.03,  # a guess: a ~0.45 m shoulder width spans ~15 px here
    max_hist=15,  # 0.5 s of history before a speed is locked
    verbose=False,
)

speeds = {}
while True:
    ok, frame = cap.read()
    if not ok:
        break
    speeds.update(speed(frame).speed_dict)  # {track_id: km/h} once locked
cap.release()

kmh = sorted(speeds.values())
print(f"{len(kmh)} tracks; median {kmh[len(kmh) // 2]} km/h, range {kmh[0]}-{kmh[-1]} km/h")
25 tracks; median 1 km/h, range 0-4 km/h

Yine yaklaşık 4 kat sapma var; nedeni de aynı: vücut boyutundan tahmin edilen bir ölçek. Bunun gibi üstten çekim yapan kameralar için kutu merkezi uygundur; açılı kameralarda alt orta nokta döngüsünü veya bir homografiyi tercih et.

Isı Haritası Oluştur#

Ultralytics YOLO ile bir şehir otoyolunun ısı haritası: mavi-kırmızı katman en yoğun şeritlerde en parlak hâlde; araç ve kamyon kutuları ile 12 otomobil ve 2 kamyonluk güncel bir sayaç

Bir ısı haritası, her karede izlenen her kutunun altında ısı biriktirir; böylece en yoğun trafiği taşıyan şeritler veya koridorlar en parlak şekilde görünür. Haritaya bir region ver; yukarıdaki otoyol örneğinde olduğu gibi nesneleri de sayar:

import cv2

from ultralytics import solutions
from ultralytics.utils.downloads import safe_download

video = safe_download("https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4")
cap = cv2.VideoCapture(str(video))
heatmap = solutions.Heatmap(
    model="yolo26n.pt",
    classes=[0],
    tracker="bytetrack.yaml",
    colormap=cv2.COLORMAP_PARULA,
    verbose=False,
)

while True:
    ok, frame = cap.read()
    if not ok:
        break
    results = heatmap(frame)
cap.release()
cv2.imwrite("heatmap.jpg", results.plot_im)  # Birikmiş ısı katmanının bulunduğu son kare

Saatlerce süren görüntülerde aynı katman, yoğun koridorları, kullanılmayan bölgeleri ve insanların gerçekten izlediği yolları gösterir. Antrenman izleme ve Streamlit canlı çıkarım arayüzü aynı yapı taşlarıyla oluşturulur.

Yaygın Hatalar#

Modeli her karede iki kez çalıştırma

Belirti: Sayaç işlem hattı beklenen FPS'nin yarısında çalışıyor. Çözüm: ObjectCounter, Heatmap ve SpeedEstimator algılama ve izlemeyi kendi içinde yapar. Bunları kendi model.track() döngüne sarmalama ve r.orig_img aktarma; ham kareleri besle.

Kalibre edilmemiş hıza güvenme

Belirti: Yayalar 1 km/sa veya arabalar 300 km/sa hızla gidiyor. Çözüm: Nesnelerin hareket ettiği bilinen bir uzunluğu kullanarak meter_per_pixel değerini ölç, kameranın gerçek FPS değerini doğrula ve medyanı bilinen bir hızla (yürüme hızı veya belirtilen hız sınırı) karşılaştır.

Açılı kameralarda kutunun alt orta noktasını kullan

Nesne kameraya yaklaşıp kutusu büyüdükçe geometrik merkez yükselir. Alt orta nokta, nesnenin yere temas ettiği yeri yaklaşık olarak gösterir; bu noktadan ölçülen mesafeler gerçek hareketi çok daha yakından takip eder.

Dene

Kendi alanından bir videoda (veya demo klibinde) çizgi sayacını oluştur ve counted.mp4 içindeki her geçişi gözle kontrol et. Ardından sahnedeki gerçek uzunluklardan birini ölç, çözüm betiğiyle ölçeği hesapla, speed_loop.py komutunu yeniden çalıştır ve medyan hızı bilinen bir referansla karşılaştır. Sayımları, ölçeği ve medyan hızların önceki ve sonraki değerlerini sun.

Tamamlanma ölçütü
Aşağıdakilerin tümü doğru olduğunda dersi tamamlamış olursun.
  • Çizgi sayacındaki IN ve OUT değerleri, aynı klip için elle yaptığın sayımla eşleşiyor.

  • Hız tahmininde sahnede ölçtüğün bir ölçeği kullanıyorsun ve medyan değer, bilinen bir referans hızın %25'i içinde kalıyor.

  • Açılı bir kamerada hız ölçümü için kutunun alt orta noktasının neden doğru nokta olduğunu açıklayabiliyorsun.

Çözümü göster

Karede ölçebileceğin bir şeyden kalibrasyon yap, ardından makullük kontrolü uygula:

# Two points along a floor feature whose real length you know (read them off a saved frame)
(x1, y1), (x2, y2) = (100, 300), (140, 300)
real_length_m = 1.2  # e.g. measured tile width or lane marking

pixels = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
print(f"pixels_per_meter = {pixels / real_length_m:.1f}, meter_per_pixel = {real_length_m / pixels:.4f}")
pixels_per_meter = 33.3, meter_per_pixel = 0.0300

pixels_per_meter öğesini speed_loop.py içine (veya meter_per_pixel öğesini SpeedEstimator içine) koyup yeniden çalıştır. Yürüyenlerin hızları hâlâ 4–5 km/sa değerinden çok farklı görünüyorsa ölçek yanlış derinlikte ölçülmüştür veya FPS yanlıştır: yarı hızda oynatılan bir klip tüm okumaları yarıya indirir. Demo klibinde her iki betik de aynı tahmini ölçeği kullandı (piksel başına 0.03 m, yani metre başına 33 piksel) ve 2–4 kat düşük hızlar ölçtü; dolayısıyla ya burada bir piksel tahminden daha fazla alanı kapsıyor ya da klibin gerçek çekim hızı 30 FPS değil. Hangisinin geçerli olduğunu ancak sahnede ölçüm yapmak belirler.

Sırada ne var

Tek model ve tek akış yönetilebilir. Sırada paralel olarak çok sayıda akış ve bunlarla birlikte gelen iş parçacığı güvenli çıkarım disiplini var.

İlerlemeni kaydetmek için giriş yap