Реализация AI-3D-реконструкции объекта по фотографиям (NeRF) в мобильном приложении
NeRF (Neural Radiance Field) на мобильном устройстве — это не «нажал кнопку, получил 3D». Это многошаговый процесс с серьёзными вычислительными требованиями, который в 2024–2025 году наконец стал реалистичным для продакшн-приложений благодаря 3D Gaussian Splatting и новым моделям типа InstantNGP и Nerfacto.
NeRF vs Gaussian Splatting vs Photogrammetry
Три технологии решают одну задачу: 3D-объект из фотографий. Разница принципиальная:
| Метод | Скорость обучения | Время рендера | Качество | Редактируемость |
|---|---|---|---|---|
| Классический NeRF | Часы–дни | Медленный | Высокое | Плохая |
| InstantNGP/Nerfacto | 5–30 мин | Быстрый | Хорошее | Средняя |
| 3D Gaussian Splatting | 10–40 мин | Реальное время | Отличное | Хорошая |
| Photogrammetry (Metashape, COLMAP) | 30 мин–несколько часов | Мгновенный (mesh) | Зависит от фото | Отличная |
Для мобильных приложений в 2025 году: 3D Gaussian Splatting — лучший баланс скорости и качества. Для быстрого превью в AR — photogrammetry с last-generation COLMAP pipeline.
Архитектура: съёмка на устройстве, обработка в облаке
On-device reconstruction возможна только в ограниченных сценариях (Apple Object Capture API — только на Mac с Apple Silicon). Практичная архитектура для мобильного:
Мобильное устройство:
- Guided capture flow (20–60 фото по орбитальной схеме)
- Метаданные ARKit (camera poses) — упрощают COLMAP SfM
- Upload в облако
Backend (GPU-инстанс):
- COLMAP SfM (если нет ARKit poses) или pose estimation из метаданных
- 3D Gaussian Splatting обучение (nerfstudio + gsplat)
- Экспорт в .splat / .ply / .glb
- CDN → мобильное устройство
Мобильное устройство:
- Загрузка и рендер результата
- AR-просмотр через RealityKit (iOS) / SceneView (Android)
Guided capture на iOS с ARKit
Ключевой UX: пользователь должен обойти объект правильно, иначе реконструкция будет с артефактами.
class GuidedCaptureSession: NSObject {
private var arSession: ARSession
private var capturedFrames: [(UIImage, simd_float4x4)] = [] // image + camera transform
private let targetFrameCount = 40
private let minAngleBetweenFrames: Float = 8.0 // градусы
func shouldCaptureFrame(currentTransform: simd_float4x4) -> Bool {
guard let lastTransform = capturedFrames.last?.1 else { return true }
// Угловое расстояние от последнего захваченного кадра
let angularDistance = computeAngularDistance(currentTransform, lastTransform)
return angularDistance >= minAngleBetweenFrames
}
var captureProgress: Float {
// Оцениваем покрытие орбиты вокруг объекта
let coveredAngles = estimateOrbitCoverage(capturedFrames.map { $0.1 })
return min(coveredAngles / 360.0, 1.0)
}
}
AR-оверлей показывает «орбиту» вокруг объекта: зелёные дуги — уже снятые ракурсы, серые — нужно снять. Это снижает процент неудачных реконструкций из-за неполного покрытия.
Требования к качеству снимков
До отправки в облако — базовая валидация:
func validateCaptureSet(_ frames: [(UIImage, simd_float4x4)]) -> ValidationResult {
// Минимальное количество кадров
guard frames.count >= 20 else {
return .insufficientFrames(current: frames.count, required: 20)
}
// Покрытие углов (нужно хотя бы 270° из 360°)
let orbitCoverage = estimateOrbitCoverage(frames.map { $0.1 })
guard orbitCoverage >= 0.75 else {
return .insufficientCoverage(coverage: orbitCoverage)
}
// Средняя резкость кадров
let avgSharpness = frames.map { sharpnessScore($0.0) }.reduce(0, +) / Float(frames.count)
guard avgSharpness >= 60.0 else {
return .blurryImages
}
return .valid
}
Backend: 3D Gaussian Splatting обучение
# nerfstudio + gsplat pipeline
from nerfstudio.cameras.cameras import CameraType
from nerfstudio.pipelines.base_pipeline import Pipeline
def run_gaussian_splatting(
images_dir: Path,
camera_poses: list[np.ndarray] | None = None,
output_dir: Path = Path("output")
) -> Path:
"""
Если camera_poses переданы (из ARKit) — пропускаем COLMAP SfM.
Это сокращает время обработки с 15-20 мин до 3-5 мин.
"""
config = SplatfactoModelConfig(
num_downscales=2, # уменьшаем для скорости
use_scale_regularization=True,
max_gauss_ratio=10.0,
)
trainer = Trainer(config, output_dir=output_dir)
trainer.train() # ~10-40 мин на GPU (A100: 10 мин, T4: 25 мин)
# Экспорт в web-friendly формат
export_gaussian_splat(output_dir / "splat.ply")
export_glb(output_dir / "model.glb") # для AR Quick Look / SceneViewer
return output_dir
Отображение результата в AR
// iOS: RealityKit Quick Look для .usdz / .glb
import RealityKit
import ARKit
class ModelViewerViewController: UIViewController {
func presentARModel(modelURL: URL) {
let arView = ARView(frame: view.bounds, cameraMode: .ar)
let anchor = AnchorEntity(plane: .horizontal)
ModelEntity.loadModelAsync(contentsOf: modelURL)
.sink(
receiveCompletion: { _ in },
receiveValue: { [weak self] entity in
entity.generateCollisionShapes(recursive: true)
anchor.addChild(entity)
arView.scene.anchors.append(anchor)
// Pinch to scale, pan to move
arView.installGestures([.scale, .translation, .rotation], for: entity)
}
)
.store(in: &cancellables)
}
}
Ориентиры по срокам
MVP с guided capture, загрузкой в облако, Nerfacto/Gaussian Splatting обучением и базовым AR-просмотром результата — 3–4 недели. Полная реализация с использованием ARKit camera poses (без COLMAP), прогресс-трекингом обработки, экспортом в несколько форматов (.glb, .usdz, .obj), шаринг 3D-модели и поддержкой iOS + Android — 2–3 месяца.







