System Development распознавания товаров на полках (Shelf Monitoring)
Shelf Monitoring — автоматический контроль выкладки товаров в рознице: наличие продуктов на полках (out-of-stock), соответствие планограмме, правильность ценников. По данным IHL Group, out-of-stock обходится ритейлу в $1 трлн в год глобально. Автоматизация инспекции полок сокращает реакцию на out-of-stock с часов до минут.
Детекция товаров на полке
from ultralytics import YOLO
import numpy as np
import cv2
class ShelfMonitoringSystem:
def __init__(self, product_model_path: str,
planogram_path: str = None):
self.detector = YOLO(product_model_path)
self.planogram = self._load_planogram(planogram_path) if planogram_path else None
def analyze_shelf_image(self, image: np.ndarray) -> dict:
"""Анализ одного фото полки"""
# Детекция всех SKU
detections = self.detector(image, conf=0.4, iou=0.5)
detected_products = []
for box in detections[0].boxes:
sku = self.detector.model.names[int(box.cls)]
x1, y1, x2, y2 = map(int, box.xyxy[0])
detected_products.append({
'sku': sku,
'bbox': [x1, y1, x2, y2],
'confidence': float(box.conf),
'facings': 1 # каждый bounding box = 1 facing
})
# Агрегация по SKU
sku_counts = {}
for product in detected_products:
sku = product['sku']
if sku not in sku_counts:
sku_counts[sku] = {'count': 0, 'positions': []}
sku_counts[sku]['count'] += 1
sku_counts[sku]['positions'].append(product['bbox'])
result = {
'detected_skus': sku_counts,
'total_facings': len(detected_products),
}
# Сравнение с планограммой
if self.planogram:
result['planogram_compliance'] = self._check_planogram(
sku_counts, self.planogram
)
result['out_of_stock'] = self._find_out_of_stock(
sku_counts, self.planogram
)
return result
def _find_out_of_stock(self, current: dict, planogram: dict) -> list:
"""Нахождение отсутствующих товаров"""
missing = []
for sku, expected_facings in planogram.items():
current_facings = current.get(sku, {}).get('count', 0)
if current_facings == 0:
missing.append({'sku': sku, 'status': 'out_of_stock',
'expected_facings': expected_facings})
elif current_facings < expected_facings * 0.5:
missing.append({'sku': sku, 'status': 'low_stock',
'current': current_facings,
'expected': expected_facings})
return missing
Training модели на корпоративном каталоге
Для крупного ритейлера (5000+ SKU) — иерархическая классификация:
# Структура датасета: изображения кропов продуктов по папкам
# dataset/
# train/
# category_beverages/
# sku_cola_1l/
# sku_juice_orange/
# category_dairy/
# ...
from ultralytics import YOLO
model = YOLO('yolov8l.pt')
model.train(
data='shelf_products.yaml',
epochs=200,
imgsz=640,
batch=32,
workers=8,
optimizer='AdamW',
lr0=1e-3,
# Аугментации специфичные для полки
degrees=5.0, # небольшой поворот
scale=0.3, # изменение масштаба (разные расстояния до полки)
fliplr=0.5,
hsv_h=0.02, # небольшое изменение цвета
mosaic=1.0
)
Мобильное приложение для инспекторов
Сотрудник фотографирует полку через мобильное приложение, система мгновенно показывает:
- Зелёная рамка: SKU в наличии, соответствует планограмме
- Жёлтая: мало товара
- Красная: отсутствует
class ShelfInspectionAPI:
def __init__(self, monitor: ShelfMonitoringSystem):
self.monitor = monitor
def analyze_photo(self, image_bytes: bytes,
store_id: str,
shelf_id: str) -> dict:
image = cv2.imdecode(
np.frombuffer(image_bytes, np.uint8),
cv2.IMREAD_COLOR
)
result = self.monitor.analyze_shelf_image(image)
# Добавляем визуализацию
annotated = self._annotate_image(image, result)
return {
'store_id': store_id,
'shelf_id': shelf_id,
'analysis': result,
'annotated_image_base64': encode_image_b64(annotated)
}
Integration с роботами для автоматической инспекции
Автономные роботы (Simbe Tally, Brain Corp) объезжают магазин и фотографируют полки. CV-система обрабатывает фото в реальном времени, передаёт задания на пополнение персоналу.
| Метрика | Значение |
|---|---|
| Точность распознавания SKU | 88–95% (зависит от схожести продуктов) |
| Точность детекции out-of-stock | 90–97% |
| Скорость анализа фото | < 2 секунды |
| Точность compliance check | 85–92% |
| Масштаб | Срок |
|---|---|
| 100–500 SKU, одна категория | 5–7 недель |
| 1000–5000 SKU, полный магазин | 10–16 недель |
| Сеть + роботы + аналитика | 18–28 недель |







