Правильная реализация кубической сплайн-интерполяции

Я использовал один из предложенных алгоритмов, но результаты очень плохие.

Я реализовал алгоритм вики

в Java (код ниже). x(0) является points.get(0), y(0) является values[points.get(0)], α является alfa а также μ является mi, Остальное такое же, как в псевдокоде вики.

    public void createSpline(double[] values, ArrayList<Integer> points){
a = new double[points.size()+1];

for (int i=0; i <points.size();i++)
{
a[i] = values[points.get(i)];

}

b = new double[points.size()];
d = new double[points.size()];
h = new double[points.size()];

for (int i=0; i<points.size()-1; i++){
h[i] = points.get(i+1) - points.get(i);
}

alfa = new double[points.size()];

for (int i=1; i <points.size()-1; i++){
alfa[i] = (double)3 / h[i] * (a[i+1] - a[i]) - (double)3 / h[i-1] *(a[i+1] - a[i]);
}

c = new double[points.size()+1];
l = new double[points.size()+1];
mi = new double[points.size()+1];
z = new double[points.size()+1];

l[0] = 1; mi[0] = z[0] = 0;

for (int i =1; i<points.size()-1;i++){
l[i] = 2 * (points.get(i+1) - points.get(i-1)) - h[i-1]*mi[i-1];
mi[i] = h[i]/l[i];
z[i] = (alfa[i] - h[i-1]*z[i-1])/l[i];
}

l[points.size()] = 1;
z[points.size()] = c[points.size()] = 0;

for (int j=points.size()-1; j >0; j--)
{
c[j] = z[j] - mi[j]*c[j-1];
b[j] = (a[j+1]-a[j]) - (h[j] * (c[j+1] + 2*c[j])/(double)3) ;
d[j] = (c[j+1]-c[j])/((double)3*h[j]);
}for (int i=0; i<points.size()-1;i++){
for (int j = points.get(i); j<points.get(i+1);j++){
//                fk[j] = values[points.get(i)];
functionResult[j] = a[i] + b[i] * (j - points.get(i))
+ c[i] * Math.pow((j - points.get(i)),2)
+ d[i] * Math.pow((j - points.get(i)),3);
}
}

}

В результате я получаю следующее:

введите описание изображения здесь

но это должно быть похоже на это:

введите описание изображения здесь


Я также пытаюсь реализовать алгоритм по-другому в соответствии с: http://www.geos.ed.ac.uk/~yliu23/docs/lect_spline.pdf

Сначала они показывают, как сделать линейный сплайн, и это довольно просто. Я создаю функции, которые рассчитывают A а также B коэффициенты. Затем они расширяют линейный сплайн, добавляя вторую производную. C а также D Коэффициенты тоже легко рассчитать.

Но проблемы начинаются, когда я пытаюсь вычислить вторую производную. Я не понимаю, как они их рассчитывают.

Поэтому я реализовал только линейную интерполяцию. Результат:

введите описание изображения здесь

Кто-нибудь знает, как исправить первый алгоритм или объяснить, как вычислить вторую производную во втором алгоритме?

3

Решение

Кубический b-сплайн был недавно описан в серии статей Unser, Thévenaz и другие., увидеть среди других

М. Унсер, А. Алдруби, М. Иден, «Быстрые B-сплайн-преобразования для непрерывного представления и интерполяции изображений», IEEE Trans. Pattern Анальный. Машина Интелл., том 13, н. 3, с. 277-285, март 1991 г.

М. Унсер, «Сплайны, идеально подходящие для обработки сигналов и изображений», IEEE Signal Proc. Магнето, с. 22- 38, ноябрь 1999 г.

а также

П. Тевеназ, Т. Блу, М. Унсер, «Возвращение к интерполяции» IEEE Trans. по медицинской визуализации, том 19, нет. 7, с. 739-758, июль 2000 г.

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

Что такое сплайны?

Сплайны — это кусочно-полиномы, которые гладко связаны друг с другом. За сплайн степени nкаждый сегмент является полиномом степени n, Части связаны так, что сплайн непрерывен до его производной степени n-1 на узлы, а именно, точки соединения частей полинома.

Как можно построить сплайны?

Сплайн нулевого порядка следующий

введите описание изображения здесь

Все остальные сплайны могут быть построены как

введите описание изображения здесь

где сверток взят n-1 раз.

Кубические сплайны

Самые популярные сплайны — кубические сплайны, чье выражение

введите описание изображения здесь

Сплайн-интерполяция

Учитывая функцию f(x) выборка в дискретных целочисленных точках k, задача сплайн-интерполяции состоит в определении аппроксимации s(x) в f(x) выражается следующим образом

введите описание изображения здесь

где ckэто коэффициенты интерполяции и s(k) = f(k),

Сплайн-предварительная фильтрация

К сожалению, начиная с n=3 на,

введите описание изображения здесь

таким образом ckэто не коэффициенты интерполяции. Их можно определить, решив линейную систему уравнений, полученную путем принуждения s(k) = f(k)а именно

введите описание изображения здесь

Такое уравнение может быть преобразовано в форму свертки и решено в преобразованном zпространство как

введите описание изображения здесь

где

введите описание изображения здесь

Соответственно,

введите описание изображения здесь

Такой путь всегда предпочтительнее, чем решение линейной системы уравнений, например, LU разложение.

Решение вышеприведенного уравнения можно определить, заметив, что

введите описание изображения здесь

где

введите описание изображения здесь

Первая фракция является представителем причинный фильтр, в то время как второй является представителем противоопухолевый фильтр. Оба они показаны на рисунках ниже.

Причинный фильтр

введите описание изображения здесь

Антикаузальный фильтр

введите описание изображения здесь

На последнем рисунке

введите описание изображения здесь

Выходные данные фильтров могут быть выражены следующими рекурсивными уравнениями

введите описание изображения здесь

Вышеприведенные уравнения могут быть решены путем первого определения «начальных условий» для c- а также c+, Предполагая периодическое, зеркальные входная последовательность fk такой, что

введите описание изображения здесь

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

введите описание изображения здесь

в то время как начальное условие для c+ может быть выражено как

введите описание изображения здесь

7

Другие решения

Извините, но Ваш исходный код действительно нечитаемый беспорядок для меня, поэтому я придерживаюсь теории. Вот несколько советов:

  1. SPLINE кубики

    SPLINE это не интерполяция, а приближение чтобы использовать их, вам не нужно никакого деривации. Если у вас есть десять очков: p0,p1,p2,p3,p4,p5,p6,p7,p8,p9 затем кубический сплайн начинается / заканчивается тройной точкой. Если вы создаете функцию «рисовать» СПЛАЙН Затем исправьте кубическую кривую, чтобы обеспечить непрерывность последовательности вызовов:

        spline(p0,p0,p0,p1);
    spline(p0,p0,p1,p2);
    spline(p0,p1,p2,p3);
    spline(p1,p2,p3,p4);
    spline(p2,p3,p4,p5);
    spline(p3,p4,p5,p6);
    spline(p4,p5,p6,p7);
    spline(p5,p6,p7,p8);
    spline(p6,p7,p8,p9);
    spline(p7,p8,p9,p9);
    spline(p8,p9,p9,p9);
    

    не забывайте, что кривая SPLINE для p0,p1,p2,p3 нарисовать только кривую «между» p1,p2 !!!

  2. Безье кубики

    4-точечный Безье Коэффициенты могут быть вычислены следующим образом:

        a0=                              (    p0);
    a1=                    (3.0*p1)-(3.0*p0);
    a2=          (3.0*p2)-(6.0*p1)+(3.0*p0);
    a3=(    p3)-(3.0*p2)+(3.0*p1)-(    p0);
    
  3. интерполирование

    чтобы использовать интерполяцию, вы должны использовать интерполяционные полиномы. Есть много, но я предпочитаю использовать кубики … похоже на Безье / СПЛАЙН / NURBS … так

    • p(t) = a0+a1*t+a2*t*t+a3*t*t*t где t = <0,1>

    Осталось только вычислить a0,a1,a2,a3, У вас есть 2 уравнения (p(t) и его вывод по t) и 4 балла из набора данных. Вы также должны обеспечить непрерывность … Таким образом, первый вывод для точек соединения должен быть одинаковым для соседних кривых (t=0,t=1). Это приводит к системе 4 линейных уравнений (использование t=0 а также t=1). Если вы получите его, он создаст простое уравнение, зависящее только от координат входной точки:

        double  d1,d2;
    d1=0.5*(p2-p0);
    d2=0.5*(p3-p1);
    a0=p1;
    a1=d1;
    a2=(3.0*(p2-p1))-(2.0*d1)-d2;
    a3=d1+d2+(2.0*(-p2+p1));
    

    последовательность вызовов такая же, как для СПЛАЙН

[Заметки]

  1. Разница между интерполяцией и аппроксимацией заключается в том, что:

    Кривая интерполяции всегда проходит через контрольные точки, но многочлены высокого порядка имеют тенденцию колебаться, и приближение только приближается к контрольным точкам (в некоторых случаях может пересекать их, но обычно нет).

  2. переменные:

    • a0,... p0,... являются векторами (число измерений должно соответствовать входным точкам)
    • t является скалярным
  3. рисовать кубики из коэффициентов a0,..a3

    просто сделайте что-то вроде этого:

        MoveTo(a0.x,a0.y);
    for (t=0.0;t<=1.0;t+=0.01)
    {
    tt=t*t;
    ttt=tt*t;
    p=a0+(a1*t)+(a2*tt)+(a3*ttt);
    LineTo(p.x,p.y);
    }
    
5

Увидеть сплайн-интерполяция, хотя они дают только полезный пример 3х3. Для большего количества точек выборки, скажем, N + 1 перечислил x[0..N] со значениями y[0..N] нужно решить следующую систему для неизвестного k[0..N]

              2*    c[0]    * k[0] + c[0] * k[1] == 3*   d[0];
c[0] * k[0] + 2*(c[0]+c[1]) * k[1] + c[1] * k[2] == 3*(d[0]+d[1]);
c[1] * k[1] + 2*(c[1]+c[2]) * k[2] + c[2] * k[3] == 3*(d[1]+d[2]);
c[2] * k[2] + 2*(c[2]+c[3]) * k[3] + c[3] * k[4] == 3*(d[2]+d[3]);
...
c[N-2]*k[N-2]+2*(c[N-2]+c[N-1])*k[N-1]+c[N-1]*k[N] == 3*(d[N-2]+d[N-1]);
c[N-2]*k[N-1] + 2*c[N-1]        *  k[N]          == 3*   d[N-1];

где

c[k]=1/(x[k+1]-x[k]); d[k]=(y[k+1]-y[k])*c[k]*c[k];

Эту проблему можно решить с помощью итерации Гаусса-Зейделя (не было ли она изобретена именно для этой системы?) Или вашего любимого космического решателя Крылова.

1