Розробка системи підрахунку об'єктів у кадрі (Object Counting)
Підрахунок об'єктів на зображенні або відео — задача з нюансами. Простий підхід «детектуй і порахуй бокси» працює лише при малій кількості об'єктів і хорошій видимості кожного. При щільних скупченнях (натовп, урожай на полі, клітини під мікроскопом, автомобілі на парковці) детектори втрачають продуктивність: bounding boxes накладаються, NMS відсікає правильні, а latency зростає через велику кількість об'єктів. Для таких випадків ми застосовуємо спеціалізовані підходи: density maps та crowd counting моделі. За час роботи ми реалізували 30+ проектів у рітейлі, транспорті та біомедицині — точність підрахунку досягає 95% навіть на щільних сценах.
Як ми вирішуємо проблему щільних скупчень?
Для задач із сотнями та тисячами об'єктів у кадрі — підрахунок людей у натовпі, зерен на полі, клітин під мікроскопом — ми використовуємо density map. Це зображення, де кожен піксель містить «щільність» об'єктів в околиці. Інтеграл по density map = кількість об'єктів. Досвід показує: на щільних скупченнях density map дає MAE на 30–50% нижчу, ніж детекція. Наприклад, на Shanghai Tech Part A (щільний натовп) CSRNet показує MAE 68.2 проти ~110 у YOLO при прямій оцінці кількості. Density map — це не просто регресія, а метод, стійкий до occlusion та scale variations. Згідно з Li et al. (2018), ця архітектура залишається еталоном для crowd counting.
Ось приклад архітектури CSRNet, яку ми адаптуємо під ваш домен:
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__() vgg = vgg16(pretrained=True) self.frontend = nn.Sequential(*list(vgg.features.children())[:23]) 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 Детекція + підрахунок для розріджених сцен
Зазначимо: коли об'єктів менше 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 Розмітка для навчання: точкові анотації (dot annotations) — по одній точці на кожен об'єкт. З точок генеруємо density map через Gaussian kernel. Це дешевше за бокси і точніше для щільних сцен.
Counting через лінію (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) def _crosses_line(self, p1, p2): # перевірка перетину відрізка з лінією pass Чому density map ефективніша за детекцію на натовпах?
Детектор намагається знайти кожен об'єкт окремо — при перекриттях bounding boxes накладаються, і NMS відсікає «хороші» бокси. Density map регресує щільність без сегментації кожного об'єкта, що стійкіше до occlusion. На Shanghai Tech Part A (щільний натовп) CSRNet показує MAE 68.2 проти ~110 у YOLO при прямій оцінці кількості.
Як підготувати дані для навчання density map: 3 кроки
- Збір даних — наберіть не менше 1000 зображень вашого сценарію (натовп, транспорт, клітини). Важливо: дані мають покривати всі можливі щільності та освітлення.
- Розмітка — кожен об'єкт відмічається однією точкою (dot annotation). Для щільних натовпів використовуйте інструменти типу LabelMe або CVAT.
- Генерація density map — розмиття точок гаусовим ядром з sigma, що залежить від розміру об'єкта. Ми автоматизуємо цей крок скриптом.
Кейс: підрахунок відвідувачів торговельного центру
Одного разу до нас звернулася мережа ТЦ із задачею: підрахувати кількість людей у кожному залі протягом дня, щоб оптимізувати роботу касирів та охорони. Встановлені камери давали потік 30 FPS, але через перекриття та тіні детектор YOLOv8 давав MAE ~25 на типовий кадр. Ми навчили CSRNet на щільних сценах — після донавчання на 2000 кадрах з dot annotations MAE знизився до 8. Систему розгорнули на NVIDIA T4, latency p99 склав 45 мс — відео оброблялося в реальному часі. За рік експлуатації точність підрахунку не падала нижче 93%, а економія на персоналі склала 1.2 млн грн на рік. На іншому проекті — підрахунок відвідувачів у парку — ми знизили помилку на 40%, що дозволило зекономити 2.3 млн грн за рік.
Застосування та метрики
| Застосування | Підхід | Метрика |
|---|---|---|
| Підрахунок транспорту на дорозі | Трекінг + лінія | Accuracy, false count rate |
| Підрахунок людей у натовпі | Density map (CSRNet) | MAE, RMSE |
| Підрахунок клітин під мікроскопом | Density map | MAE |
| Підрахунок фруктів на плантації | YOLO + counting | mAP, MAE |
| Інвентаризація товарів на полиці | YOLO + counting | Accuracy |
Типові метрики CSRNet на Shanghai Tech:
- Part A (щільні натовпи): MAE 68.2, RMSE 115.0
- Part B (розріджені): MAE 10.6, RMSE 16.0
Що входить у роботу під ключ
- Аудит задачі та даних: визначаємо, який підхід дасть максимальну точність під ваш бюджет.
- Розробка та навчання моделі: від прототипу до production-ready інференсу з квантуванням (INT8) для прискорення.
- Інтеграція у вашу інфраструктуру: API, відеострім, база даних.
- Оптимізація продуктивності: latency p99 < 50 мс на GPU для реального часу.
- Документація та навчання вашої команди.
- Гарантія на точність моделі: фіксуємо MAE в специфікації.
Орієнтовні терміни
| Задача | Термін |
|---|---|
| Підрахунок через детекцію, готова модель | 1–2 тижні |
| Density map, кастомний домен | 3–5 тижнів |
| Комплексна система (відео + аналітика) | 4–7 тижнів |
Точну оцінку даємо після аналізу ваших даних. Отримайте консультацію — обговоримо вашу задачу і підберемо оптимальне рішення. Зв'яжіться з нами, щоб почати проект.







