目录

  • 双线性插值(Bilinear Interpolation)
    • 线性插值
    • 双线性插值
  • 深入理解双线性插值
    • 我的插值理解
    • 代码
    • 官方插值办法
    • 源图像和目标图像几何中心的对齐
    • 将浮点运算转换成整数运算
    • 代码
    • 效果对比
    • 再次深入理解
  • 引用

双线性插值(Bilinear Interpolation)

  • 双线性插值是实现上采样的一种手段,关于它的知识其实非常非常简单,但是很多博客写的比较晦涩难懂,这里简单介绍一下双线性插值究竟做了什么。
  • 首先双线性插值是用来放大图像的,但是我们都知道既然要放大图像,其实是对图像的像素进行扩充,而双线性插值就是使用已有的像素点来计算其他像素点从而实现像素的扩充,也就是说双线性插值是在像素层面的计算。
  • 下面让我们先来看看什么是线性插值:

线性插值

  • 先讲一下线性插值:已知数据 (x0, y0) 与 (x1, y1),要计算 [x0, x1] 区间内某一位置 x 在直线上的y值(反过来也是一样,略):

    上面比较好理解吧,仔细看就是用x和x0,x1的距离作为一个权重,用于y0和y1的加权。双线性插值本质上就是在两个方向上做线性插值。
  • 上面讲的实在是很清楚了,再来让我们看看双线性插值,其实没什么了不起的,就是从两个方向进行了插值。

双线性插值

  • 这种方法特点是不需要进行学习,运行速度快,操作简单。只需要设置好固定的参数值即可,设置的参数就是中心值需要乘以的系数。
  • 双线性插值,这个名字咋一听很高大上的样纸,再在维基百科上一查(见文末,我去,一堆的公式吓死人),像俺这种半文盲,看到公式脑子就懵的类型,真心给跪。虽然看着好复杂,但仔细一看道理再简单不过了,所以还是自己梳理一下好。
  • 双线性插值,顾名思义就是两个方向的线性插值加起来(这解释过于简单粗暴,哈哈)。所以只要了解什么是线性插值,分别在x轴和y轴都做一遍,就是双线性插值了。
  • 如A点坐标(0,0),值为3,B点坐标(0,2),值为5,那要对坐标为(0,1)的点C进行插值,就让C落在AB线上,值为4就可以了。
  • 但是如果C不在AB的线上肿么办捏,所以就有了双线性插值。如图,

    已知Q12,Q22,Q11,Q21,但是要插值的点为P点,这就要用双线性插值了,首先在x轴方向上,对R1和R2两个点进行插值,这个很简单,然后根据R1和R2对P点进行插值,这就是所谓的双线性插值。
  • 方法:
  • 咱们看一下完整公式推导:
  • 下面重点来了:

    由于咱们的像素间隔都是1,所以括号外面的分母(x2-x1)(y2-y1)=1,所以
    上式=f(Q11)(x2−x)(y2−y)+f(Q21)(x−x1)(y2−y)+f(Q12)(x2−x)(y−y1)+f(Q22)(x−x1)(y−y1)上式=f(Q11)(x2-x)(y2-y)+f(Q21)(x-x1)(y2-y)+f(Q12)(x2-x)(y-y1)+f(Q22)(x-x1)(y-y1)上式=f(Q11)(x2−x)(y2−y)+f(Q21)(x−x1)(y2−y)+f(Q12)(x2−x)(y−y1)+f(Q22)(x−x1)(y−y1)
    我们注意观察(x2−x)(y2−y)(x2-x)(y2-y)(x2−x)(y2−y)这个,其实x2−x=1−(x−floor(x))x2-x=1-(x-floor(x))x2−x=1−(x−floor(x)),floor是向下取整,细细品味一下你就会明白这个等式。同理,x−x1=x−floor(x)x-x1=x-floor(x)x−x1=x−floor(x)
    所以我们专门用u、vu、vu、v两个变量记录x−floor(x),y−floor(y)x-floor(x),y-floor(y)x−floor(x),y−floor(y),替换进去后,最终
    上式=f(Q11)(1−u)(1−v)+f(Q21)u(1−v)+f(Q12)(1−u)v+f(Q22)uv上式=f(Q11)(1-u)(1-v)+f(Q21)u(1-v)+f(Q12)(1-u)v+f(Q22)uv上式=f(Q11)(1−u)(1−v)+f(Q21)u(1−v)+f(Q12)(1−u)v+f(Q22)uv

深入理解双线性插值

我的插值理解

  • 通过上面的例子,其实我们能够有所感觉,所谓的插值,不过是通过周围已知的像素值来计算一些原本没有给出的像素值;所谓的线性,是指我们通过线性的方式来用已知像素值计算未知的像素值。这样的话像素值会增多,也就实现了图像的放大。当然我们也可以进行图像的缩小,一样的道理,还是进行插值,只不过需要的像素点少了而已。
  • 这样看来的话,给我们一个像素矩阵,我们应当也是会根据要求来进行插值的。
  • 现在我们来看一个图像放大的例子:

    上图是原来的图像,是3*3的矩阵,而我们的任务是放大到4*4,我们首先需要建立一个坐标系,左上角为(0,0)。通过图像我们可以看到,我们要放大图像的话,其实边界都是之前图像的边界,我们只不过是将原图的边划分成更小的粒度而已,比如上图原来元素之间间隔1,共有3个元素,但我们要想在原来的长度下构成4个元素,那每个元素间隔就是2/3,新矩阵间隔计算公式为**(每边原来的元素数-1)/(目标每边的元素数-1)**,所以我们就可以画出下面的新矩阵:

    黑点的间隔就是2/3,然后利用双线性插值的公式来计算上图每个黑点的像素值就好了。

代码

from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import math
def BiLinear_interpolation(img,dstH,dstW):scrH,scrW,_=img.shapeprint(img.shape)img=np.pad(img,((0,1),(0,1),(0,0)),'constant')print(img.shape)retimg=np.zeros((dstH,dstW,3),dtype=np.uint8)for i in range(dstH):for j in range(dstW):scrx=i*(scrH-1)/(dstH-1)scry=j*(scrW-1)/(dstW-1)x=math.floor(scrx)y=math.floor(scry)u=scrx-xv=scry-yretimg[i,j]=(1-u)*(1-v)*img[x,y]+u*(1-v)*img[x+1,y]+(1-u)*v*img[x,y+1]+u*v*img[x+1,y+1]return retimg
im_path='testPict.png'
image=np.array(Image.open(im_path))
image2=BiLinear_interpolation(image,image.shape[0]*10,image.shape[1]*10)
image2=Image.fromarray(image2.astype('uint8')).convert('RGB')
image2.save('outmy_x10.png')

官方插值办法

  • emmm,怎么说呢,如果你读懂了我的理解之后,你应该知道,我的方法其实是相当于在原图的内部提取出更多的点,从而扩大图像。下面我用同样的例子来展示官方差值的作法:
  • 下面是将3*3扩大成4*4的图像:

    有人可能会说,那边际的红点怎么推测呀,周围的蓝色的点不够4个啊,请看下图:

    猜一下深蓝色的像素点是什么,没错,就是padding的像素点,像素值为0,也就是说只需要padding就好了。
  • 那么如何根据原图计算目标图的像素点分别对应原图的坐标呢?
    srcX=dstX* (srcWidth/dstWidth),
    srcY = dstY* (srcHeight/dstHeight)
    其中(dstX,dsY)是目标图像的像素点的逻辑下标,左上角的点规定为(0,0),srcWidth是原图像的每边像素点的个数,dstWidth是目标图像的每条边像素点的个数,srcX是目标图像像素点(dstX,dstY)对应在原图像的坐标系下的实际坐标,可能不是整数,那就需要插值了。
    经过几何中心对齐后的优化后的公式为:
    SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5
    SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5

源图像和目标图像几何中心的对齐

  • 这是优化措施之一,针对官方的双线性插值方法,在我的方法中双线性插值一开始就是几何中心对齐的。
  • 按照网上一些博客上写的,源图像和目标图像的原点(0,0)均选择左上角,然后根据插值公式计算目标图像每点像素,假设你需要将一幅5x5的图像缩小成3x3,那么源图像和目标图像各个像素之间的对应关系如下:

    只画了一行,用做示意,从图中可以很明显的看到,如果选择右上角为原点(0,0),那么最右边和最下边的像素实际上并没有参与计算,而且目标图像的每个像素点计算出的灰度值也相对于源图像偏左偏上。
    那么,让坐标加1或者选择右下角为原点怎么样呢?很不幸,还是一样的效果,不过这次得到的图像将偏右偏下。
    最好的方法就是,两个图像的几何中心重合,并且目标图像的每个像素之间都是等间隔的,并且都和两边有一定的边距,这也是matlab和openCV的做法。如下图:
  • 分别使用上述提到的公式和几何中心对齐之后的公式进行处理后,就会分别得到上述对应的两幅图,显然使用几何中心对齐的公式更为合理。
  • 看个例子:假设源图像是33,中心点坐标(1,1)目标图像是99,中心点坐标(4,4),我们在进行插值映射的时候,尽可能希望均匀的用到源图像的像素信息,最直观的就是(4,4)映射到(1,1)现在直接计算srcX=4*3/9=1.3333!=1,也就是我们在插值的时候所利用的像素集中在图像的右下方,而不是均匀分布整个图像。现在考虑中心点对齐,srcX=(4+0.5)*3/9-0.5=1,刚好满足我们的要求。

将浮点运算转换成整数运算

  • 这也是优化方法之一。
  • 参考图像处理界双线性插值算法的优化,直接进行计算的话,由于计算的srcX和srcY 都是浮点数,后续会进行大量的乘法,而图像数据量又大,速度不会理想,解决思路是:
      浮点运算→→整数运算→→”<<左右移按位运算”。
    放大的主要对象是u,v这些浮点数,OpenCV选择的放大倍数是2048“如何取这个合适的放大倍数呢,要从三个方面考虑,
      第一:精度问题,如果这个数取得过小,那么经过计算后可能会导致结果出现较大的误差。
      第二,这个数不能太大,太大会导致计算过程超过长整形所能表达的范围。
      第三:速度考虑。假如放大倍数取为12,那么算式在最后的结果中应该需要除以1212=144,但是如果取为16,则最后的除数为1616=256,这个数字好,我们可以用右移来实现,而右移要比普通的整除快多了。”我们利用左移11位操作就可以达到放大目的。

代码

from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import math
def BiLinear_interpolation(img,dstH,dstW):scrH,scrW,_=img.shapeprint(img.shape)img=np.pad(img,((0,1),(0,1),(0,0)),'constant')print(img.shape)retimg=np.zeros((dstH,dstW,3),dtype=np.uint8)for i in range(dstH):for j in range(dstW):scrx=(i+0.5)*(scrH/dstH)-0.5scry=(j+0.5)*(scrW/dstW)-0.5x=math.floor(scrx)y=math.floor(scry)u=scrx-xv=scry-yretimg[i,j]=(1-u)*(1-v)*img[x,y]+u*(1-v)*img[x+1,y]+(1-u)*v*img[x,y+1]+u*v*img[x+1,y+1]return retimg
im_path='testPict.png'
image=np.array(Image.open(im_path))
image2=BiLinear_interpolation(image,image.shape[0]*10,image.shape[1]*10)
image2=Image.fromarray(image2.astype('uint8')).convert('RGB')
image2.save('out0.5_x10.png')

效果对比

  • 我分别运行了下,其实几乎分辨不出来任何区别……不过用我的方法得到的图像占空间比较大。

再次深入理解

在图像的仿射变换中,很多地方需要用到插值运算,常见的插值运算包括最邻近插值,双线性插值,双三次插值,兰索思插值等方法,OpenCV提供了很多方法,其中,双线性插值由于折中的插值效果和运算速度,运用比较广泛。
  越是简单的模型越适合用来举例子,我们就举个简单的图像:3*3 的256级灰度图。假如图像的象素矩阵如下图所示(这个原始图把它叫做源图,Source):
234 38 22
67 44 12
89 65 63
  这 个矩阵中,元素坐标(x,y)是这样确定的,x从左到右,从0开始,y从上到下,也是从零开始,这是图象处理中最常用的坐标系。
  如果想把这副图放大为 4*4大小的图像,那么该怎么做呢?那么第一步肯定想到的是先把4*4的矩阵先画出来再说,好了矩阵画出来了,如下所示,当然,矩阵的每个像素都是未知数,等待着我们去填充(这个将要被填充的图的叫做目标图,Destination):
  ? ? ? ?
  ? ? ? ?
  ? ? ? ?
  ? ? ? ?
  然后要往这个空的矩阵里面填值了,要填的值从哪里来来呢?是从源图中来,好,先填写目标图最左上角的象素,坐标为(0,0),那么该坐标对应源图中的坐标可以由如下公式得出srcX=dstX* (srcWidth/dstWidth) , srcY = dstY * (srcHeight/dstHeight)
  好了,套用公式,就可以找到对应的原图的坐标了(0*(3/4),0*(3/4))=>(0*0.75,0*0.75)=>(0,0),找到了源图的对应坐标,就可以把源图中坐标为(0,0)处的234象素值填进去目标图的(0,0)这个位置了。
  接下来,如法炮制,寻找目标图中坐标为(1,0)的象素对应源图中的坐标,套用公式:
(1*0.75,0*0.75)=>(0.75,0) 结果发现,得到的坐标里面竟然有小数,这可怎么办?计算机里的图像可是数字图像,象素就是最小单位了,象素的坐标都是整数,从来没有小数坐标。这时候采用的一种策略就是采用四舍五入的方法(也可以采用直接舍掉小数位的方法),把非整数坐标转换成整数,好,那么按照四舍五入的方法就得到坐标(1,0),完整的运算过程就是这样的:(1*0.75,0*0.75)=>(0.75,0)=>(1,0) 那么就可以再填一个象素到目标矩阵中了,同样是把源图中坐标为(1,0)处的像素值38填入目标图中的坐标。
  依次填完每个象素,一幅放大后的图像就诞生了,像素矩阵如下所示:
  234 38 22 22
  67 44 12 12
  89 65 63 63
  89 65 63 63
  这种放大图像的方法叫做最临近插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真;效果不好的根源就是其简单的最临近插值方法引入了严重的图像失真,比如,当由目标图的坐标反推得到的源图的的坐标是一个浮点数的时候,采用了四舍五入的方法,直接采用了和这个浮点数最接近的象素的值,这种方法是很不科学的,当推得坐标值为 0.75的时候,不应该就简单的取为1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目标象素值其实应该根据这个源图中虚拟的点四周的四个真实的点来按照一定的规律计算出来的,这样才能达到更好的缩放效果。
  双线型内插值算法就是一种比较好的图像缩放算法,它充分的利用了源图中虚拟点四周的四个真实存在的像素值来共同决定目标图中的一个像素值,因此缩放效果比简单的最邻近插值要好很多。
双线性内插值算法描述如下:
  对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v) (其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。
  比如,象刚才的例子,现在假如目标图的象素坐标为(1,1),那么反推得到的对应于源图的坐标是(0.75 , 0.75), 这其实只是一个概念上的虚拟象素,实际在源图中并不存在这样一个象素,那么目标图的象素(1,1)的取值不能够由这个虚拟象素来决定,而只能由源图的这四个象素共同决定:(0,0)(0,1)(1,0)(1,1),而由于(0.75,0.75)离(1,1)要更近一些,那么(1,1)所起的决定作用更大一些,这从公式1中的系数uv=0.75×0.75就可以体现出来,而(0.75,0.75)离(0,0)最远,所以(0,0)所起的决定作用就要小一些,公式中系数为(1-u)(1-v)=0.25×0.25也体现出了这一特点。

引用

  • https://blog.csdn.net/qq_37577735/article/details/80041586
  • https://blog.csdn.net/never__say__no/article/details/109081233
  • https://www.cnblogs.com/wojianxin/p/12516029.html

双线性插值实现图像缩放详解相关推荐

  1. OpenCV实战(12)——图像滤波详解

    OpenCV实战(12)--图像滤波详解 0. 前言 1. 频域分析 2. 低通滤波器 3. 图像下采样 3.1 使用低通滤波器下采样图像 3.2 内插像素值 4. 中值滤波器 5. 完整代码 小结 ...

  2. JPEG图像压缩算法详解

    转载自 http://www.ibm.com/developerworks/cn/linux/l-cn-jpeg/ JPEG压缩算法之前已有很多前辈详细讲解过,我就不在这里画蛇添足了(主要是我懒..) ...

  3. 【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解

    本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行讲解,主要通过MFC单文档视图实现显示BMP图片空间几何变换,包括图像平移.图形 ...

  4. Windows:缩放设置及DPI缩放详解

    摘要:再次遇到软件在显示器上不能显示完全的情况,同样的分辨率同样的软件,一台显示正常一台显示不全.造成这个原因的是在相同分辨率下其设置不同 缩放 比例问题导致,这里记录一下windwos系统如何设置缩 ...

  5. listen函数的第二个参数_【图像处理】OpenCV系列十七 --- 几何图像变换函数详解(一)...

    上一篇我们学习了仿射变换的warpAffine函数,知道了如何用这个函数对图像进行旋转.平移等操作,那么本节我们一起来学习一下与仿射变换相关的其他函数以及相关的几何图像变换. 一.convertMap ...

  6. android opencv中图像分割,opencv在android平台下的开发【4】-图像滤波详解

    前言 在上一篇opencv-android-图像平滑处理文章中,简单介绍了几种图像平滑,也就是图像模糊的方法,使用了几个简单的滤波器,这都属于图像的滤波操作. opencv针对图像的处理提供了imgp ...

  7. 矩概念与图像矩详解及其hu矩的运用

    一.矩概念详解 矩这个东西,能组成的名词太多了,矩形,就是长方形,矩阵,就是m行n列的二维数组,所以想了解矩,就要从其具体的场景中去理解. 今天我们要讲的图像矩,就是一个新的概念,图像矩就是图像的矩, ...

  8. python怎么画参数函数图像_详解pandas.DataFrame.plot() 画图函数

    首先看官网的DataFrame.plot( )函数 DataFrame.plot(x=None, y=None, kind='line', ax=None, subplots=False, share ...

  9. 基于OpenCV的图像透视变换详解(从理论到实现再到实践)

    一.仿射变换与透视变换 一直无法理解两种仿射变换与透视变换的区别,因此详细学习了两种变换的具体细节,重新书写了公式,并给出自己的一些看法. 1.仿射变换 可以认为,仿射变换是透视变换的一种特例.    ...

最新文章

  1. 单例模式 之 单例模式——Holder
  2. oracle截取字符串
  3. 北大 AI 公开课 2019 | 颜水成:人工智能行业观察与实践
  4. Project Server的页面如何修改Text
  5. mysql 5.1 innodb trx_mysql 优化innodb_flush_log_at_trx_commit的案例介绍
  6. Web前端主要学什么?这些知识要掌握
  7. DevExress笔记
  8. android listview headerview 分割线,【我的Android进阶之旅】如何去除ListView中Header View、Footer View中的分割线...
  9. elementui获取所有树节点_element-ui tree获取子节点全选的父节点信息
  10. 罗永浩“真还传”再出番外篇,被执行1800万,交个朋友回应来了…
  11. 微信域名防红防屏蔽系统的原理 微信域名防屏蔽的注意点
  12. 13.1Question Answering 问答系统意境级讲解
  13. 域内,如何限制一台电脑只能指定的域用户登录
  14. C++11 std::function类模板
  15. vue 插槽的版本变化1.x-2.6.0-3.x(详细)
  16. 怎样看python源代码-如何查看python源代码
  17. 随处可用的坐姿小帮手,还能按摩热敷,荣泰P30按摩坐垫体验
  18. 数字图像处理 信息隐藏 LSB算法
  19. 非负数的正则表达式匹配
  20. 抽35块树莓派新品单片机送给可爱的你们

热门文章

  1. 最全word排版技巧汇总,千万不要错过!
  2. 8小时饮食法,以及8小时饮食法改良版
  3. js删除css某个属性值
  4. js判断是否获得焦点
  5. python 正则表达式提取url
  6. Qt汉化QColorDialog窗口
  7. 计算机网络设备互连与管理,软考网络管理员备考知识点精讲之计算机网络互连设备...
  8. 使用OpenVINO实现人体动作识别
  9. 山西计算机教室配备标准,山西省义务教育阶段中小学现代教育技术设备配备标准.doc...
  10. PJBLog的CSS模板图