Интерполя́ция, интерполи́рование — в вычислительной математике способ нахождения промежуточных значений величины по имеющемуся дискретному набору известных значений.



















/**
* Кубическая интерполяция
*
* @param array $p Массив известных значений функции: f(x0), f(x1), f(x2), f(x3)
* @param float $x x-координата искомой точки
* @return float Значение функции f($x)
*/
function cubicInterpolate ($p, $x) {
return $p[1] + (-0.5 * $p[0] + 0.5 * $p[2]) * $x
+ ($p[0] - 2.5 * $p[1] + 2.0 * $p[2] - 0.5 * $p[3]) * $x * $x
+ (-0.5 * $p[0] + 1.5 * $p[1] - 1.5 * $p[2] + 0.5 * $p[3]) * $x * $x * $x;
}

/**
* Функция бикубической интерполяции
*
* @param array $p Массив с 2-мя измерениями (4 x 4), содержащий известные значения 16-ти соседних точек
* @param float $x x-координата искомой точки
* @param float $y y-координата искомой точки
* @return float Значение функции f($x, $y)
*/
function bicubicInterpolate ($p, $x, $y) {
$tmp = array();
$tmp[0] = cubicInterpolate($p[0], $y);
$tmp[1] = cubicInterpolate($p[1], $y);
$tmp[2] = cubicInterpolate($p[2], $y);
$tmp[3] = cubicInterpolate($p[3], $y);
return cubicInterpolate($tmp, $x);
}

g(x,y) = a00 * x^0 * y^0 + a01 * x^0 * y^1 +
a02 * x^0 * y^2 + a03 * x^0 * y^3 +
a10 * x^1 * y^0 + a11 * x^1 * y^1 +
a12 * x^1 * y^2 + a13 * x^1 * y^3 +
a20 * x^2 * y^0 + a21 * x^2 * y^1 +
a22 * x^3 * y^2 + a23 * x^2 * y^3 +
a30 * x^3 * y^0 + a31 * x^3 * y^1 +
a32 * x^3 * y^2 + a33 * x^3 * y^3
class CachedBicubicInterpolator
{
private $a00, $a01, $a02, $a03,
$a10, $a11, $a12, $a13,
$a20, $a21, $a22, $a23,
$a30, $a31, $a32, $a33;
/**
* Кешируем коэффициенты.
*
* @param array $p 2-мерный массив (4 x 4), содержащий значения известных соседних точек
* @return void
*/
public function updateCoefficients ($p) {
$this->a00 = $p[1][1];
$this->a01 = -.5 * $p[1][0] + .5 * $p[1][2];
$this->a02 = $p[1][0] - 2.5 * $p[1][1] + 2 * $p[1][2] - .5 * $p[1][3];
$this->a03 = -.5 * $p[1][0] + 1.5 * $p[1][1] - 1.5 * $p[1][2] + .5 * $p[1][3];
$this->a10 = -.5 * $p[0][1] + .5 * $p[2][1];
$this->a11 = .25 * $p[0][0] - .25 * $p[0][2] - .25 * $p[2][0] + .25 * $p[2][2];
$this->a12 = -.5 * $p[0][0] + 1.25 * $p[0][1] - $p[0][2] + .25 * $p[0][3]
+ .5 * $p[2][0] - 1.25 * $p[2][1] + $p[2][2] - .25 * $p[2][3];
$this->a13 = .25 * $p[0][0] - .75 * $p[0][1] + .75 * $p[0][2] - .25 * $p[0][3]
- .25 * $p[2][0] + .75 * $p[2][1] - .75 * $p[2][2] + .25 * $p[2][3];
$this->a20 = $p[0][1] - 2.5 * $p[1][1] + 2 * $p[2][1] - .5 * $p[3][1];
$this->a21 = -.5 * $p[0][0] + .5 * $p[0][2] + 1.25 * $p[1][0] - 1.25 * $p[1][2]
- $p[2][0] + $p[2][2] + .25 * $p[3][0] - .25 * $p[3][2];
$this->a22 = $p[0][0] - 2.5 * $p[0][1] + 2 * $p[0][2] - .5 * $p[0][3] - 2.5 * $p[1][0]
+ 6.25 * $p[1][1] - 5 * $p[1][2] + 1.25 * $p[1][3] + 2 * $p[2][0]
- 5 * $p[2][1] + 4 * $p[2][2] - $p[2][3] - .5 * $p[3][0]
+ 1.25 * $p[3][1] - $p[3][2] + .25 * $p[3][3];
$this->a23 = -.5 * $p[0][0] + 1.5 * $p[0][1] - 1.5 * $p[0][2] + .5 * $p[0][3]
+ 1.25 * $p[1][0] - 3.75 * $p[1][1] + 3.75 * $p[1][2]
- 1.25 * $p[1][3] - $p[2][0] + 3 * $p[2][1] - 3 * $p[2][2] + $p[2][3]
+ .25 * $p[3][0] - .75 * $p[3][1] + .75 * $p[3][2] - .25 * $p[3][3];
$this->a30 = -.5 * $p[0][1] + 1.5 * $p[1][1] - 1.5 * $p[2][1] + .5 * $p[3][1];
$this->a31 = .25 * $p[0][0] - .25 * $p[0][2] - .75 * $p[1][0] + .75 * $p[1][2]
+ .75 * $p[2][0] - .75 * $p[2][2] - .25 * $p[3][0] + .25 * $p[3][2];
$this->a32 = -.5 * $p[0][0] + 1.25 * $p[0][1] - $p[0][2] + .25 * $p[0][3]
+ 1.5 * $p[1][0] - 3.75 * $p[1][1] + 3 * $p[1][2] - .75 * $p[1][3]
- 1.5 * $p[2][0] + 3.75 * $p[2][1] - 3 * $p[2][2] + .75 * $p[2][3]
+ .5 * $p[3][0] - 1.25 * $p[3][1] + $p[3][2] - .25 * $p[3][3];
$this->a33 = .25 * $p[0][0] - .75 * $p[0][1] + .75 * $p[0][2] - .25 * $p[0][3]
- .75 * $p[1][0] + 2.25 * $p[1][1] - 2.25 * $p[1][2] + .75 * $p[1][3]
+ .75 * $p[2][0] - 2.25 * $p[2][1] + 2.25 * $p[2][2] - .75 * $p[2][3]
- .25 * $p[3][0] + .75 * $p[3][1] - .75 * $p[3][2] + .25 * $p[3][3];
}
/**
* Получаем значения.
*
* @param float $x $x = $x - $x0
* @param float $y $y = $y - $y0
* @return float Значение функции в точке.
*/
public function getValue ($x, $y) {
//Кешируем возвещение во 2 и 3 степени.
$x2 = $x * $x;
$x3 = $x2 * $x;
$y2 = $y * $y;
$y3 = $y2 * $y;
return ($this->a00 + $this->a01 * $y + $this->a02 * $y2 + $this->a03 * $y3) +
($this->a10 + $this->a11 * $y + $this->a12 * $y2 + $this->a13 * $y3) * $x +
($this->a20 + $this->a21 * $y + $this->a22 * $y2 + $this->a23 * $y3) * $x2 +
($this->a30 + $this->a31 * $y + $this->a32 * $y2 + $this->a33 * $y3) * $x3;
}
}
<?php
header("Content-type: image/png");//Меняем заголовок
include 'interpolation.php';//Подключаем необходимые файлы
include 'colormap.php';//Подключаем необходимые файлы
$simpleData = array(
array(0, 0.1, 0.15, 0.2, 0.15, 0.1, 0),
array(0, 0.1, 0.5, 1, 0.9, 0.1, 0),
array(0, 0.1, 0.7, 1, 0.9, 0.1, 0),
array(0, 0.1, 0.6, 0.7, 0.5, 0.1, 0),
array(0, 0.2, 0.8, 0.6, 0.15, 0.08, 0.1),
array(0.08, 0.2, 0.15, 0.2, 0.15, 0.1, 0.1),
array(0.1, 0.8, 0.1, 0.1, 0.1, 0, 0)
);//Пример массива исходных данных 7 х 7
$countX = count($simpleData[0]);//Определяем размерность входных данных
$countY = count($simpleData);
$input = array();
/* Экстраполируем и перевернем массив для удобства
* Линейно экстраполируем крайние строки и столбцы, для того чтобы можно было интерполировать крайние квадраты
* В случае заполнения нулями - граница будет выглядеть слишком грубо
*/
for ($i = 0; $i < $countX; $i ++) {
for ($j = 0; $j < $countY; $j ++) {
$input[$i + 1][$j + 1] = $simpleData[$j][$i];
if ($i == 0) {
$input[0][$j + 1] = $simpleData[$j][$i] - $simpleData[$j][$i + 1];//экстраполируем влево
}
if ($i == ($countX - 1)) {
$input[$countX + 1][$j + 1] = $simpleData[$j][$i] - $simpleData[$j][$i - 1];//экстраполируем вправо
}
if ($j == 0) {
$input[$i + 1][0] = $simpleData[$j][$i] - $simpleData[$j + 1][$i];//экстраполируем вверх
}
if ($j == ($countY - 1)) {
$input[$i + 1][$countY + 1] = $simpleData[$j][$i] - $simpleData[$j - 1][$i];//экстраполируем вниз
}
}
}
/* Экстраполируем углы
* Особой точности здесь не требуется, поэтому я использовал среднее арифметическое.
*/
$input[0][0] = ($input[1][0] + $input[0][1]) / 2;
$input[$countX + 1][0] = ($input[$countX][0] + $input[$countX][1]) / 2;
$input[0][$countY + 1] = ($input[0][$countY] + $input[1][$countY]) / 2;
$input[$countX + 1][$countY + 1] = ($input[$countX + 1][$countY] + $input[$countX][$countY]) / 2;
$step = 50; //Шаг сетки 50 пикселей
$img = imagecreatetruecolor(($countX - 1) * $step, ($countY - 1) * $step);//Создаем изображение искомого размера
$colormap = createColormap($img);//Создаем карту цветов
$b2i = new CachedBicubicInterpolator();
for ($i = 1; $i < $countX; $i ++) {//Обход исходной сетки
for ($j = 1; $j < $countY; $j ++) {
$points = array();
$points[0][0] = $input[$i - 1][$j - 1];
$points[1][0] = $input[$i][$j - 1];
$points[2][0] = $input[$i + 1][$j - 1];
$points[3][0] = $input[$i + 2][$j - 1];
$points[0][1] = $input[$i - 1][$j];
$points[1][1] = $input[$i][$j];
$points[2][1] = $input[$i + 1][$j];
$points[3][1] = $input[$i + 2][$j];
$points[0][2] = $input[$i - 1][$j + 1];
$points[1][2] = $input[$i][$j + 1];
$points[2][2] = $input[$i + 1][$j + 1];
$points[3][2] = $input[$i + 2][$j + 1];
$points[0][3] = $input[$i - 1][$j + 2];
$points[1][3] = $input[$i][$j + 2];
$points[2][3] = $input[$i + 1][$j + 2];
$points[3][3] = $input[$i + 2][$j + 2];
$b2i->updateCoefficients($points);//Обновим коэффициенты
for ($x = 0; $x < $step; $x ++) {//Обход результирующего изображения
for ($y = 0; $y < $step; $y ++) {
$rx = ($i - 1) * $step + $x;//х пикселя на выходном изображении
$ry = ($j - 1) * $step + $y;//y пикселя на выходном изображении
$ax = $x / $step;//x - x0
$ay = $y / $step;//y - y0
$val = $b2i->getValue($ax, $ay);//Получим значение
$color = ceil(($val) * 1024) - 1;//Подберем цвет
if ($color < 0) $color = 0;//На всякий случай
if ($color > 1023) $color = 1023;//На всякий случай
imagesetpixel($img, $rx, $ry, $colormap[$color]);//Нарисовали точку
}
}
}
}
imagepng($img);
?>
function createColormap(&$image) {
$colormap = array();
for ($i = 0; $i < 256; $i ++) {
$colormap[$i] = imagecolorallocate($image, 0, $i, 255);
}
for ($i = 0; $i < 256; $i ++) {
$colormap[$i + 256] = imagecolorallocate($image, 0, 255, 255 - $i);
}
for ($i = 0; $i < 256; $i ++) {
$colormap[$i + 512] = imagecolorallocate($image, $i, 255, 0);
}
for ($i = 0; $i < 256; $i ++) {
$colormap[$i + 768] = imagecolorallocate($image, 255, 255 - $i, 0);
}
return $colormap;
}
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
комментарии (34)