文章目录
在图像缩放领域,bicubic双立方插值算法一般是4抽头,而为了取得更好的画质,增加到6抽头或8抽头时,往往会采用lanczos(兰佐斯)插值算法。但是如果直接使用lanczos插值系数则会出现振铃现象,就是指放大或插值过程中,图像锐利边缘附近出现明暗交替的"波纹"或"鬼影"伪影,本质是插值核(如Sinc、Lanczos)的振荡特性与灰度阶跃卷积引发的吉布斯现象。吉布斯现象------有限带宽逼近不连续信号必然在跳变点附近产生约9%过冲及振铃;并非错误,而是数学必然。

1.放大振铃现象
1.1系数产生
为了用FPGA实现6抽头,16相位的lanczos插值算法,用python代码产生了一组系数,代码如下。
python
import math
# Parameters
PHASE_NUM = 16
TAP_NUM = 6
a = TAP_NUM/2
SCALE = 2 ** 14
init_phase = -0.1/PHASE_NUM
def sinc(x):
if abs(x) < 1e-10:
return 1.0
return math.sin(math.pi *x) / (math.pi * x)
def lanczos(x):
if abs(x) >= a:
return 0.0
return sinc(x) * sinc(x / a)
# Generate coefficients
coeff_fixed = []
for phase in range(PHASE_NUM):
frac = phase / PHASE_NUM
for i in [-2, -1, 0, 1, 2, 3]:
t = lanczos(i - frac + init_phase)
it = int(t * SCALE)
coeff_fixed.append(it)
for j in range(0,PHASE_NUM):
print(f"phase[{j:2d}] = ", end="")
for i in range(0,TAP_NUM):
print(f"{coeff_fixed[j*TAP_NUM+i]:<5d}, ", end="")
print("")
生成的系数放大2^14倍,用于verilog代码使用。
powershell
phase[ 0] = 20 , -83 , 16382, 85 , -21 , 0 ,
phase[ 1] = 206 , -840 , 16242, 1018 , -257 , 8 ,
phase[ 2] = 346 , -1444, 15873, 2087 , -529 , 33 ,
phase[ 3] = 442 , -1896, 15285, 3274 , -828 , 72 ,
phase[ 4] = 495 , -2201, 14495, 4558 , -1142, 126 ,
phase[ 5] = 510 , -2368, 13525, 5914 , -1457, 191 ,
phase[ 6] = 493 , -2412, 12402, 7311 , -1756, 262 ,
phase[ 7] = 451 , -2347, 11157, 8716 , -2020, 336 ,
phase[ 8] = 391 , -2194, 9823 , 10096, -2231, 404 ,
phase[ 9] = 321 , -1971, 8436 , 11414, -2368, 461 ,
phase[10] = 248 , -1698, 7029 , 12637, -2412, 499 ,
phase[11] = 177 , -1394, 5638 , 13732, -2345, 510 ,
phase[12] = 114 , -1079, 4295 , 14668, -2151, 487 ,
phase[13] = 63 , -766 , 3028 , 15419, -1818, 426 ,
phase[14] = 27 , -472 , 1863 , 15965, -1336, 322 ,
phase[15] = 5 , -207 , 820 , 16289, -701 , 172 ,
1.2modelsim仿真效果图
对于文字,边框类图片,边缘比较明显。下面是水平垂直都放大2倍后的图,边缘不平滑,出现明暗相间的情况。

对于彩色图像,也会有可能出现边缘变亮变暗的情况。

2.振铃现象改善
2.1系数产生
为了解决振铃现象,最简单的方法就是给Lanczos 核加窗,牺牲一点锐度,压制吉布斯振铃。在原始 Lanczos 权重上,再乘一个窗函数,把核两端权重压到更低,削弱震荡。 直接在系数生成阶段修改,不用改卷积逻辑。常用的窗有汉宁窗 Hanning,汉明窗 Hamming,布莱克曼窗 Blackman。
这里采用布莱克曼窗(Blackman Window),修改系数生成代码,
python
import math
# Parameters
PHASE_NUM = 16
TAP_NUM = 6
a = TAP_NUM/2
SCALE = 2 ** 14
init_phase = -0.1/PHASE_NUM
def sinc(x):
if abs(x) < 1e-10:
return 1.0
return math.sin(math.pi *x) / (math.pi * x)
def lanczos(x):
if abs(x) >= a:
return 0.0
return sinc(x) * sinc(x / a)
def blkman_win(x):
if abs(x) >= a:
return 0.0
return 0.42 + 0.5*math.cos(math.pi * x / 3) + 0.08 * math.cos(2*math.pi * x / 3)
# Generate coefficients
coeff_fixed = []
for phase in range(PHASE_NUM):
frac = phase / PHASE_NUM
for i in [-2, -1, 0, 1, 2, 3]:
t = lanczos(i - frac + init_phase) * blkman_win(i)
it = int(t * SCALE)
coeff_fixed.append(it)
for j in range(0,PHASE_NUM):
print(f"phase[{j:2d}] = ", end="")
for i in range(0,TAP_NUM):
print(f"{coeff_fixed[j*TAP_NUM+i]:<5d}, ", end="")
print("")
生成的系数放大2^14倍,用于verilog代码使用。
powershell
phase[ 0] = 2 , -52 , 16382, 53 , -2 , 0 ,
phase[ 1] = 26 , -529 , 16242, 641 , -33 , 0 ,
phase[ 2] = 45 , -910 , 15873, 1315 , -68 , 0 ,
phase[ 3] = 57 , -1194, 15285, 2062 , -107 , 0 ,
phase[ 4] = 64 , -1386, 14495, 2872 , -148 , 0 ,
phase[ 5] = 66 , -1492, 13525, 3726 , -189 , 0 ,
phase[ 6] = 64 , -1519, 12402, 4605 , -228 , 0 ,
phase[ 7] = 58 , -1479, 11157, 5491 , -262 , 0 ,
phase[ 8] = 50 , -1382, 9823 , 6360 , -290 , 0 ,
phase[ 9] = 41 , -1242, 8436 , 7191 , -307 , 0 ,
phase[10] = 32 , -1070, 7029 , 7961 , -313 , 0 ,
phase[11] = 23 , -878 , 5638 , 8651 , -304 , 0 ,
phase[12] = 14 , -679 , 4295 , 9241 , -279 , 0 ,
phase[13] = 8 , -483 , 3028 , 9714 , -236 , 0 ,
phase[14] = 3 , -297 , 1863 , 10058, -173 , 0 ,
phase[15] = 0 , -130 , 820 , 10262, -91 , 0 ,
2.2modelsim仿真效果图
文字,边框类图片,放大边缘改善比较明显。

彩色图像边缘也有改善。

3.其他改善措施
除了修改系数,其他还有一些改善的方法。不过这些方法会增加一些额外的资源。
3.1局部数值限制
对卷积输出结果做值域钳位:把插值输出限制在当前 6 个输入像素的最大值、最小值之间。原理:Lanczos 振铃会产生超出原图明暗范围的像素,强行钳位就能切掉波纹。
3.2边缘检测和动态切换插值核
(1)用简单梯度算子检测当前区域是否为强边缘;
(2)平坦区域:用标准 Lanczos(保细节);
(3)强边缘区域:自动切换为加窗 Lanczo。
此方法消耗资源最多,往往不会使用。
3.3后处理滤波
缩放结束后,串一级小型平滑滤波,压制残留振铃:
(1)3-tap 一维均值 / 高斯滤波(行方向)
(2)中值滤波(对椒盐状振铃、细线鬼影效果好)
缺点:会轻微模糊整体画面,一般作为辅助手段,不做主方案。
3.4图像边界补边
(1)重复边缘像素 Repeat(最常用,FPGA 首选)
超出窗口的像素,直接复用画面最边缘像素。 例:最左侧 6-tap 窗口缺左侧像素 → 全部用第一列像素填充。逻辑简单、无跳变、抑制边界振铃效果好。
(2)镜像翻转 Mirror(画质最优,高端显示器 / TV 使用)
超出部分镜像反射像素,模拟连续画面,过渡最自然。