layout: post
title: 二维三次卷积插值算法及Fortran代码
categories:
- 2012-07-24 20:59:20 初稿
- 2012-07-26 09:39:47 更新注意
- 2012-11-26 16:18:26 修正代码错误, 默认三阶精度边界条件
最近有人问起二维三次卷积插值算法(Cubic Convolution Interpolation)及其程序的问题, 我想到这种插值算法也能用于图像的插值, 所以也就有了兴趣, 稍微了解了一下, 并试着用Fortran实现了一下, 同时也顺便复习了一下Fortran90的一下新特性. 如果需要, 敬请使用; 发现Bug, 烦请明示.
值得注意的是, 我在程序中将原本为Nx×Ny的格点数据向正反方向都增加了节点, 变为0:Nx+2×0:Ny+2. 这样做的目的是为了计算每个节点x, y方向导数的方便, 不再需要区分边界点与非边界点, 统一使用中心差分公式即可. 扩展节点数据的取法保证了边界点的导数由最近两点的差分决定.
代码
<table class="highlighttable"><th colspan="2">fortran</th><tr><td><div class="linenodiv" style="background-color: #f0f0f0; padding-right: 10px"><pre style="line-height: 125%"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92</pre></div></td><td class="code"><div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #AA22FF; font-weight: bold">Program </span>CubConv
<span style="color: #00BB00; font-weight: bold">integer </span>i, j, NgrdX, NgrdY, Nx, Ny
<span style="color: #00BB00; font-weight: bold">real</span><span style="color: #666666">*8</span> Xmin, Ymin, Xmax, Ymax, dXgrd, dYgrd, x, y, dx, dy, Rtmp, &
& F, CubConvInterp
<span style="color: #00BB00; font-weight: bold">real</span><span style="color: #666666">*8</span>, <span style="color: #AA22FF; font-weight: bold">allocatable::</span> Zxy(:,:)
<span style="color: #008800; font-style: italic">! 对最高二次的函数,插值应该给出精确值,故用作测试</span>
F(x, y) <span style="color: #666666">=</span> (x<span style="color: #666666">*</span>x<span style="color: #666666">+</span>y<span style="color: #666666">*</span>y)
<span style="color: #008800; font-style: italic">! 原始网格设定</span>
NgrdX <span style="color: #666666">=</span> <span style="color: #666666">3</span>
NgrdY <span style="color: #666666">=</span> <span style="color: #666666">3</span>
dXgrd <span style="color: #666666">=</span> <span style="color: #666666">2.</span>D0
dYgrd <span style="color: #666666">=</span> <span style="color: #666666">2.</span>D0
Xmin <span style="color: #666666">=</span> <span style="color: #666666">-1.</span>D0
Ymin <span style="color: #666666">=</span> <span style="color: #666666">-1.</span>D0
Xmax <span style="color: #666666">=</span> Xmin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(NgrdX<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dXgrd
Ymax <span style="color: #666666">=</span> Ymin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(NgrdY<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dYgrd
<span style="color: #AA22FF; font-weight: bold">allocate</span>(Zxy(<span style="color: #666666">0</span>:NgrdX<span style="color: #666666">+2</span>, <span style="color: #666666">0</span>:NgrdY<span style="color: #666666">+2</span>))
<span style="color: #008800; font-style: italic">! 获取网格节点</span>
Zxy <span style="color: #666666">=</span> <span style="color: #666666">0.</span>D0
<span style="color: #AA22FF; font-weight: bold">do </span>i<span style="color: #666666">=1</span>, NgrdX
x <span style="color: #666666">=</span> Xmin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(i<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dXgrd
<span style="color: #AA22FF; font-weight: bold">do </span>j<span style="color: #666666">=1</span>, NgrdY
y <span style="color: #666666">=</span> Ymin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(j<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dYgrd
Zxy(i, j) <span style="color: #666666">=</span> F(x, y)
<span style="color: #AA22FF; font-weight: bold">end do</span>
<span style="color: #AA22FF; font-weight: bold"> end do</span>
<span style="color: #008800; font-style: italic">! 处理边界点,三阶精度</span>
Zxy(<span style="color: #666666">0</span>, <span style="color: #666666">1</span>:NgrdY) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>( Zxy(<span style="color: #666666">1</span>, <span style="color: #666666">1</span>:NgrdY)<span style="color: #666666">-</span>Zxy(<span style="color: #666666">2</span>, <span style="color: #666666">1</span>:NgrdY) )<span style="color: #666666">+</span>Zxy(<span style="color: #666666">3</span>, <span style="color: #666666">1</span>:NgrdY)
Zxy(<span style="color: #666666">1</span>:NgrdX, <span style="color: #666666">0</span>) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>( Zxy(<span style="color: #666666">1</span>:NgrdX, <span style="color: #666666">1</span>)<span style="color: #666666">-</span>Zxy(<span style="color: #666666">1</span>:NgrdX, <span style="color: #666666">2</span>) )<span style="color: #666666">+</span>Zxy(<span style="color: #666666">1</span>:NgrdX, <span style="color: #666666">3</span>)
Zxy(NgrdX<span style="color: #666666">+1</span>, <span style="color: #666666">1</span>:NgrdY) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>(Zxy(NgrdX, <span style="color: #666666">1</span>:NgrdY)<span style="color: #666666">-</span>Zxy(NgrdX<span style="color: #666666">-1</span>, <span style="color: #666666">1</span>:NgrdY)) &
& <span style="color: #666666">+</span>Zxy(NgrdX<span style="color: #666666">-2</span>, <span style="color: #666666">1</span>:NgrdY)
Zxy(<span style="color: #666666">1</span>:NgrdX, NgrdY<span style="color: #666666">+1</span>) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>(Zxy(<span style="color: #666666">1</span>:NgrdX, NgrdY)<span style="color: #666666">-</span>Zxy(<span style="color: #666666">1</span>:NgrdX, NgrdY<span style="color: #666666">-1</span>)) &
& <span style="color: #666666">+</span>Zxy(<span style="color: #666666">1</span>:NgrdX, NgrdY<span style="color: #666666">-2</span>)
Zxy(<span style="color: #666666">0</span>, <span style="color: #666666">0</span>) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>( Zxy(<span style="color: #666666">1</span>, <span style="color: #666666">0</span>)<span style="color: #666666">-</span>Zxy(<span style="color: #666666">2</span>, <span style="color: #666666">0</span>) )<span style="color: #666666">+</span>Zxy(<span style="color: #666666">3</span>, <span style="color: #666666">0</span>)
Zxy(NgrdX<span style="color: #666666">+1</span>, <span style="color: #666666">0</span>) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>( Zxy(NgrdX, <span style="color: #666666">0</span>)<span style="color: #666666">-</span>Zxy(NgrdX<span style="color: #666666">-1</span>, <span style="color: #666666">0</span>) )<span style="color: #666666">+</span>Zxy(NgrdX<span style="color: #666666">-2</span>, <span style="color: #666666">0</span>)
Zxy(<span style="color: #666666">0</span>, NgrdY<span style="color: #666666">+1</span>) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>( Zxy(<span style="color: #666666">0</span>, NgrdY)<span style="color: #666666">-</span>Zxy(<span style="color: #666666">0</span>, NgrdY<span style="color: #666666">-1</span>) )<span style="color: #666666">+</span>Zxy(<span style="color: #666666">0</span>, NgrdY<span style="color: #666666">-2</span>)
Zxy(NgrdX<span style="color: #666666">+1</span>, NgrdY<span style="color: #666666">+1</span>) <span style="color: #666666">=</span> <span style="color: #666666">3.</span>D0<span style="color: #666666">*</span>(Zxy(NgrdX, NgrdY<span style="color: #666666">+1</span>)<span style="color: #666666">-</span>Zxy(NgrdX<span style="color: #666666">-1</span>, NgrdY<span style="color: #666666">+1</span>)) &
& <span style="color: #666666">+</span>Zxy(NgrdX<span style="color: #666666">-2</span>, NgrdY<span style="color: #666666">+1</span>)
<span style="color: #008800; font-style: italic">! 改变网格,测试插值,误差应为0</span>
Nx <span style="color: #666666">=</span> <span style="color: #666666">50</span>
Ny <span style="color: #666666">=</span> <span style="color: #666666">50</span>
dx <span style="color: #666666">=</span> (Xmax<span style="color: #666666">-</span>Xmin)<span style="color: #666666">/</span><span style="color: #AA22FF">dble</span>(Nx<span style="color: #666666">-1</span>)
dy <span style="color: #666666">=</span> (Ymax<span style="color: #666666">-</span>Ymin)<span style="color: #666666">/</span><span style="color: #AA22FF">dble</span>(Ny<span style="color: #666666">-1</span>)
<span style="color: #AA22FF; font-weight: bold">do </span>i<span style="color: #666666">=1</span>, Nx
x <span style="color: #666666">=</span> Xmin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(i<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dx
<span style="color: #AA22FF; font-weight: bold">do </span>j<span style="color: #666666">=1</span>, Ny
y <span style="color: #666666">=</span> Ymin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(j<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dy
Rtmp <span style="color: #666666">=</span> CubConvInterp(x, y, Xmin, Ymin, dXgrd, dYgrd, NgrdX, NgrdY, Zxy)
<span style="color: #AA22FF; font-weight: bold">write</span>(<span style="color: #666666">*</span>, <span style="color: #BB4444">'</span>(<span style="color: #666666">5</span>F18.<span style="color: #666666">9</span>)<span style="color: #BB4444">'</span>) x, y, F(x, y), Rtmp, Rtmp<span style="color: #666666">-</span>F(x, y)
<span style="color: #AA22FF; font-weight: bold">end do</span>
<span style="color: #AA22FF; font-weight: bold"> end do</span>
<span style="color: #AA22FF; font-weight: bold">End Program </span>CubConv
<span style="color: #008800; font-style: italic">!</span>
<span style="color: #008800; font-style: italic">!</span>
<span style="color: #00BB00; font-weight: bold">Real</span><span style="color: #666666">*8</span> <span style="color: #AA22FF; font-weight: bold">Function </span>CubConvInterp(Xpos, Ypos, Xmin, Ymin, dXgrd, dYgrd, Nx, Ny, Zxy)
<span style="color: #00BB00; font-weight: bold">integer </span>i, j, Nx, Ny
<span style="color: #00BB00; font-weight: bold">real</span><span style="color: #666666">*8</span> Xpos, Ypos, Xmin, Ymin, dXgrd, dYgrd, u, v, Zxy(<span style="color: #666666">0</span>:Nx<span style="color: #666666">+2</span>, <span style="color: #666666">0</span>:Ny<span style="color: #666666">+2</span>), &
& X(<span style="color: #666666">4</span>), Y(<span style="color: #666666">4</span>), C(<span style="color: #666666">4</span>, <span style="color: #666666">4</span>), D(<span style="color: #666666">4</span>, <span style="color: #666666">4</span>), DX(<span style="color: #666666">4</span>), DY(<span style="color: #666666">4</span>), CDX(<span style="color: #666666">4</span>)
<span style="color: #AA22FF; font-weight: bold">data </span>D(<span style="color: #666666">1</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">/</span> <span style="color: #666666">-1.</span>D0, <span style="color: #666666">2.</span>D0, <span style="color: #666666">-1.</span>D0, <span style="color: #666666">0.</span>D0 <span style="color: #666666">/</span>
<span style="color: #AA22FF; font-weight: bold">data </span>D(<span style="color: #666666">2</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">/</span> <span style="color: #666666">3.</span>D0, <span style="color: #666666">-5.</span>D0, <span style="color: #666666">0.</span>D0, <span style="color: #666666">2.</span>D0 <span style="color: #666666">/</span>
<span style="color: #AA22FF; font-weight: bold">data </span>D(<span style="color: #666666">3</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">/</span> <span style="color: #666666">-3.</span>D0, <span style="color: #666666">4.</span>D0, <span style="color: #666666">1.</span>D0, <span style="color: #666666">0.</span>D0 <span style="color: #666666">/</span>
<span style="color: #AA22FF; font-weight: bold">data </span>D(<span style="color: #666666">4</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">/</span> <span style="color: #666666">1.</span>D0, <span style="color: #666666">-1.</span>D0, <span style="color: #666666">0.</span>D0, <span style="color: #666666">0.</span>D0 <span style="color: #666666">/</span>
i <span style="color: #666666">=</span> <span style="color: #AA22FF">int</span>((Xpos<span style="color: #666666">-</span>Xmin)<span style="color: #666666">/</span>dXgrd)<span style="color: #666666">+1</span>
j <span style="color: #666666">=</span> <span style="color: #AA22FF">int</span>((Ypos<span style="color: #666666">-</span>Ymin)<span style="color: #666666">/</span>dYgrd)<span style="color: #666666">+1</span>
u <span style="color: #666666">=</span> (Xpos<span style="color: #666666">-</span>(Xmin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(i<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dXgrd))<span style="color: #666666">/</span>dXgrd
v <span style="color: #666666">=</span> (Ypos<span style="color: #666666">-</span>(Ymin<span style="color: #666666">+</span><span style="color: #AA22FF">dble</span>(j<span style="color: #666666">-1</span>)<span style="color: #666666">*</span>dYgrd))<span style="color: #666666">/</span>dYgrd
C(<span style="color: #666666">1</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">=</span> [ Zxy(i<span style="color: #666666">-1</span>, j<span style="color: #666666">-1</span>), Zxy(i, j<span style="color: #666666">-1</span>), Zxy(i<span style="color: #666666">+1</span>, j<span style="color: #666666">-1</span>), Zxy(i<span style="color: #666666">+2</span>, j<span style="color: #666666">-1</span>) ]
C(<span style="color: #666666">2</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">=</span> [ Zxy(i<span style="color: #666666">-1</span>, j ), Zxy(i, j ), Zxy(i<span style="color: #666666">+1</span>, j ), Zxy(i<span style="color: #666666">+2</span>, j ) ]
C(<span style="color: #666666">3</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">=</span> [ Zxy(i<span style="color: #666666">-1</span>, j<span style="color: #666666">+1</span>), Zxy(i, j<span style="color: #666666">+1</span>), Zxy(i<span style="color: #666666">+1</span>, j<span style="color: #666666">+1</span>), Zxy(i<span style="color: #666666">+2</span>, j<span style="color: #666666">+1</span>) ]
C(<span style="color: #666666">4</span>, <span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">=</span> [ Zxy(i<span style="color: #666666">-1</span>, j<span style="color: #666666">+2</span>), Zxy(i, j<span style="color: #666666">+2</span>), Zxy(i<span style="color: #666666">+1</span>, j<span style="color: #666666">+2</span>), Zxy(i<span style="color: #666666">+2</span>, j<span style="color: #666666">+2</span>) ]
X(<span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">=</span> [u<span style="color: #666666">*</span>u<span style="color: #666666">*</span>u, u<span style="color: #666666">*</span>u, u, <span style="color: #666666">1.</span>D0]
Y(<span style="color: #666666">1</span>:<span style="color: #666666">4</span>) <span style="color: #666666">=</span> [v<span style="color: #666666">*</span>v<span style="color: #666666">*</span>v, v<span style="color: #666666">*</span>v, v, <span style="color: #666666">1.</span>D0]
DX <span style="color: #666666">=</span> <span style="color: #AA22FF">matmul</span>(D, X)
DY <span style="color: #666666">=</span> <span style="color: #AA22FF">matmul</span>(D, Y)
CDX <span style="color: #666666">=</span> <span style="color: #AA22FF">matmul</span>(C, DX)
CubConvInterp <span style="color: #666666">=</span> <span style="color: #666666">0.25</span>D0<span style="color: #666666">*</span><span style="color: #AA22FF">dot_product</span>(DY, CDX)
<span style="color: #AA22FF; font-weight: bold">End Function </span>CubConvInterp
</pre></div>
</td></tr></table>注意
如果需要计算任意位置的导数, 需要直接利用插值公式的导数来计算, 而不能先求出每个节点的导数再对导数进行插值.
参考
- 韩复兴, 孙建国, 杨昊. 基于二维三次卷积插值算法的波前构建射线追踪. 吉林大学学报(地球科学版), 38(2), 2008.
- 李清, 侯永军, 沈春林. 数字地形数据的二维三次卷积插值. 南京航空航天大学学报, 29(4), 1997.
- 二维三次卷积插值算法