Массивная интерполяция

Прежде чем я начну, примите мои извинения за то, что я не математик и на самом деле не знаю правильных имен для того, что я пытаюсь сделать...;) Указатели на любые простые объяснения на английском языке, которые могут помочь, были бы наиболее признателен (поскольку я в настоящее время чисто Google, основанный на том, что я думаю, что решение может быть).

Если у вас есть многомерный массив исходных значений и вы хотите увеличить этот массив в n раз, я думаю, что мне нужно использовать бикубическую интерполяцию. Конечно, верхнее правое изображение на этой странице отражает то, что я стремление к созданию постепенного потока значений между базовыми точками исходных данных, основанных на значениях их окружающих соседей. Я полностью согласен с тем, что не увеличивая объем данных, я не увеличиваю разрешение данных; просто размытие краев.

Что-то похожее на выход из этого;

Исходная сетка

к этому (и далее);

Целевая сетка

Переход по ссылке в статье в Википедии дает мне (предполагаемый) пример реализации того, к чему я стремлюсь, но, если это произойдет, я боюсь, что в настоящее время мне не хватает логического скачка, чтобы попасть туда. Когда я вызываю getValue(source, 0.5, 0.5) для BicubicInterpolator, что я получаю обратно? Я думал, что если бы я дал x/y (0.0,0.0), я бы вернул левое нижнее значение сетки, и если бы я посмотрел на (1,1), я бы получил верхний правый угол, и любое значение между дай мне указанную позицию в интерполированной сетке.

double[][] source  = new double[][] {{1, 1, 1, 2}, {1, 2, 2, 3}, {1, 2, 2, 3}, {1, 1, 3, 3}};
BicubicInterpolator bi = new BicubicInterpolator();
for (double idx = 0; idx <= 1; idx += 0.1) {
  LOG.info("Result (" + String.format("%3.1f", idx) + ", " + String.format("%3.1f", idx) + ") : " + bi.getValue(source, idx, idx));         
}

Выход для диагональной линии через мою исходную сетку однако;

Result (0.0, 0.0) : 2.0
Result (0.1, 0.1) : 2.08222625
Result (0.2, 0.2) : 2.128
Result (0.3, 0.3) : 2.13747125
Result (0.4, 0.4) : 2.11424
Result (0.5, 0.5) : 2.06640625
Result (0.6, 0.6) : 2.00672
Result (0.7, 0.7) : 1.9518312500000001
Result (0.8, 0.8) : 1.92064
Result (0.9, 0.9) : 1.93174625
Result (1.0, 1.0) : 2.0

Я запутался, потому что диагонали идут от 1 до 3 и от 1 до 2; нет ничего идущего от 2 до 2 с очень маленькими (общими) вариациями. Я совершенно не понимаю вещи?


РЕДАКТИРОВАТЬ: Следуя предложению Питера расширить границы для анализа, сетка теперь может быть сгенерирована как быстрый и грязный масштаб до матрицы 30х30;

Сетка из ответа Петра

Теперь, когда то, что происходит, становится более понятным, я вижу, что мне нужно рассмотреть несколько дополнительных вещей;

  • Управляйте выбросом (видно в середине сетки, где источник имеет блок из четырех ячеек со значением 2, но интерполированное значение достигает пика в 2,2)
  • Обрабатывайте пустые значения в исходной сетке и рассматривайте их как пустые, а не нулевые, чтобы они не искажали вычисление
  • Будьте готовы, чтобы мне сказали, что я нахожусь в дурацком поручении и что нужно другое решение
  • Посмотрите, было ли это то, что клиент думал, что он на самом деле хотел, когда он сказал: "Сделайте это меньше блоков"

1 ответ

Решение

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

public static void main(String... args) {
    double[][] source = new double[][]{{1, 1, 1, 2}, {1, 2, 2, 3}, {1, 2, 2, 3}, {1, 1, 3, 3}};
    BicubicInterpolator bi = new BicubicInterpolator();
    for (int i = 0; i <= 30; i++) {
        double idx = i / 10.0;
        System.out.printf("Result (%3.1f, %3.1f) : %3.1f%n", idx, idx, bi.getValue(source, idx, idx));
    }
}

public static class CubicInterpolator {
    public static double getValue(double[] p, double x) {
        int xi = (int) x;
        x -= xi;
        double p0 = p[Math.max(0, xi - 1)];
        double p1 = p[xi];
        double p2 = p[Math.min(p.length - 1,xi + 1)];
        double p3 = p[Math.min(p.length - 1, xi + 2)];
        return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
    }
}

public static class BicubicInterpolator extends CubicInterpolator {
    private double[] arr = new double[4];

    public double getValue(double[][] p, double x, double y) {
        int xi = (int) x;
        x -= xi;
        arr[0] = getValue(p[Math.max(0, xi - 1)], y);
        arr[1] = getValue(p[xi], y);
        arr[2] = getValue(p[Math.min(p.length - 1,xi + 1)], y);
        arr[3] = getValue(p[Math.min(p.length - 1, xi + 2)], y);
        return getValue(arr, x+ 1);
    }
}

печать

Result (0.0, 0.0) : 1.0
Result (0.1, 0.1) : 1.0
Result (0.2, 0.2) : 1.0
Result (0.3, 0.3) : 1.1
Result (0.4, 0.4) : 1.1
Result (0.5, 0.5) : 1.3
Result (0.6, 0.6) : 1.4
Result (0.7, 0.7) : 1.6
Result (0.8, 0.8) : 1.7
Result (0.9, 0.9) : 1.9
Result (1.0, 1.0) : 2.0
Result (1.1, 1.1) : 2.1
Result (1.2, 1.2) : 2.1
Result (1.3, 1.3) : 2.1
Result (1.4, 1.4) : 2.1
Result (1.5, 1.5) : 2.1
Result (1.6, 1.6) : 2.0
Result (1.7, 1.7) : 2.0
Result (1.8, 1.8) : 1.9
Result (1.9, 1.9) : 1.9
Result (2.0, 2.0) : 2.0
Result (2.1, 2.1) : 2.1
Result (2.2, 2.2) : 2.3
Result (2.3, 2.3) : 2.5
Result (2.4, 2.4) : 2.7
Result (2.5, 2.5) : 2.8
Result (2.6, 2.6) : 2.9
Result (2.7, 2.7) : 3.0
Result (2.8, 2.8) : 3.0
Result (2.9, 2.9) : 3.0
Result (3.0, 3.0) : 3.0

Глядя на то, как это работает, у вас есть сетка 2х2 внутренних значений и квадрат 4х4 снаружи для внешних значений. значения от (0,0, 0,0) до (1,0, 1,0) отображают диагональ между 2 (в ячейке 2,2) и 2 (в ячейке 3,3), используя внешние значения, чтобы помочь интерполировать значения.

double[][] source = new double[][]{{1, 1, 1, 2}, {1, 2, 2, 3}, {1, 2, 2, 3}, {1, 1, 3, 3}};
BicubicInterpolator bi = new BicubicInterpolator();
for (int i = -10; i <= 20; i++) {
    double idx = i / 10.0;
    System.out.printf("Result (%3.1f, %3.1f) : %3.1f%n", idx, idx, bi.getValue(source, idx, idx));
}

печать

Result (-1.0, -1.0) : -5.0
Result (-0.9, -0.9) : -2.8
Result (-0.8, -0.8) : -1.2
Result (-0.7, -0.7) : -0.2
Result (-0.6, -0.6) : 0.5
Result (-0.5, -0.5) : 1.0
Result (-0.4, -0.4) : 1.3
Result (-0.3, -0.3) : 1.5
Result (-0.2, -0.2) : 1.7
Result (-0.1, -0.1) : 1.9
Result (0.0, 0.0) : 2.0
Result (0.1, 0.1) : 2.1
Result (0.2, 0.2) : 2.1
Result (0.3, 0.3) : 2.1
Result (0.4, 0.4) : 2.1
Result (0.5, 0.5) : 2.1
Result (0.6, 0.6) : 2.0
Result (0.7, 0.7) : 2.0
Result (0.8, 0.8) : 1.9
Result (0.9, 0.9) : 1.9
Result (1.0, 1.0) : 2.0
Result (1.1, 1.1) : 2.1
Result (1.2, 1.2) : 2.3
Result (1.3, 1.3) : 2.5
Result (1.4, 1.4) : 2.7
Result (1.5, 1.5) : 2.8
Result (1.6, 1.6) : 2.7
Result (1.7, 1.7) : 2.1
Result (1.8, 1.8) : 0.9
Result (1.9, 1.9) : -1.4
Result (2.0, 2.0) : -5.0
Другие вопросы по тегам