Реструктуризация проекта и генератор синтетических датасетов эхолота.
Перенесены backend/frontend/desktop/engine, добавлены вкладки конструктора сцен и генератора датасета с параметрами лучей и длины сетки рельефа, обновлены API и Docker-сборка. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,457 @@
|
||||
.pragma library
|
||||
|
||||
function inferParamType(valueText) {
|
||||
var v = (valueText === undefined || valueText === null) ? "" : String(valueText).trim()
|
||||
if (v === "true" || v === "false")
|
||||
return "bool"
|
||||
if (/^-?\d+$/.test(v))
|
||||
return "int"
|
||||
if (/^-?(?:\d+\.\d*|\d*\.\d+)$/.test(v))
|
||||
return "float"
|
||||
return "string"
|
||||
}
|
||||
|
||||
function parseDefaults(defaultsText) {
|
||||
var out = []
|
||||
if (!defaultsText)
|
||||
return out
|
||||
var chunks = String(defaultsText).split(",")
|
||||
for (var i = 0; i < chunks.length; ++i) {
|
||||
var chunk = chunks[i].trim()
|
||||
if (!chunk)
|
||||
continue
|
||||
var eq = chunk.indexOf("=")
|
||||
var key = eq >= 0 ? chunk.slice(0, eq).trim() : chunk
|
||||
var value = eq >= 0 ? chunk.slice(eq + 1).trim() : ""
|
||||
out.push({ key: key, value: value, kind: inferParamType(value) })
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function serializeParams(items) {
|
||||
var parts = []
|
||||
for (var i = 0; i < items.length; ++i) {
|
||||
var p = items[i]
|
||||
parts.push(p.key + "=" + p.value)
|
||||
}
|
||||
return parts.join(",")
|
||||
}
|
||||
|
||||
function paramDescription(key) {
|
||||
if (key === "minCluster")
|
||||
return "Минимальный размер кластера в точках."
|
||||
if (key === "targetPoints")
|
||||
return "Целевое количество точек после прореживания."
|
||||
if (key === "leaf")
|
||||
return "Размер вокселя для Voxel Grid."
|
||||
if (key === "meanK")
|
||||
return "Число соседей для статистической оценки."
|
||||
if (key === "stddev")
|
||||
return "Порог отклонения для удаления выбросов."
|
||||
if (key === "radius")
|
||||
return "Радиус поиска соседей."
|
||||
if (key === "minNeighbors")
|
||||
return "Минимум соседей, чтобы точка считалась валидной."
|
||||
if (key === "threshold")
|
||||
return "Порог отклонения точки от геометрической модели."
|
||||
if (key === "shadowThreshold")
|
||||
return "Порог для удаления теневых точек по нормалям."
|
||||
if (key === "resolution")
|
||||
return "Размер ячейки 2D-сетки для фильтра GridMinimum."
|
||||
if (key === "sample")
|
||||
return "Количество точек, которое нужно оставить после выборки."
|
||||
if (key === "axis")
|
||||
return "Ось фильтрации: x, y или z."
|
||||
if (key === "min" || key === "max")
|
||||
return "Граница диапазона для фильтра PassThrough."
|
||||
if (key === "minX" || key === "minY" || key === "minZ" || key === "maxX" || key === "maxY" || key === "maxZ")
|
||||
return "Границы CropBox/CropHull по соответствующим осям."
|
||||
if (key === "near" || key === "far")
|
||||
return "Ближняя/дальняя граница фрустума."
|
||||
if (key === "hfov" || key === "vfov")
|
||||
return "Горизонтальный/вертикальный угол обзора (в градусах)."
|
||||
if (key === "a" || key === "b" || key === "c" || key === "d")
|
||||
return "Коэффициенты плоскости ax+by+cz+d=0."
|
||||
if (key === "keepPositive")
|
||||
return "Оставлять ли точки на положительной стороне плоскости."
|
||||
if (key === "zMin" || key === "zMax")
|
||||
return "Допустимый диапазон координаты Z для conditional-фильтра."
|
||||
if (key === "nth")
|
||||
return "Оставлять каждую N-ю точку."
|
||||
if (key === "radiusMax")
|
||||
return "Максимальный радиус точки от начала координат."
|
||||
if (key === "sigmaS" || key === "sigmaR")
|
||||
return "Параметры bilateral-фильтра (пространство/интенсивность)."
|
||||
if (key === "sigma" || key === "kernel")
|
||||
return "Параметры гауссова ядра свертки."
|
||||
if (key === "iterations")
|
||||
return "Число итераций уточнения."
|
||||
if (key === "minHits")
|
||||
return "Минимальная заполненность вокселя для прохождения фильтра."
|
||||
if (key === "neighborRadiusScale")
|
||||
return "Масштаб радиуса поиска соседей для fallback-реконструкции."
|
||||
if (key === "runEveryNthFrame")
|
||||
return "Запуск реконструкции на каждом N-м кадре."
|
||||
if (key === "searchRadius")
|
||||
return "Радиус поиска соседей для greedy triangulation."
|
||||
if (key === "mu")
|
||||
return "Коэффициент плотности соседей для greedy triangulation."
|
||||
if (key === "maxNearest")
|
||||
return "Максимум соседей для greedy triangulation."
|
||||
if (key === "maxSurfaceAngle")
|
||||
return "Максимальный угол поверхности в радианах."
|
||||
if (key === "poissonDepth")
|
||||
return "Глубина октодерева для Poisson реконструкции."
|
||||
if (key === "samplesPerNode")
|
||||
return "Число выборок на узел для сглаживания Poisson."
|
||||
return "Параметр этапа обработки."
|
||||
}
|
||||
|
||||
function reconstructionTitle(id) {
|
||||
if (id === "surface_fallback")
|
||||
return "Fallback Surface"
|
||||
if (id === "pcl_greedy_triangulation")
|
||||
return "PCL Greedy Triangulation"
|
||||
if (id === "pcl_poisson_reconstruction")
|
||||
return "PCL Poisson Reconstruction"
|
||||
return id
|
||||
}
|
||||
|
||||
function phaseModel() {
|
||||
return [
|
||||
{
|
||||
id: "crop",
|
||||
title: "Обрезка",
|
||||
hint: "Ограничение области интереса и удаление лишних фрагментов.",
|
||||
accent: "#88d1ff",
|
||||
filterBg: "#263e55",
|
||||
filterBorder: "#4b7598"
|
||||
},
|
||||
{
|
||||
id: "nan_preclean",
|
||||
title: "NaN (предочистка)",
|
||||
hint: "Удаление NaN сразу после загрузки/обрезки, иначе статистические фильтры работают нестабильно.",
|
||||
accent: "#8fe8ff",
|
||||
filterBg: "#1f4450",
|
||||
filterBorder: "#3f8394"
|
||||
},
|
||||
{
|
||||
id: "conditions_indexes",
|
||||
title: "Условия/Индексы",
|
||||
hint: "Отбор точек по полям, диапазонам и индексным маскам.",
|
||||
accent: "#9fd7ff",
|
||||
filterBg: "#24405a",
|
||||
filterBorder: "#4f7aa1"
|
||||
},
|
||||
{
|
||||
id: "noise",
|
||||
title: "Шум",
|
||||
hint: "Удаление выбросов и нестабильных точек перед геометрией.",
|
||||
accent: "#a4f4b9",
|
||||
filterBg: "#244534",
|
||||
filterBorder: "#4b8f68"
|
||||
},
|
||||
{
|
||||
id: "morphology",
|
||||
title: "Морфология",
|
||||
hint: "Геометрические операции локальной структуры облака.",
|
||||
accent: "#9cf5d1",
|
||||
filterBg: "#1f4a3e",
|
||||
filterBorder: "#4b8f7d"
|
||||
},
|
||||
{
|
||||
id: "downsample",
|
||||
title: "Прореживание",
|
||||
hint: "Снижение плотности облака для скорости и устойчивости.",
|
||||
accent: "#ffcb8a",
|
||||
filterBg: "#4a3724",
|
||||
filterBorder: "#8e6f47"
|
||||
},
|
||||
{
|
||||
id: "smoothing",
|
||||
title: "Сглаживание",
|
||||
hint: "Снижение локального шума перед расчетом нормалей и реконструкцией.",
|
||||
accent: "#ffd892",
|
||||
filterBg: "#4e3a22",
|
||||
filterBorder: "#917349"
|
||||
},
|
||||
{
|
||||
id: "normals",
|
||||
title: "Нормали",
|
||||
hint: "Подготовка нормалей для продвинутой реконструкции (этап зарезервирован).",
|
||||
accent: "#d2b7ff",
|
||||
filterBg: "#3e3155",
|
||||
filterBorder: "#6f5a95"
|
||||
},
|
||||
{
|
||||
id: "reconstruction",
|
||||
title: "Реконструкция",
|
||||
hint: "Построение поверхности по подготовленному облаку точек.",
|
||||
accent: "#ff9dc4",
|
||||
filterBg: "#4b2f40",
|
||||
filterBorder: "#8d5a75"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function filterDefinitions() {
|
||||
return [
|
||||
{
|
||||
title: "Крупнейший кластер",
|
||||
idValue: "keep_largest_cluster",
|
||||
phaseId: "crop",
|
||||
hint: "Оставляет основной объект и отбрасывает изолированные фрагменты."
|
||||
},
|
||||
{
|
||||
title: "Remove NaN Points",
|
||||
idValue: "pcl_remove_nan",
|
||||
phaseId: "nan_preclean",
|
||||
family: "preprocess",
|
||||
hint: "Удаляет NaN/Inf после загрузки и обрезки, до статистических фильтров."
|
||||
},
|
||||
{
|
||||
title: "Remove NaN Normals",
|
||||
idValue: "pcl_remove_nan_normals",
|
||||
phaseId: "nan_preclean",
|
||||
family: "preprocess",
|
||||
hint: "Удаляет невалидные нормали (в текущем формате — невалидную геометрию)."
|
||||
},
|
||||
{
|
||||
title: "PassThrough",
|
||||
idValue: "pcl_pass_through",
|
||||
phaseId: "crop",
|
||||
hint: "Фильтрует точки по диапазону выбранной оси."
|
||||
},
|
||||
{
|
||||
title: "CropBox",
|
||||
idValue: "pcl_crop_box",
|
||||
phaseId: "crop",
|
||||
hint: "Ограничивает облако заданным 3D-параллелепипедом."
|
||||
},
|
||||
{
|
||||
title: "CropHull",
|
||||
idValue: "pcl_crop_hull",
|
||||
phaseId: "crop",
|
||||
hint: "Обрезка по области интереса (в текущей версии через box-границы)."
|
||||
},
|
||||
{
|
||||
title: "Frustum Culling",
|
||||
idValue: "pcl_frustum_culling",
|
||||
phaseId: "crop",
|
||||
hint: "Оставляет точки в пирамиде видимости камеры."
|
||||
},
|
||||
{
|
||||
title: "PlaneClipper3D",
|
||||
idValue: "pcl_plane_clipper_3d",
|
||||
phaseId: "crop",
|
||||
hint: "Отсекает точки по уравнению плоскости."
|
||||
},
|
||||
{
|
||||
title: "Conditional Removal",
|
||||
idValue: "pcl_conditional_removal",
|
||||
phaseId: "conditions_indexes",
|
||||
hint: "Удаляет точки по логическому условию (диапазон Z)."
|
||||
},
|
||||
{
|
||||
title: "Extract Indices",
|
||||
idValue: "pcl_extract_indices",
|
||||
phaseId: "conditions_indexes",
|
||||
hint: "Извлекает точки по индексной маске (каждая N-я)."
|
||||
},
|
||||
{
|
||||
title: "Functor Filter",
|
||||
idValue: "pcl_functor_filter",
|
||||
phaseId: "conditions_indexes",
|
||||
hint: "Пользовательский предикат (радиус + проверка валидности)."
|
||||
},
|
||||
{
|
||||
title: "ProjectInliers",
|
||||
idValue: "pcl_project_inliers",
|
||||
phaseId: "normals",
|
||||
hint: "Проецирует точки на геометрическую модель (плоскость)."
|
||||
},
|
||||
{
|
||||
title: "Normal Refinement",
|
||||
idValue: "pcl_normal_refinement",
|
||||
phaseId: "normals",
|
||||
hint: "Уточняет локальную геометрию по соседям."
|
||||
},
|
||||
{
|
||||
title: "Статистическая фильтрация",
|
||||
idValue: "pcl_statistical_outlier",
|
||||
phaseId: "noise",
|
||||
hint: "Удаляет выбросы на основе распределения расстояний до соседей."
|
||||
},
|
||||
{
|
||||
title: "Радиусная фильтрация",
|
||||
idValue: "pcl_radius_outlier",
|
||||
phaseId: "noise",
|
||||
hint: "Удаляет точки с недостаточным числом соседей в заданном радиусе."
|
||||
},
|
||||
{
|
||||
title: "Model Outlier Removal",
|
||||
idValue: "pcl_model_outlier",
|
||||
phaseId: "noise",
|
||||
hint: "Удаляет точки, отклоняющиеся от геометрической модели."
|
||||
},
|
||||
{
|
||||
title: "Shadow Points Removal",
|
||||
idValue: "pcl_shadow_points",
|
||||
phaseId: "noise",
|
||||
hint: "Удаляет теневые точки на основе нормалей поверхности."
|
||||
},
|
||||
{
|
||||
title: "Approximate Voxel Grid",
|
||||
idValue: "pcl_approximate_voxel_grid",
|
||||
phaseId: "downsample",
|
||||
hint: "Ускоренное воксельное прореживание для больших облаков."
|
||||
},
|
||||
{
|
||||
title: "Voxel Grid Label",
|
||||
idValue: "pcl_voxel_grid_label",
|
||||
phaseId: "downsample",
|
||||
hint: "Воксельное прореживание с поддержкой меток."
|
||||
},
|
||||
{
|
||||
title: "Voxel Grid Covariance",
|
||||
idValue: "pcl_voxel_grid_covariance",
|
||||
phaseId: "downsample",
|
||||
hint: "Воксельная сетка с ковариациями (для NDT-пайплайнов)."
|
||||
},
|
||||
{
|
||||
title: "Grid Minimum",
|
||||
idValue: "pcl_grid_minimum",
|
||||
phaseId: "downsample",
|
||||
hint: "Оставляет точку с минимальным Z в каждой ячейке."
|
||||
},
|
||||
{
|
||||
title: "Farthest Point Sampling",
|
||||
idValue: "pcl_farthest_point_sampling",
|
||||
phaseId: "downsample",
|
||||
hint: "Выбирает наиболее удаленные друг от друга точки."
|
||||
},
|
||||
{
|
||||
title: "Normal Space Sampling",
|
||||
idValue: "pcl_normal_space_sampling",
|
||||
phaseId: "downsample",
|
||||
hint: "Равномерная выборка в пространстве нормалей."
|
||||
},
|
||||
{
|
||||
title: "Sampling Surface Normal",
|
||||
idValue: "pcl_sampling_surface_normal",
|
||||
phaseId: "downsample",
|
||||
hint: "Выборка точек на основе нормалей поверхности."
|
||||
},
|
||||
{
|
||||
title: "Bilateral Filter",
|
||||
idValue: "pcl_bilateral_filter",
|
||||
phaseId: "smoothing",
|
||||
hint: "Двустороннее сглаживание с сохранением границ."
|
||||
},
|
||||
{
|
||||
title: "Fast Bilateral Filter",
|
||||
idValue: "pcl_fast_bilateral_filter",
|
||||
phaseId: "smoothing",
|
||||
hint: "Быстрое двустороннее сглаживание."
|
||||
},
|
||||
{
|
||||
title: "Fast Bilateral Filter OMP",
|
||||
idValue: "pcl_fast_bilateral_filter_omp",
|
||||
phaseId: "smoothing",
|
||||
hint: "Параллельная версия bilateral-фильтра."
|
||||
},
|
||||
{
|
||||
title: "Convolution",
|
||||
idValue: "pcl_convolution",
|
||||
phaseId: "smoothing",
|
||||
hint: "Свертка облака точек с ядром."
|
||||
},
|
||||
{
|
||||
title: "Gaussian Kernel",
|
||||
idValue: "pcl_gaussian_kernel",
|
||||
phaseId: "smoothing",
|
||||
hint: "Гауссово ядро свертки."
|
||||
},
|
||||
{
|
||||
title: "Gaussian Kernel RGB",
|
||||
idValue: "pcl_gaussian_kernel_rgb",
|
||||
phaseId: "smoothing",
|
||||
hint: "Гауссово ядро с RGB-ориентированной семантикой."
|
||||
},
|
||||
{
|
||||
title: "VoxelGrid Occlusion Estimation",
|
||||
idValue: "pcl_voxel_grid_occlusion",
|
||||
phaseId: "morphology",
|
||||
hint: "Оценка окклюзии через заполненность вокселей."
|
||||
},
|
||||
{
|
||||
title: "Fallback Surface",
|
||||
idValue: "surface_fallback",
|
||||
phaseId: "reconstruction",
|
||||
family: "reconstruction",
|
||||
hint: "Базовая реконструкция поверхности по облаку точек."
|
||||
},
|
||||
{
|
||||
title: "PCL Greedy Triangulation",
|
||||
idValue: "pcl_greedy_triangulation",
|
||||
phaseId: "reconstruction",
|
||||
family: "reconstruction",
|
||||
hint: "Жадная триангуляция с параметрами радиуса и углов."
|
||||
},
|
||||
{
|
||||
title: "PCL Poisson Reconstruction",
|
||||
idValue: "pcl_poisson_reconstruction",
|
||||
phaseId: "reconstruction",
|
||||
family: "reconstruction",
|
||||
hint: "Реконструкция поверхности методом Poisson из libpcl_surface."
|
||||
},
|
||||
{
|
||||
title: "Прореживание плотности",
|
||||
idValue: "downsample_dense",
|
||||
phaseId: "downsample",
|
||||
hint: "Снижает число точек для ускорения пайплайна на плотных облаках."
|
||||
},
|
||||
{
|
||||
title: "PCL Voxel Grid",
|
||||
idValue: "pcl_voxel_grid",
|
||||
phaseId: "downsample",
|
||||
hint: "Равномерно прореживает облако с помощью воксельной сетки."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function filterPaletteModel() {
|
||||
return filterDefinitions()
|
||||
}
|
||||
|
||||
function filterPaletteGroupedModel() {
|
||||
var phases = phaseModel()
|
||||
var filters = filterDefinitions()
|
||||
var grouped = []
|
||||
for (var p = 0; p < phases.length; ++p) {
|
||||
var phase = phases[p]
|
||||
var items = []
|
||||
for (var i = 0; i < filters.length; ++i) {
|
||||
if (filters[i].phaseId === phase.id)
|
||||
items.push(filters[i])
|
||||
}
|
||||
grouped.push({
|
||||
phaseId: phase.id,
|
||||
phaseTitle: phase.title,
|
||||
phaseHint: phase.hint,
|
||||
phaseAccent: phase.accent,
|
||||
phaseFilterBg: phase.filterBg,
|
||||
phaseFilterBorder: phase.filterBorder,
|
||||
items: items
|
||||
})
|
||||
}
|
||||
return grouped
|
||||
}
|
||||
|
||||
function reconstructionPaletteModel() {
|
||||
return [
|
||||
{ title: "Fallback Surface", idValue: "surface_fallback" },
|
||||
{ title: "PCL Greedy Triangulation", idValue: "pcl_greedy_triangulation" },
|
||||
{ title: "PCL Poisson Reconstruction", idValue: "pcl_poisson_reconstruction" }
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user