图解图像四点插值算法
四点插值的目的
四点插值主要的意义就是通过已知的点的灰度值来计算推导未知点的灰度值,以求把小的图片显示到大的显示区域内(主要就是通过插值算法补充没有数据点的像素点的灰度值),同时,适当且准确的插值可以最大程度上不改变图像的实际信息同时增加细节,提升观感,注意,如果插值算法选取合适,可以认为插出来的点包含的信息可以替代没有被我们捕捉到的原始图像的信息。接下来介绍四点插值的算法。
注:正常情况下,横向的两点插值可以起到扩宽图像的效果,比方说原来的图像只有240个像素点的信息,每两个点之间插入一个点之后,总的图像总共成了479个像素点,处理后变成了480个像素的宽度(最后一个像素可以选择保留前一像素的灰度值),相当于宽度扩宽了一倍,但同时,单纯的两点横向插值只在一个方向上有拉伸,容易导致横线的出现(纵向上一些灰度值接近的像素点相比之下是压缩了,所以会呈现出可见的横线),那么为了把“压缩”的纵向像素点拉伸,我们采取了四点插值。这样在横纵向上都有相同比例的拉伸,自然不会出现集中的短线的情况。
四点插值的本质原理及图解
四点插值可以分解为三次两点插值,首先分别两点插值求得A’和B’的灰度值,然后用这两个灰度值插出E的灰度值,这也是为什么教科书上介绍四点插值一般采用十字形的例子的原因。
这里的h0到h3都可以理解为是像素的数目。
工程化会遇到的问题
好了,理论上的分析到此结束了,到了工程化的部分,这个部分需要注意的问题其实就只有一个,如何正确地表示你想表示的图像的像素点。
与matlab不同的是,工程化语言例如c和c++内部,数据是按照连续的地址存储的,而matlab可以直接把图像转化为一个矩阵,但实际计算机内部还是按照连续地址存储图像数据的,只是matlab帮助我们实现了连续内存到矩阵的转化(这么一想再结合matlab封装的函数不得不感叹matlab用于仿真是真的好用,可惜我们学校买的正版没法用了)。
内存与像素值矩阵的关系
接下来来展示内存和像素取值之间的关系:
内存中存储的图片是按照一定的顺序在连续的地址空间中存储的,例如左边存的数据对应到右边就相当于从这幅3*3像素图片的左上角从左到右从上到下存储的数据。在内存中,读取相应点的灰度值要通过控制指针来读取的。
简单情况的举例
用最简单的情况来举例,如果我们打算在灰度值123的像素和灰度值为0的像素之间插入一个新的像素,要赋给它一个灰度值,公式上的体现为
g(new)=1/2*123+1/2*0
这里之所以是二分之一是因为我们只需要插入一个像素点,这个像素点到已知的两个像素点的距离是相同的,所以权值都是二分之一。如果计算出了小数,一般会选择向下取整不易造成错误。
新的例子
新例子,如果我们要在两个像素点之间插入三个新的像素点,要怎么计算权值呢如下图所示:
回忆一下,因为2号像素距离两个已知像素的值还是相同的,所以公式不变,但对于1号和三号像素,显然权值是不同的,1号像素更偏向灰度值为123的像素,所以灰度值自然要大一些,3号则相应的灰度值要小一些。
再具体一点,计算3号像素的灰度值,我们可以用位于中心的2号像素的灰度值作为一个参考,2号像素理论上计算得到的灰度值是123的一半,也就是61.5,向下取整得到整数部分61即为2号像素点的灰度值。小数部分(0.5)取出来后面使用。
可以看到,现在实际上我们求得1号像素点的灰度值可以用2号像素点平均出来!
但是为了计算方便,我们常把小数部分定义为h0(即本例中的0.5,添加的像素越多,此值不一定是0.5),h1=1-h0,这样再套用上面的公式计算就可以啦。
回到最初的问腿,计算机内存村图片和我们熟知的矩阵方式是有区别的,那要怎么实现一一对应呢,答案就在于指针!
如果要切换列,例如从灰度值为123的像素切换到灰度为0的像素,我们只需要把指针向后偏移一列数据长度数的单元即可(本例中为向后偏移三个单元)。如果要从123切换到159,指针向后偏移一个单元即可。
以上就是我理解的四点插值的基本原理和涉及到工程实现的相关问题的解析,如果有不对的地方还请多多指正!后续如果有需要的话我会再补充8点插值和16点插值相关的方法。