Подгонка плоскости к набору точек с использованием разложения по сингулярным значениям

Я пытаюсь подогнать плоскость к набору точек в трехмерном пространстве. Первоначально я пробовал исчерпывающую подгонку методом наименьших квадратов, но это оказалось слишком медленным. Я читал, что наиболее эффективным решением было бы выполнить разложение по сингулярным значениям.

Математика для этого мне не по силам, но я нашел кучу ресурсов, чтобы попытаться заставить это работать.

Согласно ответу в этом сообщении, мне нужно чтобы вычислить центроид точек, вычтите центроид из всех точек, поместите их в матрицу 3xN и выполните SVD. Затем я беру левый сингулярный вектор в качестве нормали к плоскости.

Все идет нормально.

Я нашел математическую библиотеку C# под названием alglib, в которой есть функция для SVD. Определение алгоритма можно найти здесь. Здесь у меня возникают проблемы, так как для этого требуются еще две матрицы в качестве входных данных в дополнение к матрице точек данных, и я действительно не понимаю, что в них помещать. Я запустил этот код независимо:

Vector3 centroid = getCentroid(planeVerts);
    double[,] dataMat = substractCentroid(planeVerts, centroid);
    double[] w = new double[3];
    double[,] u = new double[1,1];
    double[,] t = new double[1, 1];

    bool a = alglib.svd.rmatrixsvd(dataMat, 3, planeVerts.Length, 0, 0, 2, ref w, ref u, ref t);

    Vector3 planeNorm = new Vector3((float) w[0], (float) w[1], (float) w[2]);

Итак, теоретически я думал, что «w» будет содержать нормаль моей плоскости, но, к сожалению, это не так (я визуализировал ее в Unity3D, и она была под неправильным углом). Матрицы «u» и «t» — это те, которые меня смущают, и я действительно не знаю, на что мне их устанавливать.

Подробный API для функции rmatrixsvd можно найти здесь.

Есть ли ветераны математики или алгоритмов, которые могли бы поделиться своими знаниями по этому вопросу? Мне нужно использовать C#, так как мой проект находится в Unity3D. Я буду рад предоставить дополнительную информацию, если это необходимо.


person Fat-chunk    schedule 30.03.2015    source источник


Ответы (1)


Глядя на документацию, похоже, что w будет содержать ваши сингулярные значения, U будет содержать левые сингулярные векторы, а V будет содержать правые сингулярные векторы. Поскольку dataMat имеет размер 3xN, U должно быть 3x3, а V должно быть NxN. И, как вы говорите, вам нужен левый сингулярный вектор, установите UNeeded=1 и просто возьмите первый столбец U. Поскольку вам не нужны правые сингулярные векторы, вы также можете установить VNeeded=0.

person vrume21    schedule 30.03.2015
comment
Просто примечание; OP также необходимо установить параметр UNeeded для вывода левых сингулярных векторов. - person Dan Bryant; 31.03.2015
comment
Спасибо! Обновлен ответ, чтобы включить эти предложения. - person vrume21; 31.03.2015
comment
Спасибо за ответ. Это может показаться действительно глупым вопросом, но какие значения я ввожу в матрицы U и V? Спасибо! - person Fat-chunk; 31.03.2015
comment
Вы просто выделяете необходимую память и передаете указатели на две матрицы в функцию. Любые значения, введенные в U и V, будут перезаписаны. - person vrume21; 31.03.2015
comment
Да, я понял это в конце концов. Благодарю вас! - person Fat-chunk; 31.03.2015