Я хочу использовать Церера рассчитать координаты треугольника.
Для задачи мне нужно решить для координат сетки в сетке. Каждый треугольник имеет свои вершины, но доступна структура, такая как треугольники (3 вершины) и ребра (4 вершины).
Пример данных (псевдокод):
triangles = [[v1, v2, v3], [v4, v5, v6]]
inner_edges = [[[v1, v4], [v2, v5]]]
Края [v1, v2]
а также [v4, v5]
изначально одинаковы, которые могут измениться при решении.
Теперь у меня есть две функции стоимости, одна на треугольниках и одна на внутренних краях
f([v1, v2, v3]) = res_t1
g([v1, v4, v2, v5]) = res_2
Есть две простые блочные структуры
Первый решает для вектора x
со всеми координатами (2*|V|
поскольку каждая вершина имеет две координаты), так как блоки зависят от всех вершин. Во втором случае блоки треугольников должны зависеть только от трех вершин, а блоки ребер — от четырех вершин.
Теперь я хочу использовать второй, так как ожидаю лучшей производительности и лучшей конвергенции.
Как мне настроить ceres для решения тех же координат, но только с учетом подмножества вершин, соответствующих текущему остатку?
Я попытался установить проблему с размерами 6 и 8 и указателем в нужном месте в x
, но ceres не позволяет использовать один и тот же указатель результата с другим смещением.
Далее я попытался использовать SubsetParameterization
например вот так
vector<double> x(mesh.n_faces()*6);
for(int i=0; i < mesh.n_faces(); i++){
vector<int> const_params;
for(int j = 0; j < mesh.n_faces(); j++) {
if(i != j) {
const_params.push_back(6*j);
const_params.push_back(6*j+1);
const_params.push_back(6*j+2);
const_params.push_back(6*j+3);
const_params.push_back(6*j+4);
const_params.push_back(6*j+5);
}
}
//auto *ssp = new ceres::SubsetParameterization(6, const_params); // (1)
auto *ssp = new ceres::SubsetParameterization(mesh.n_faces() * 6, const_params); // (2)
problem.AddParameterBlock(x.data(), mesh.n_faces() * 6, ssp);
problem.AddResidualBlock(face_cost_function, NULL, x.data());
}
Но черешние проверки говорят мне, что оба варианта неверны.
за (1) я получаю
local_parameterization.cc:98 Check failed: constant.back() < size Indices indicating constant parameter must be less than the size of the parameter block.
и за (2) я получаю
problem_impl.cc:135 Check failed: size == existing_size Tried adding a parameter block with the same double pointer, 000002D736397260, twice, but with different block sizes. Original size was 1152 but new size is 6
Как мне установить ceres up, чтобы я мог разделить одну и ту же проблему на перекрывающиеся блоки, которые влияют только на несколько переменных результата?
Я понял. Вам разрешено использовать несколько указателей в одном массиве, вам просто не разрешено иметь блоки разных размеров для одного и того же указателя.
Это означает, что ваши блоки внутри массива могут не перекрываться внутри массива, но разные функции стоимости могут использовать одни и те же блоки.
Решение состоит в том, чтобы использовать один блок на пару координат:
for(int i = 0; i < mesh.n_faces(); i++) {
face_cost_functors.push_back(new FaceFunctor());
ceres::DynamicAutoDiffCostFunctionFaceFunctor> *face_cost_function = new ceres::DynamicAutoDiffCostFunction<FaceFunctor>(face_cost_functors.back());
face_cost_function->SetNumResiduals(1);
face_cost_function->AddParameterBlock(2);
face_cost_function->AddParameterBlock(2);
face_cost_function->AddParameterBlock(2);
problem.AddResidualBlock(face_cost_function, NULL, &x.data()[6*i], &x.data()[6*i+2], &x.data()[6*i+4]);
}
Затем вы можете добавить дополнительные функции стоимости, если они используют одинаковые блоки (т. Е. Начальный адрес и размер блока одинаковы). Я здесь не использую никакой SubsetParametrization.
Это не сработало раньше, потому что я пытался использовать блок размером 6 для треугольников и 4 блока размера 2 для пар ребер, которые перекрывают блоки размера 6.
Теперь он работает намного быстрее, чем раньше, и сходится без проблем.
Других решений пока нет …