Розробка системи підрахунку об'єктів у кадрі
Підрахунок об'єктів на зображенні або відео — завдання з нюансами. Простий підхід "детектуй і рахуй бокси" працює тільки при малій кількості об'єктів і хорошій видимості кожного. При щільних скупленнях (толпа, врожай на полі, клітини під мікроскопом, автомобілі на паркінгу) детектори втрачають продуктивність. Для таких випадків застосовуються спеціалізовані підходи: density maps та crowd counting моделі.
Підхід 1: Детекція + підрахунок
Для розріджених об'єктів (< 50 у кадрі, об'єкти не перекриваються сильно) — YOLOv8/YOLO11 + підрахунок боксів:
from ultralytics import YOLO
model = YOLO('yolov8m.pt')
def count_objects(image_path: str, target_class: str) -> int:
results = model(image_path, conf=0.4, iou=0.5)
class_names = model.names
target_id = [k for k, v in class_names.items() if v == target_class][0]
count = 0
for result in results:
for cls in result.boxes.cls:
if cls.item() == target_id:
count += 1
return count
Підхід 2: Density Map для щільних скупленнь
Для завдань зі сотнями та тисячами об'єктів у кадрі: підрахунок людей у товпі, зерен на полі, клітин під мікроскопом.
Density map — зображення, де кожен піксель містить "щільність" об'єктів у окрузі. Інтеграл по density map = кількість об'єктів.
import torch
import torch.nn as nn
from torchvision.models import vgg16
class CSRNet(nn.Module):
"""Crowd Scene Recognition Network для підрахунку людей"""
def __init__(self):
super().__init__()
# Frontend: VGG16 без FC шарів
vgg = vgg16(pretrained=True)
self.frontend = nn.Sequential(*list(vgg.features.children())[:23])
# Backend: dilated convolutions для multi-scale context
self.backend = nn.Sequential(
nn.Conv2d(512, 512, 3, padding=2, dilation=2),
nn.ReLU(inplace=True),
nn.Conv2d(512, 256, 3, padding=2, dilation=2),
nn.ReLU(inplace=True),
nn.Conv2d(256, 128, 3, padding=2, dilation=2),
nn.ReLU(inplace=True),
nn.Conv2d(128, 64, 3, padding=2, dilation=2),
nn.ReLU(inplace=True),
nn.Conv2d(64, 1, 1)
)
def forward(self, x):
x = self.frontend(x)
density_map = self.backend(x)
count = density_map.sum()
return density_map, count
Розмітка для навчання: точечні анотації (dot annotations) — по одній точці на кожен об'єкт. Із точок генеруємо density map через Gaussian kernel.
Підхід 3: Підрахунок через лінію (Line Crossing)
Для відео-підрахунку транспорту, людей у дверях: трекинг + віртуальна лінія.
class LineCrossingCounter:
def __init__(self, line_start, line_end):
self.line = (line_start, line_end)
self.counted_ids = set()
self.count = 0
self.prev_positions = {}
def update(self, track_id, center_x, center_y):
if track_id in self.prev_positions:
prev_pos = self.prev_positions[track_id]
if self._crosses_line(prev_pos, (center_x, center_y)):
if track_id not in self.counted_ids:
self.count += 1
self.counted_ids.add(track_id)
self.prev_positions[track_id] = (center_x, center_y)
Застосування та метрики
| Застосування | Підхід | Метрика |
|---|---|---|
| Підрахунок транспорту на дорозі | Трекинг + лінія | Accuracy, false count rate |
| Підрахунок людей у товпі | Density map (CSRNet) | MAE, RMSE |
| Підрахунок клітин під мікроскопом | Density map | MAE |
| Підрахунок фруктів на плантації | YOLO + counting | mAP, MAE |
| Інвентаризація товарів на полиці | YOLO + counting | Accuracy |
Типові метрики CSRNet на Shanghai Tech dataset:
- Part A (щільні толпи): MAE 68.2, RMSE 115.0
- Part B (розріджені): MAE 10.6, RMSE 16.0
| Завдання | Хронологія |
|---|---|
| Підрахунок через детекцію, готова модель | 1–2 тижні |
| Density map, користувацький домен | 3–5 тижнів |
| Комплексна система (відео + аналітика) | 4–7 тижнів |







