Протягивая массив - PullRequest
       21

Протягивая массив

8 голосов
/ 22 июля 2010

У меня есть вектор образцов, которые образуют кривую.Давайте представим, что в нем 1000 баллов.Если я хочу растянуть его до 1500 баллов, какой самый простой алгоритм дает достойные результаты?Я ищу что-то, что составляет всего несколько строк C / C ++.

Я всегда хочу увеличить размер вектора, и новый вектор может быть где угодно от 1,1x до 50xтекущего вектора.

Спасибо!

Ответы [ 3 ]

6 голосов
/ 23 июля 2010

Здесь C ++ для линейной и квадратичной интерполяции.
interp1( 5.3, a, n ) - это [5] + .3 * (a [6] - a [5]), .3 пути от [5] до [6];
interp1array( a, 1000, b, 1500 ) будет растягиваться a до b.
interp2( 5.3, a, n ) рисует параболу через 3 ближайших пункта a [4] a [5] a [6]: более плавный, чем interp1, но все еще быстрый.
(Сплайны используют 4 ближайших точки, еще более гладкие; если вы читаете Python, см. базовый-сплайн-интерполяция-в-а-несколько линий-оф-NumPy .

// linear, quadratic interpolation in arrays
// from interpol.py denis 2010-07-23 July

#include <stdio.h>
#include <stdlib.h>

    // linear interpolate x in an array
// inline
float interp1( float x, float a[], int n )
{
    if( x <= 0 )  return a[0];
    if( x >= n - 1 )  return a[n-1];
    int j = int(x);
    return a[j] + (x - j) * (a[j+1] - a[j]);
}

    // linear interpolate array a[] -> array b[]
void inter1parray( float a[], int n, float b[], int m )
{
    float step = float( n - 1 ) / (m - 1);
    for( int j = 0; j < m; j ++ ){
        b[j] = interp1( j*step, a, n );
    }
}

//..............................................................................
    // parabola through 3 points, -1 < x < 1
float parabola( float x, float f_1, float f0, float f1 )
{
    if( x <= -1 )  return f_1; 
    if( x >= 1 )  return f1; 
    float l = f0 - x * (f_1 - f0);
    float r = f0 + x * (f1 - f0);
    return (l + r + x * (r - l)) / 2;
}

    // quadratic interpolate x in an array
float interp2( float x, float a[], int n )
{
    if( x <= .5  ||  x >= n - 1.5 )
        return interp1( x, a, n );
    int j = int( x + .5 );
    float t = 2 * (x - j);  // -1 .. 1
    return parabola( t, (a[j-1] + a[j]) / 2, a[j], (a[j] + a[j+1]) / 2 );
}

    // quadratic interpolate array a[] -> array b[]
void interp2array( float a[], int n, float b[], int m )
{
    float step = float( n - 1 ) / (m - 1);
    for( int j = 0; j < m; j ++ ){
        b[j] = interp2( j*step, a, n );
    }
}

int main( int argc, char* argv[] )
{
        // a.out [n m] --
    int n = 10, m = 100;
    int *ns[] = { &n, &m, 0 },
        **np = ns;
    char* arg;
    for( argv ++;  (arg = *argv) && *np;  argv ++, np ++ )
        **np = atoi( arg );
    printf( "n: %d  m: %d\n", n, m );

    float a[n], b[m];
    for( int j = 0; j < n; j ++ ){
        a[j] = j * j;
    }
    interp2array( a, n, b, m );  // a[] -> b[]

    for( int j = 0; j < m; j ++ ){
        printf( "%.1f ", b[j] );
    }
    printf( "\n" );
}
2 голосов
/ 22 июля 2010

Какой самый простой алгоритм, который дает достойные результаты?

Сплайны Катмулла-Рома. (если вы хотите плавную кривую)

http://www.mvps.org/directx/articles/catmull/
http://en.wikipedia.org/wiki/Cubic_Hermite_spline

Для каждого нового элемента, вычисляющего дробную позицию в старом массиве, используйте дробную часть (f - floor (f)) в качестве коэффициента интерполяции и часть «integer» (т.е. floor (f)) для поиска ближайших элементов.

Это предполагает, что вы оперируете данными, которые могут быть математически интерполированы (плавающие). Если данные не могут быть интерполированы (строки), то единственным решением является использование ближайшего доступного элемента старого массива.

Вам понадобится некоторая настройка, если точки в массиве распределены неравномерно.

0 голосов
/ 22 июля 2010

Самый простой вариант, который я могу себе представить, это просто fn, расширяющий массив на основе средних значений, поэтому:

x, y, z

становится

х, ср. (Х, у), у, ср (у, г), z

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

...