Горнодобывающие предприятия — второй по смертности сектор после строительства. В подземных шахтах риск фатальных инцидентов в 3 раза выше, чем в карьерах. Типичная проблема: контроль СИЗ в условиях плохого освещения (до 10 люкс), запылённости, мониторинг опасных зон, трекинг персонала (underground personnel tracking), детекция аварийных ситуаций. Автоматизация контроля СИЗ и опасных зон позволяет снизить аварийность на 30–50%. Системы на основе классического CV не справляются: точность детекции касок в темноте падает до 50%. Мы используем современные нейросетевые детекторы YOLO с дообучением на специализированных датасетах, что даёт стабильные 85-95% accuracy даже в тяжёлых условиях.
Мы разрабатываем AI-решения под ключ: от сбора датасета до деплоя на видеосерверах. Наш опыт — более 5 лет в промышленном CV, 30+ проектов для горнодобывающих компаний. Гарантируем compliance rate не ниже 85% на этапе приёмки.
Проблемы, которые решаем
Подземные шахты — экстремальная среда для компьютерного зрения. Низкая освещённость (до 10 люкс), взвесь угольной пыли, высокая влажность. Традиционные детекторы на основе Haar-каскадов или пересчёт по цвету дают 50–60% точности — неприемлемо. Другая сложность — ложные срабатывания на горное оборудование. Ошибки трекинга при пересечении людей с техникой. Без интеграции с SCADA невозможно автоматически заблокировать опасные зоны. Мы реализуем связку OPC-UA / Modbus TCP с задержкой не более 500 мс.
Какие AI-модели мы используем для детекции нарушений?
Базовый стек — YOLOv8/9 с трекингом ByteTrack. Для подземных условий с низкой освещённостью применяем CLAHE-препроцессинг (повышение контрастности в 1.5–2 раза) и опционально тепловизоры LWIR. Наш собственный Mine Safety Dataset содержит 15 000+ аннотированных кадров с 8 классами: person, mining_helmet, headlamp, reflective_jacket, dust_mask, safety_boots, no_helmet, no_headlamp, mining_equipment.
import numpy as np
import cv2
from ultralytics import YOLO
from dataclasses import dataclass
import time
from typing import Optional
@dataclass
class MineWorkerStatus:
worker_id: int
bbox: list
has_helmet: bool
has_lamp: bool
has_reflective_vest: bool
has_mask: bool
in_danger_zone: bool
proximity_to_machinery: bool
compliance: bool
class MineMonitoringSystem:
"""
Система мониторинга безопасности в горнодобывающей отрасли.
Учёт специфики: низкое освещение, дым/пыль, ИК-камеры.
Mine Safety Dataset (custom):
- mining_helmet, lamp_headlamp, reflective_jacket
- mining_equipment, person, danger_zone_marker
"""
MINE_PPE_CLASSES = {
0: 'person',
1: 'mining_helmet', # шахтная каска с фонарём
2: 'headlamp', # фонарь отдельно
3: 'reflective_jacket', # световозвращающий жилет
4: 'dust_mask',
5: 'safety_boots',
6: 'no_helmet', # нарушение
7: 'no_headlamp', # нарушение
8: 'mining_equipment', # комбайн, погрузчик
}
CRITICAL_ZONES = ['roof_instability', 'gas_presence', 'machinery_working']
def __init__(self, model_path: str,
thermal_model_path: Optional[str] = None,
danger_zones: Optional[dict] = None,
device: str = 'cuda'):
self.model = YOLO(model_path)
self.thermal_model = YOLO(thermal_model_path) if thermal_model_path else None
self.danger_zones = danger_zones or {}
self.device = device
self._worker_tracks: dict[int, dict] = {}
def process_frame(self, frame: np.ndarray,
camera_id: str,
timestamp: float = None) -> dict:
if timestamp is None:
timestamp = time.time()
# Улучшение для тёмных/пыльных условий
enhanced = self._enhance_low_light(frame)
results = self.model.track(
enhanced, persist=True, conf=0.40,
verbose=False, tracker='bytetrack.yaml'
)
workers_status = []
violations = []
if results[0].boxes is None:
return self._empty_result(camera_id, timestamp)
persons = {}
ppe_items = {}
for box in results[0].boxes:
cls_id = int(box.cls.item())
cls_name = self.MINE_PPE_CLASSES.get(cls_id, 'unknown')
x1, y1, x2, y2 = map(int, box.xyxy[0])
cx, cy = (x1+x2)//2, (y1+y2)//2
tid = int(box.id.item()) if box.id is not None else -1
if cls_name == 'person':
persons[tid] = {
'bbox': [x1,y1,x2,y2], 'center': (cx,cy),
'has_helmet': False, 'has_lamp': False,
'has_vest': False, 'has_mask': False,
'violations': []
}
elif cls_name in ('no_helmet', 'no_headlamp'):
ppe_items[tid] = {
'type': cls_name, 'center': (cx, cy),
'violation': True
}
elif cls_name in ('mining_helmet', 'headlamp',
'reflective_jacket', 'dust_mask'):
ppe_items[tid] = {
'type': cls_name, 'center': (cx, cy),
'violation': False
}
# Ассоциация PPE с работниками
for item_tid, item_data in ppe_items.items():
nearest = self._find_nearest(item_data['center'], persons)
if nearest is None:
continue
p = persons[nearest]
if item_data['violation']:
p['violations'].append(item_data['type'])
else:
t = item_data['type']
if t == 'mining_helmet':
p['has_helmet'] = True
elif t == 'headlamp':
p['has_lamp'] = True
elif t == 'reflective_jacket':
p['has_vest'] = True
elif t == 'dust_mask':
p['has_mask'] = True
# Оценка каждого работника
for pid, pdata in persons.items():
in_danger = self._check_danger_zone(pdata['center'])
compliance = (pdata['has_helmet'] and
not pdata['violations'] and
not in_danger)
ws = MineWorkerStatus(
worker_id=pid, bbox=pdata['bbox'],
has_helmet=pdata['has_helmet'],
has_lamp=pdata['has_lamp'],
has_reflective_vest=pdata['has_vest'],
has_mask=pdata['has_mask'],
in_danger_zone=in_danger,
proximity_to_machinery=False,
compliance=compliance
)
workers_status.append(ws)
if not compliance or pdata['violations']:
violations.append({
'worker_id': pid,
'bbox': pdata['bbox'],
'issues': pdata['violations'] + (['danger_zone'] if in_danger else []),
'severity': 'critical' if in_danger else 'warning'
})
total = len(workers_status)
compliant = sum(1 for w in workers_status if w.compliance)
return {
'camera_id': camera_id,
'timestamp': timestamp,
'workers': [w.__dict__ for w in workers_status],
'violations': violations,
'compliance_rate_pct': round(compliant/max(total,1)*100, 1),
'critical_alert': any(v['severity']=='critical' for v in violations)
}
def _enhance_low_light(self, frame: np.ndarray) -> np.ndarray:
"""Улучшение видимости в тёмных условиях шахты"""
lab = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)
clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(8,8))
lab[:,:,0] = clahe.apply(lab[:,:,0])
enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
# Небольшое повышение яркости
enhanced = cv2.convertScaleAbs(enhanced, alpha=1.2, beta=20)
return enhanced
def _check_danger_zone(self, center: tuple) -> bool:
for zone_id, polygon in self.danger_zones.items():
poly = np.array(polygon, dtype=np.int32)
if cv2.pointPolygonTest(poly,
(float(center[0]), float(center[1])), False) >= 0:
return True
return False
def _find_nearest(self, center: tuple, persons: dict) -> Optional[int]:
min_dist = 150
nearest = None
cx, cy = center
for pid, p in persons.items():
px, py = p['center']
dist = np.sqrt((cx-px)**2 + (cy-py)**2)
if dist < min_dist:
min_dist = dist
nearest = pid
return nearest
def _empty_result(self, camera_id: str, timestamp: float) -> dict:
return {
'camera_id': camera_id, 'timestamp': timestamp,
'workers': [], 'violations': [],
'compliance_rate_pct': 100.0, 'critical_alert': False
}
Как мы собираем датасет и обучаем модель?
Сбор данных ведётся с камер на объекте в различных условиях: день, ночь, запылённость. Разметка выполняется в LabelStudio экспертами-безопасниками (8 классов). На этапе обучения применяем аугментации: изменение яркости, добавление шума, имитацию пыли (motion blur + Gaussian noise). Используем YOLOv8/9 с предобученными весами на COCO, дообучаем на нашем Mine Safety Dataset (15 000+ кадров). Обучаем на GPU A100 или RTX 4090 в течение 2–3 дней. Финальная модель проходит валидацию на отложенной выборке — target mAP50 0.85+.
Как мы тестируем и гарантируем точность?
Сравниваем детекцию с экспертным видеоанализом. Типичные метрики:
| Условие | Detection Rate | False Positive |
|---|---|---|
| Нормальное освещение (открытый карьер) | 93–97% | 2–4% |
| Тёмная шахта (CLAHE enhanced) | 82–89% | 6–12% |
| Пыль/дым (коэффициент снижения 15–30%) | 72–82% | 10–18% |
| Тепловизор (LWIR, любые условия) | 88–94% | 3–7% |
Тепловизор LWIR лучше RGB-камер в условиях пыли и дыма в 2–3 раза по точности детекции. Мы рекомендуем комбинацию RGB+LWIR для подземных участков. Стоимость проекта рассчитывается индивидуально в зависимости от числа камер и зон контроля. Экономия на штрафах и простоях составляет до 40% годовых.
Что входит в работу?
Мы берём на себя полный цикл: аудит текущей системы видеонаблюдения, сбор датасета (разметка с учётом специфики шахты), обучение модели, настройка трекера, интеграция с SCADA и MES, поставка сервера или инференс на существующем оборудовании.
- Документация: ETL-схема потоков, API-документация (REST/RTSP), инструкция по эксплуатации.
- Доступ к веб-дашборду с реальным compliance_rate_pct, тепловой картой опасных зон.
- Обучение операторов (2 дня, онлайн или на объекте).
- Техподдержка 3 месяца после запуска.
Детали интеграции со SCADA
Интеграция реализуется через OPC-UA или Modbus TCP. Система передаёт сигналы тревоги (danger_zone, violation) непосредственно на SCADA-сервер, что позволяет автоматически блокировать оборудование при нарушении СИЗ в опасной зоне. Время реакции — не более 500 мс от детекции до выдачи сигнала.Ориентировочные сроки внедрения
| Задача | Срок |
|---|---|
| PPE мониторинг для карьера (хорошее освещение) | 4–6 недель |
| Подземная шахта + ИК + SCADA интеграция | 10–16 недель |
| Enterprise mine safety платформа | 18–28 недель |
Точная оценка — после аудита. Мы выезжаем на объект или анализируем записи с камер. Оценим проект бесплатно — свяжитесь с нами и получите консультацию.
Гарантии и сопровождение
Более 5 лет в промышленном CV, 30+ внедрений, команда из senior AI/ML-инженеров. Наши системы работают на шахтах в Казахстане, России и ЮАР. Даём гарантию compliance rate не ниже 85% на этапе приёмки. По данным National Institute for Occupational Safety and Health, автоматизированный мониторинг СИЗ снижает травматизм на 35–50%. Свяжитесь с нами для бесплатного аудита вашего объекта. Закажите демо-доступ к системе.







