Реализация AI-распознавания автомобилей (марка, модель) в мобильном приложении
Распознавание марки и модели автомобиля по фотографии — задача с хорошо изученным решением. Модели, обученные на Stanford Cars Dataset (196 классов) или CompCars, дают точность 90%+ на чистых боковых снимках. Основная сложность в продакшн — ракурсы, частичная видимость (только перед или только задняя часть), ночные условия и автомобили из нишевых рынков.
Готовые API и их ограничения
| Сервис | Кол-во моделей | Особенности |
|---|---|---|
| CarAPI / CarQuery | 10 000+ | Хорош для классификации, слабее на старых/редких авто |
| AutoVIN API | Широкая база | VIN-декодирование в связке с фото |
| Imagga | Кастомные теги | Требует дообучения под automotive |
| Google Cloud AutoML Vision | Кастомное | Нужна своя разметка |
Для большинства проектов: кастомная CoreML/TFLite модель на базе EfficientNetV2, дообученная на объединённом датасете (Stanford Cars + VMMRdb). Размер модели — 25–40 МБ, точность Top-1 на популярных моделях — 88–93%.
Реализация на iOS с CoreML
class CarRecognitionService {
private lazy var model: VNCoreMLModel = {
let config = MLModelConfiguration()
config.computeUnits = .cpuAndNeuralEngine
let mlModel = try! CarClassifierV3(configuration: config).model
return try! VNCoreMLModel(for: mlModel)
}()
func recognize(image: UIImage) async throws -> [CarPrediction] {
guard let cgImage = image.cgImage else { throw CarError.invalidImage }
return try await withCheckedThrowingContinuation { continuation in
let request = VNCoreMLRequest(model: model) { request, error in
if let error = error {
continuation.resume(throwing: error)
return
}
let results = (request.results as? [VNClassificationObservation]) ?? []
let predictions = results
.filter { $0.confidence > 0.05 }
.prefix(5)
.map { CarPrediction(
makeModel: $0.identifier, // "Toyota Camry 2022"
confidence: $0.confidence
)}
continuation.resume(returning: Array(predictions))
}
// Нормализация ориентации изображения критична — иначе точность падает
request.imageCropAndScaleOption = .centerCrop
let handler = VNImageRequestHandler(cgImage: cgImage,
orientation: image.cgImageOrientation)
try? handler.perform([request])
}
}
}
Параметр imageCropAndScaleOption = .centerCrop — не очевидная деталь. По умолчанию Vision framework масштабирует изображение иначе, чем ожидала модель при обучении, что даёт 5–8% потери точности.
Многоракурсная классификация
Для высокоточных задач (страховые приложения, автодилеры) один снимок недостаточен. Запрашиваем три ракурса:
enum CarPhotoAngle: CaseIterable {
case frontThreeQuarter // 3/4 спереди — оптимален для марки/модели
case rear // для задней части (доп. верификация)
case side // боковой — для кузова и поколения
var instruction: String {
switch self {
case .frontThreeQuarter: return "Сфотографируйте автомобиль спереди-сбоку (45°)"
case .rear: return "Сфотографируйте сзади"
case .side: return "Сфотографируйте строго сбоку"
}
}
}
// Агрегация результатов по трём снимкам — weighted voting
func aggregatePredictions(_ predictions: [[CarPrediction]]) -> CarPrediction {
let weights: [Double] = [0.5, 0.3, 0.2] // frontThreeQuarter важнее
// ... weighted voting по makeModel
}
Определение года выпуска и поколения
Год выпуска визуально — сложнее марки/модели: рестайлинги меняют внешность незначительно. Два подхода:
- Классификатор поколений (отдельная голова в multi-task модели)
- Hybrid: VIN через OCR (если номер виден) + визуальная классификация поколения
VIN-подход точнее: если OCR считал VIN с номерного знака или рамки, все данные (марка, модель, год, комплектация) декодируются без AI через NHTSA API или платные VIN-декодеры.
Ориентиры по срокам
Интеграция готовой CoreML модели с UI отображения результатов — 3–5 дней. Полная система с многоракурсным захватом, гибридным VIN+Visual подходом, базой характеристик автомобилей и iOS + Android — 1–2 недели.







