הטמעת זיהוי חריגות וידאו מבוסס בינה מלאכותית באפליקציות מובייל
לעתים קרובות אנו מקבלים בקשה כזו: "אני רוצה לזהות נפילות, חדירות או התנהגות חריגה בוידאו, אבל אני לא יודע מאיפה להתחיל." האתגר הוא שחריגות הן אירועים נדירים ללא תוויות ברורות. אי אפשר למנות מראש את כל הווריאציות של התנהגות "רעה". לכן אנו משתמשים בגישה דו-שכבתית: כללים דטרמיניסטיים מהירים לתרחישים ידועים ובינה מלאכותית לא מונחית לחריגות עדינות. זה מאזן בין מהירות לכיסוי: הכללים פועלים במילישניות, בעוד הבינה המלאכותית מתאימה את עצמה לנתונים שלך.
בפרויקט אחד, לקוח רצה לנטר חדירות לחדר שרתים וגם לסמן התנהגות חשודה של עובדים, כמו מעברים תכופים בצורה חריגה מחוץ לשעות העבודה. כללים דטרמיניסטיים תפסו בקלות הפרות אזורים, והאוטואנקודר חשף מסלולים לא טיפוסיים שלא הבחינו בהם קודם. התוצאה: דיוק זיהוי של 95% עם אפס תוצאות חיוביות שגויות במצבים נורמליים.
איך להבחין בין חריגות מרחביות להתנהגותיות?
לפני כתיבת קוד, אנו מגדירים במדויק דרישות עם הלקוח. סוגי חריגות:
- מרחבית – אובייקט באזור שבו הוא לא אמור להיות (אדם בחדר שרתים)
- התנהגותית – אובייקט נורמלי מתנהג בצורה חריגה (ריצה במקום שבו אחרים הולכים)
- זמנית – אירוע מתרחש בזמן לא נכון (תנועה בלילה)
- טכנית – תקלות בציוד (עשן, רטט)
כל סוג דורש ארכיטקטורה שונה. לחריגות מרחביות, כללים דטרמיניסטיים מספיקים; להתנהגותיות, יש צורך באוטואנקודר.
איך אנו בונים את המערכת הדו-שכבתית
אנו מפצלים את הזיהוי לשני שלבים. ראשית, כללים מהירים המבוססים על ראייה ממוחשבת (גלאי אנשים ואזורים). שנית, מודל בינה מלאכותית שפועל רק כשאין הפרות כללים, וחוסך במשאבים. גישה זו יעילה פי 3 במעבד מאשר שימוש במודל כבד אחד לכל דבר.
שכבה 1: כללים דטרמיניסטיים
הכללים מוגדרים בקונפיגורציה: קואורדינטות אזורים אסורים, לוחות זמנים, סוגי אובייקטים. הם פועלים ללא אימון, באופן מיידי וצפוי.
class AnomalyRulesEngine {
struct RestrictedZone {
let polygon: [CGPoint] // нормализованные координаты
let schedule: WorkSchedule? // nil = всегда ограничена
let name: String
}
private let restrictedZones: [RestrictedZone]
private let personDetector: VNCoreMLModel // лёгкий YOLOv8n
func check(frame: CVPixelBuffer, timestamp: Date) -> [RuleViolation] {
let persons = detectPersons(frame)
var violations: [RuleViolation] = []
for person in persons {
let personCenter = person.boundingBox.center
for zone in restrictedZones {
if zone.polygon.contains(personCenter) {
if let schedule = zone.schedule, !schedule.isActive(at: timestamp) {
violations.append(RuleViolation(
type: .unauthorizedZoneAccess,
zone: zone.name,
timestamp: timestamp
))
} else if zone.schedule == nil {
violations.append(RuleViolation(type: .restrictedZone, zone: zone.name))
}
}
}
}
return violations
}
} שכבה 2: אוטואנקודר לחריגות לא ברורות
לחריגות התנהגותיות, אנו משתמשים באוטואנקודר: מאומן על התנהגות נורמלית, חריגה = שגיאת שחזור גבוהה. האוטואנקודר קל פי 10 מגלאי YOLO (5 MB לעומת 50 MB), קריטי למכשירים ניידים.
# Обучение autoencoder на нормальных видео-фрагментах
import torch
import torch.nn as nn
class VideoAnomalyAutoencoder(nn.Module):
"""
Входной тензор: [batch, frames, height, width, channels]
Обучается только на НОРМАЛЬНЫХ сценах
Аномалия: reconstruction_error > threshold
"""
def __init__(self, input_shape=(16, 64, 64, 3)):
super().__init__()
self.encoder = nn.Sequential(
nn.Conv3d(3, 32, kernel_size=(3,3,3), padding=1),
nn.ReLU(),
nn.MaxPool3d((1,2,2)),
nn.Conv3d(32, 64, kernel_size=(3,3,3), padding=1),
nn.ReLU(),
nn.MaxPool3d((2,2,2)),
)
self.decoder = nn.Sequential(
nn.ConvTranspose3d(64, 32, kernel_size=(3,3,3), stride=(2,2,2), padding=1, output_padding=1),
nn.ReLU(),
nn.ConvTranspose3d(32, 3, kernel_size=(3,3,3), stride=(1,2,2), padding=1, output_padding=(0,1,1)),
nn.Sigmoid()
)
def forward(self, x):
z = self.encoder(x)
return self.decoder(z)
def anomaly_score(self, x):
reconstructed = self(x)
return ((x - reconstructed) ** 2).mean(dim=[1,2,3,4])סף החריגה מוגדר באחוזון ה-99 של שגיאת השחזור על הנתונים הנורמליים. במובייל, אוטואנקודר זה מומר ל-CoreML או TFLite.
הסקה במובייל: עיבוד חלון נע
עיבוד כל חלון של 16 פריימים לוקח 30-50 אלפיות השנייה באייפון 12, ומאפשר 20-30 fps.
// iOS: анализ видеопотока скользящим окном из 16 кадров
class SlidingWindowAnalyzer {
private var frameBuffer: CircularBuffer<CVPixelBuffer> = CircularBuffer(capacity: 16)
private var frameCounter = 0
private let stepSize = 8 // новое окно каждые 8 кадров (50% overlap)
func addFrame(_ frame: CVPixelBuffer) async -> AnomalyScore? {
frameBuffer.append(frame)
frameCounter += 1
guard frameCounter % stepSize == 0, frameBuffer.count == 16 else { return nil }
return try? await computeAnomalyScore(frames: Array(frameBuffer))
}
private func computeAnomalyScore(frames: [CVPixelBuffer]) async throws -> AnomalyScore {
let tensor = prepareTensor(frames) // [1, 16, 64, 64, 3]
let output = try autoencoderModel.prediction(input: tensor)
let score = output.anomalyScore.floatValue
return AnomalyScore(
value: score,
isAnomaly: score > anomalyThreshold,
frameWindow: frames
)
}
} התראות ותגובה
אנו מיישמים מערכת רב-רמות: אזהרות והתראות קריטיות עם קירור כדי למנוע ספאם. התראות קריטיות נשלחות דרך webhook למערכת אבטחה חיצונית.
// Android: многоуровневая система алертов
sealed class AnomalyAlert {
data class Warning(val message: String, val score: Float) : AnomalyAlert()
data class Critical(val message: String, val violations: List<RuleViolation>) : AnomalyAlert()
}
class AlertManager(private val notificationManager: NotificationManager) {
private val cooldownMap = mutableMapOf<String, Long>()
private val alertCooldownMs = 30_000L // не спамить: не чаще раза в 30 сек
fun emit(alert: AnomalyAlert, alertKey: String) {
val lastAlertTime = cooldownMap[alertKey] ?: 0L
if (System.currentTimeMillis() - lastAlertTime < alertCooldownMs) return
cooldownMap[alertKey] = System.currentTimeMillis()
when (alert) {
is AnomalyAlert.Warning -> showLocalNotification(alert.message, priority = LOW)
is AnomalyAlert.Critical -> {
showLocalNotification(alert.message, priority = HIGH)
sendWebhook(alert) // интеграция с внешней системой безопасности
}
}
}
} השוואת גישות
| תכונה | כללים דטרמיניסטיים | אוטואנקודר AI |
|---|---|---|
| סוג חריגה | מרחבית, זמנית | התנהגותית, טכנית |
| אימון | אזורים/לוח זמנים מוגדרים על ידי מומחה | לא מונחה על נתונים נורמליים |
| דיוק | 100% לכללים מוגדרים | תלוי נתונים (ROC-AUC ~0.9) |
| גודל מודל | 0 (גלאי פנים קל) | 5-15 MB |
| זמן השהיה ב-iOS | <5 אלפיות השנייה | 30-50 אלפיות השנייה לחלון |
כללים דטרמיניסטיים מהירים פי 10 מבינה מלאכותית, אבל מפספסים סוגי חריגות חדשים. האוטואנקודר מוצא מה שלא הוגדר מראש — מושלם כשכבה שנייה.
מה העבודה שלנו כוללת
הצוות שלנו (8+ שנים ב-CV למובייל, 15+ פרויקטים) מציע:
- איסוף ותיוג נתונים נורמליים לאימון
- עיצוב כללים דטרמיניסטיים לתרחיש שלך
- אימון והמרת אוטואנקודר ל-CoreML / TFLite
- אינטגרציה עם iOS (Swift 5.9+, SwiftUI) ואנדרואיד (Kotlin, Jetpack Compose)
- מערכת התראות רב-רמות עם אינטגרציית webhook
- תיעוד והדרכת מפעילים
- תמיכה לאחר ההשקה
נעריך את הפרויקט שלך תוך יומיים. צור קשר לייעוץ — נציג הדגמה על נתונים אמיתיים. בקש השקה פיילוט וראה את היעילות.
הערכות לוחות זמנים
| שלב | משך |
|---|---|
| זיהוי הפרות אזורים (ללא AI) | 1-2 שבועות |
| מערכת מלאה עם אוטואנקודר, חלון נע, התראות | 2-4 שבועות |
| איסוף נתונים נורמליים ואימון מודל | +1-2 שבועות |
| אינטגרציה עם מערכת אבטחה חיצונית | +1 שבוע |
העלות מחושבת באופן אישי. אנו מבטיחים איכות קוד ותיעוד מלא. אנו משתמשים בCoreML ובTFLite — כלים מוכחים להסקה במובייל.







