首页 > 编程语言 >双线性插值算法及需要注意事项

双线性插值算法及需要注意事项

时间:2023-04-11 21:01:08浏览次数:60  
标签:注意事项 线性插值 Sample 算法 图像 PartX Index1

最近在编程时用到了双线性插值算法,对图像进行缩放。网上有很多这方面的资料,介绍的也算明白。但是,这些文章只介绍了算法,并没有具体说怎么实现以及怎么实现最好,举个例子,你可以按照网上文章的算法自己写一个双线性插值程序,用它对一张图片进行处理,然后再用matlab或者openCV的resize函数对同一张图片进行处理,得到的结果是不一样的,如果源图片较小,效果差距就更大。以下是对于双线性插值的讲解以及上述现象的解释:

 

1.双线性插值

假设源图像大小为mxn,目标图像为axb。那么两幅图像的边长比分别为:m/a和n/b。注意,通常这个比例不是整数,编程存储的时候要用浮点型。目标图像的第(i,j)个像素点(i行j列)可以通过边长比对应回源图像。其对应坐标为(i*m/a,j*n/b)。

显然,这个对应坐标一般来说不是整数,而非整数的坐标是无法在图像这种离散数据上使用的。双线性插值通过寻找距离这个对应坐标最近的四个像素点,来计算该点的值(灰度值或者RGB值)。如果你的对应坐标是(2.5,4.5),那么最近的四个像素是(2,4)、(2,5)、(3,4),(3,5)。

若图像为灰度图像,那么(i,j)点的灰度值可以通过一下公式计算:

f(i,j)=w1*p1+w2*p2+w3*p3+w4*p4;

其中,pi(i=1,2,3,4)为最近的四个像素点,wi(i=1,2,3,4)为各点相应权值。关于权值的计算,在维基百科和百度百科上写的很明白。

 

2.存在的问题

这部分的前提是,你已经明白什么是双线性插值并且在给定源图像和目标图像尺寸的情况下,可以用笔计算出目标图像某个像素点的值。当然,最好的情况是你已经用某种语言实现了网上一大堆博客上原创或转载的双线性插值算法,然后发现计算出来的结果和matlab、openCV对应的resize()函数得到的结果完全不一样。

那这个究竟是怎么回事呢?

其实答案很简单,就是坐标系的选择问题,或者说源图像和目标图像之间的对应问题。

按照网上一些博客上写的,源图像和目标图像的原点(0,0)均选择左上角,然后根据插值公式计算目标图像每点像素,假设你需要将一幅5x5的图像缩小成3x3,那么源图像和目标图像各个像素之间的对应关系如下:

只画了一行,用做示意,从图中可以很明显的看到,如果选择右上角为原点(0,0),那么最右边和最下边的像素实际上并没有参与计算,而且目标图像的每个像素点计算出的灰度值也相对于源图像偏左偏上。

那么,让坐标加1或者选择右下角为原点怎么样呢?很不幸,还是一样的效果,不过这次得到的图像将偏右偏下。

最好的方法就是,两个图像的几何中心重合,并且目标图像的每个像素之间都是等间隔的,并且都和两边有一定的边距,这也是matlab和openCV的做法。如下图:

如果你不懂我上面说的什么,没关系,只要在计算对应坐标的时候改为以下公式即可,

 

int x=(i+0.5)*m/a-0.5

int y=(j+0.5)*n/b-0.5

 

instead of 

 

 

int x=i*m/a

int y=j*n/b

 

利用上述公式,将得到正确的双线性插值结果

总结:

总结一下,我得到的教训有这么几条。

1.网上的一些资料有的时候并不靠谱,自己还是要多做实验。

2.不要小瞧一些简单的、基本的算法,让你写你未必会写,而且其中可能还藏着一些玄妙。

3.要多动手编程,多体会算法,多看大牛写的源码(虽然有的时候很吃力,但是要坚持看)。

二)转自http://www.cnblogs.com/Imageshop/archive/2011/11/12/2246808.html

 在图像处理中,双线性插值算法的使用频率相当高,比如在图像的缩放中,在所有的扭曲算法中,都可以利用该算法改进处理的视觉效果。首先,我们看看该算法的简介。

     在数学上,双线性插值算法可以看成是两个变量间的线性插值的延伸。执行该过程的关键思路是先在一个方向上执行线性插值,然后再在另外一个方向上插值。下图示意出这个过程的大概意思。

双线性插值算法及需要注意事项_像素点

     用一个简单的数学表达式可以表示如下:

     f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy

     合并有关项,可写为: f(x,y)=(f(0,0)(1-x)+f(1,0)x) (1-y)+(f(0,1)(1-x)+f(1,1)x)y

     由上式可以看出,这个过程存在着大量的浮点数运算,对于图像这样大的计算用户来说,是一个较为耗时的过程。

     考虑到图像的特殊性,他的像素值的计算结果需要落在0到255之间,最多只有256种结果,由上式可以看出,一般情况下,计算出的f(x,y)是个浮点数,我们还需要对该浮点数进行取整。因此,我们可以考虑将该过程中的所有类似于1-x、1-y的变量放大合适的倍数,得到对应的整数,最后再除以一个合适的整数作为插值的结果。

      如何取这个合适的放大倍数呢,要从三个方面考虑,第一:精度问题,如果这个数取得过小,那么经过计算后可能会导致结果出现较大的误差。第二,这个数不能太大,太大会导致计算过程超过长整形所能表达的范围。第三:速度考虑。假如放大倍数取为12,那么算式在最后的结果中应该需要除以12*12=144,但是如果取为16,则最后的除数为16*16=256,这个数字好,我们可以用右移来实现,而右移要比普通的整除快多了。 

      综合考虑上述三条,我们选择2048这个数比较合适。

      下面我们假定某个算法得到了我们要取样的坐标分别PosX以及PosY,其中PosX=25.489,PosY=58.698。则这个过程的类似代码片段如下:

双线性插值算法及需要注意事项_取整_02

双线性插值算法及需要注意事项_双线性插值_03

 1 NewX = Int(PosX)                        '向下取整,NewX=25
 2 NewY = Int(PosY)                        '向下取整,NewY=58
 3 PartX = (PosX - NewX) * 2048            '对应表达式中的X
 4 PartY = (PosY - NewY) * 2048            '对应表达式中的Y
 5 InvX = 2048 - PartX                     '对应表达式中的1-X
 6 InvY = 2048 - PartY                     '对应表达式中的1-Y
 7 
 8 Index1 = SamStride * NewY + NewX * 3    '计算取样点左上角邻近的那个像素点的内存地址
 9 Index2 = Index1 + SamStride          '左下角像素点地址
10 ImageData(Speed + 2) = ((Sample(Index1 + 2) * InvX + Sample(Index1 + 5) * PartX) * InvY + (Sample(Index2 + 2) * InvX + 

                          Sample(Index2 + 5) * PartX) * PartY) \ 4194304       '处理红色分量

11 ImageData(Speed + 1) = ((Sample(Index1 + 1) * InvX + Sample(Index1 + 4) * PartX) * InvY + (Sample(Index2 + 1) * InvX +

                          Sample(Index2 + 4) * PartX) * PartY) \ 4194304       '处理绿色分量
12 ImageData(Speed) = ((Sample(Index1) * InvX + Sample(Index1 + 3) * PartX) * InvY + (Sample(Index2) * InvX +

                      Sample(Index2 + 3) * PartX) * PartY) \ 4194304           '处理蓝色分量

双线性插值算法及需要注意事项_双线性插值_04

双线性插值算法及需要注意事项_取整_05

      以上代码中涉及到的变量都为整型(PosX及PosY当然为浮点型)。

      代码中Sample数组保存了从中取样的图像数据,SamStride为该图像的扫描行大小。

      观察上述代码,除了有2句涉及到了浮点计算,其他都是整数之间的运算。

      在Basic语言中,编译时如果勾选所有的高级优化,则\ 4194304会被编译为>>22,即右移22位,如果使用的是C语言,则直接写为>>22。

      需要注意的是,在进行这代代码前,需要保证PosX以及PosY在合理的范围内,即不能超出取样图像的宽度和高度范围。

      通过这样的改进,速度较直接用浮点类型快至少100%以上,而处理后的效果基本没有什么区别。

标签:注意事项,线性插值,Sample,算法,图像,PartX,Index1
From: https://blog.51cto.com/u_14682436/6183903

相关文章

  • MATLAB代码:基于粒子群算法的储能优化配置
    MATLAB代码:基于粒子群算法的储能优化配置关键词:储能优化配置粒子群 储能充放电优化主要内容:建立了储能的成本模型,包含运行维护成本以及容量配置成本,然后以该成本函数最小为目标函数,经过粒子群算法求解出其最优运行计划,并通过其运行计划最终确定储能容量配置的大小,求解采用的......
  • MATLAB代码:基于改进粒子群算法的微网多目标优化调度
    MATLAB代码:基于改进粒子群算法的微网多目标优化调度关键词:微网多目标优化调度粒子群算法仿真平台:matlab主要内容:代码提出了一种综合考虑微电网系统运行成本和环境保护成本的并网模式下微电网多目标优化调度模型。同时采用改进的粒子群算法对优化模型进行求解,具体改进的......
  • 基于PSO粒子群算法优化RBF网络的数据预测matlab仿真
    1.算法描述      1985年,Powell提出了多变量插值的径向基函数(RBF)方法。径向基函数是一个取值仅仅依赖于离原点距离的实值函数,也可以是到任意一点c的距离,c点称为中心点。任意满足上述特性的函数,都可以叫做径向基函数。一般使用欧氏距离计算距离中心点的距离(欧式径向基函数)。......
  • 基于MPPT算法的PV光伏阵列电网模型simulink仿真
    1.算法描述       光伏阵列(PhotovoltaicArray)是多片光伏模组的连接,也是更多光伏电池的连接,光伏阵列是最大规模的光伏发电系统。太阳能电池透过光生伏特效应可以将太阳光能转化成直流电能,但一块光伏模组(光伏板)能够产生的电流不够一般住宅使用,所以将数块光伏模组连接在......
  • m基于GA遗传优化和OSPF协议的WSN最短路由算法matlab仿真,并输出节点的不同层域
    1.算法仿真效果matlab2022a仿真结果如下:    2.算法涉及理论知识概要2.1GA遗传优化        GA把问题的解表示成“染色体”,在算法中也即是以二进制编码的串。并且,在执行遗传算法之前,给出一群“染色体”,也即是假设解。然后,把这些假设解置于问题的“环境”中,并按......
  • 数字水印_最低有效位算法
    数字水印_最低有效位算法原文链接:https://blog.csdn.net/chengfenglee/article/details/123771536最低有效位(LeastSignificantBit.,LSB)指的是一个二进制数中的第0位(即最低位)最低有效位信息隐藏指的是,将一个需要隐藏的二值图像信息嵌入载体图像的最低有效位,即将载......
  • 主题:基于改进A3C算法的微网优化调度与需求响应管理
    关键词:微网优化调度 深度强化学习 A3C 需求响应  编程语言:python平台主题:基于改进A3C算法的微网优化调度与需求响应管理内容简介:代码主要做的是基于深度强化学习的微网虚拟电厂优化调度策略研究,微网的聚合单元包括风电机组,储能单元,温控负荷(空调、热水器)以及需求响......
  • MATLAB代码:基于SOE算法的多时段随机配电网重构方法
    MATLAB代码:基于SOE算法的多时段随机配电网重构方法关键词:配电网重构SOE算法多时段随机重构  仿真平台:MATLAB+CPLEXgurobi平台优势:代码具有一定的深度和创新性,注释清晰主要内容:代码主要做的是一个通过配电网重构获取最优网络拓扑的问题,从而有效降低网损,提高经济效益,同时......
  • 【LeetCode回溯算法#extra01】集合划分问题【火柴拼正方形、划分k个相等子集、公平发
    火柴拼正方形https://leetcode.cn/problems/matchsticks-to-square/你将得到一个整数数组matchsticks,其中matchsticks[i]是第i个火柴棒的长度。你要用所有的火柴棍拼成一个正方形。你不能折断任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须使用一次。如......
  • Java中常用算法及示例-分治、迭代、递归、递推、动态规划、回溯、穷举、贪心
    场景1、分治算法的基本思想是将一个计算复杂的问题分成规模较小、计算简单的小问题求解,然后综合各个小问题,得到最终答案。2、穷举(又称枚举)算法的基本思想是从所有可能的情况中搜索正确的答案。3、迭代法(IterativeMethod)无法使用公式一次求解,而需要使用重复结构(即循环)......