图像处理中两种基本的插值算法(最邻近插值法和双线性内插法)
在图像的基本仿射变换中,经常会碰到经过旋转、缩放后灰度值如何赋值的问题。因为变换之后,图像的坐标位置有可能是小数,所以就需要插值算法来确定到底将该像素赋予哪个位置。
1、最邻近插值法(Nearest Interpolation)
这是最简单的一种插值方法,不需要计算。在待求像素的四邻像素中,将距离待求像素最近的邻接像素灰度值赋予待求像素。设i+u, j+v(i, j为正整数, u, v为大于零小于1的小数,下同)为待求象素坐标,则待求象素灰度的值 f(i+u, j+v) 如下图所示:
如果(i+u, j+v)落在A区,即u<0.5, v<0.5,则将左上角象素的灰度值赋给待求象素,同理,落在B区则赋予右上角的象素灰度值,落在C区则赋予左下角象素的灰度值,落在D区则赋予右下角象素的灰度值。
最邻近元法计算量较小,但可能会造成插值生成的图像灰度上的不连续,在灰度变化的地方可能出现明显的锯齿状。
2、双线性内插法(Bilinear Interpolation)
双线性内插法是利用待求象素四个邻象素的灰度在两个方向上作线性内插,如下图所示:
对于 (i, j+v),f(i, j) 到 f(i, j+1) 的灰度变化为线性关系,则有:
f(i, j+v) = [f(i, j+1) - f(i, j)] * v + f(i, j)
同理对于 (i+1, j+v) 则有:
f(i+1, j+v) = [f(i+1, j+1) - f(i+1, j)] * v + f(i+1, j)
从f(i, j+v) 到 f(i+1, j+v) 的灰度变化也为线性关系,由此可推导出待求象素灰度的计算式如下:
f(i+u, j+v) = (1-u) * (1-v) * f(i, j) + (1-u) * v * f(i, j+1) + u * (1-v) * f(i+1, j) + u * v * f(i+1, j+1)
双线性内插法的计算比最邻近点法复杂,计算量较大,但没有灰度不连续的缺点。它具有低通滤波性质,使高频分量受损,图像轮廓可能会有一点模糊。图像看起来更光滑。
以上文章转自http://www.cnblogs.com/linzhao/archive/2012/02/16/2354175.html
下面贴上主要实验代码:
- //nearest interpolation method for resize(zoom)
- void onNearest(CDib &m_Dib, BYTE **srcImg,BYTE **dstImg,int h,int w,double zoomNumber)
- {
- int ey,ex;
- int j,i;
- int zoomH = (int)(zoomNumber*h + 0.5);
- int zoomW = (int)(zoomNumber*w + 0.5);
- int originalLineByte = ((w % 4 == 0 ? w : w + (4 - (w % 4)))*m_Dib.GetBitCount())/8; //align the width
- int zoomLineByte = ((zoomW % 4 == 0 ? zoomW : zoomW + (4 - (zoomW % 4)))*m_Dib.GetBitCount())/8;
- BYTE *temp = new BYTE[w * h];
- for(j=0;j<h;j++) //copy original image to the buffer
- {
- for(i=0;i<w;i++)
- {
- temp[j*w+i] = srcImg[j][i];
- }
- }
- BYTE *newImg = new BYTE [zoomLineByte * zoomH];
- for(ey = 0;ey < zoomH;ey++)
- {
- for(ex = 0; ex < zoomLineByte;ex++)
- {
- j = (int)(ey/zoomNumber + 0.5); //nearest value
- i = (int)(ex/zoomNumber + 0.5);
- if((i >= 0) && (i < w) && (j >= 0)&& (j < h))
- {
- //memcpy(&newImg[ey * zoomLineByte] + ex * m_Dib.GetBitCount() / 8,&temp[j * originalLineByte] + i * m_Dib.GetBitCount() <span style="white-space:pre"> </span> //<span style="white-space:pre"> </span>/ 8,m_Dib.GetBitCount() / 8);
- newImg[ey*zoomLineByte+ex] = temp[j*originalLineByte+i];
- }
- else
- {
- newImg[ey*zoomLineByte+ex] = 255;
- }
- dstImg[ey][ex]=newImg[ey*zoomLineByte+ex];
- }
- }
- }
- //bilinear interpolation method for resize(zoom)
- void onBilinear(CDib &m_Dib,BYTE **srcImg,BYTE **dstImg,int h, int w,double zoomNumber)
- {
- int ey,ex;
- int j,i;
- int zoomH = (int)(zoomNumber*h + 0.5);
- int zoomW = (int)(zoomNumber*w + 0.5);
- int originalLineByte = ((w % 4 == 0 ? w : w + (4 - (w % 4)))*m_Dib.GetBitCount())/8; //align the width
- int zoomLineByte = ((zoomW % 4 == 0 ? zoomW : zoomW + (4 - (zoomW % 4)))*m_Dib.GetBitCount())/8;
- BYTE *temp = new BYTE[w * h];
- for(j=0;j<h;j++) //copy original image to the buffer
- {
- for(i=0;i<w;i++)
- {
- temp[j*w+i] = srcImg[j][i];
- }
- }
- BYTE *newImg = new BYTE [zoomLineByte * zoomH];
- for(ey = 0;ey < zoomH;ey++)
- {
- for(ex = 0;ex < zoomLineByte;ex++)
- {
- double jz = ((double)ey)/zoomNumber; //get the original image coordinates
- double iz = ((double)ex)/zoomNumber;
- int j1 = (int)jz;
- int i1 = (int)iz;
- int j2 = j1 + 1;
- int i2 = i1 + 1;
- double u = iz - i1; //插值点与邻近整数点(j1,i1)的距离 x coordinate
- double v = jz - j1; // y coordinate
- double s1 = (1.0 - u)*(1.0 - v); <span style="white-space:pre"> </span>//邻近整数点(j1,i1)函数值的系数(左上角)left-up corner
- double s2 = (1.0-u)*v; <span style="white-space:pre"> </span>//邻近整数点(j1,i1)函数值的系数(左下角)left-down corner
- double s3 = u*(1.0 - v); //邻近整数点(j1,i1)函数值的系数(右上角)right-up corner
- double s4 = u*v; //邻近整数点(j1,i1)函数值的系数(右下角)right-down corner
- if((jz >=0) && (jz < h) && (iz >= 0) && (iz < w))
- {
- *(newImg+ey*zoomLineByte+ex) = *(temp+j1*originalLineByte+i1)*s1
- +*(temp+j1*originalLineByte+i2)*s3
- +*(temp+j2*originalLineByte+i1)*s2
- +*(temp+j2*originalLineByte+i2)*s4;
- }
- else
- {
- *(newImg+ey*zoomLineByte+ex) = 255;
- }
- dstImg[ey][ex]=newImg[ey*zoomLineByte+ex];
- }
- }
- }
实验效果如下图所示:分别放大了1.5倍
最邻近插值:
双线性内插:
可以看到最邻近插值图像中有明显的锯齿状,而双线性内插结果图中比较光滑,也带一点模糊的感觉。
其他参考链接:
http://zh.wikipedia.org/wiki/%E5%8F%8C%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC
http://en.wikipedia.org/wiki/Bilinear_interpolation
原文:http://blog.csdn.net/zyttae/article/details/42710303
图像处理中两种基本的插值算法(最邻近插值法和双线性内插法)相关推荐
- 函数指针--Nginx和Redis中两种回调函数写法
1.Nginx和Redis中两种回调函数写法 #include <stdio.h>//仿Nginx风格 //结构外声明函数指针类型 typedef void (*ngx_connectio ...
- spring mvc中两种异常的处理手法
spring mvc中两种异常的处理手法 在spring mvc中,对异常的处理,可以小结有如下两类写法: 1 <bean id="exceptionResolver" cl ...
- java : enum、创建文件和文件夹、删除文件和文件夹、获得项目绝对路径、写入数据到excel中、java代码中两种路径符号写法、读取、写入text文件...
java : enum http://www.cnblogs.com/hyl8218/p/5088287.html 创建文件和文件夹.删除文件和文件夹 http://www.cnblogs.com/m ...
- unity3d软阴影和硬阴影的原理_Unity3D中两种默认阴影的实现
Unity3D中两种阴影的实现 传统的ShadowMap ShadowMap说起来十分简单,把摄像机和光源的位置重叠,那么场景中该光源的阴影区域就是那些摄像机看不到的地方,主要应用在前向渲染路径中. ...
- apache php 工作模式,PHP Apache中两种工作方式区别(CGI模式、Apache 模块DLL)
搜索热词 对PHP在Apache中两种工作方式的区别(CGI模式.Apache 模块DLL)感兴趣的小伙伴,下面一起跟随编程之家 jb51.cc的小编两巴掌来看看吧! Windows 下有两种方法使 ...
- python列表去重函数_对python中两种列表元素去重函数性能的比较方法
测试函数: 第一种:list的set函数 第二种:{}.fromkeys().keys() 测试代码: #!/usr/bin/python #-*- coding:utf-8 -*- import t ...
- R中两种常用并行方法——2. snowfall
上一篇博客(R中两种常用并行方法--1. parallel)中已经介绍了R中常见的一种并行包:parallel,其有着简单便捷等优势,其实缺点也是非常明显,就是很不稳定.很多时候我们将大量的计算任务挂 ...
- java中两种异常类型_Java中的三种异常类型
java中两种异常类型 Errors are the bane of users and programmers alike. Developers obviously don't want thei ...
- Spring中两种编程式事务管理
Spring中两种编程式事务管理 在代码中显示调用beginTransaction,commit,rollback等与事务处理相关的方法,这就是编程式事务管理,当只有少数事务操作时,编程式事务管理才比 ...
最新文章
- java web中文乱码处理笔记
- python解除windows锁屏_实战 | Python批量提取Win10锁屏壁纸
- Oracle中查看最近被修改过的表的方法
- Android音频底层调试-基于tinyalsa
- 音视频技术开发周刊 | 213
- python代码优化无限营销软件工作室_这个教程价值有点高,利用Python制作全自动化营销软件!...
- 展示Java开发人员课程包
- 单片机控制灯光亮度c语言程序,基于51单片机控制LED灯光亮度并报警
- java bitset_Java BitSet length()方法与示例
- duration java_Java Duration类| 带示例的dividBy()方法
- 手动启动_电站首台机组首次手动开机启动一次性成功
- SIP对话、事务详解
- python语言接收信息的内置函数_python接收信息的内置函数是
- 2 Linux磁盘管理
- css 超出N行文本如何处理
- 一个websocket 可以多个页面创建吗_聊聊 WebSocket,还有 HTTP
- 计算机视觉与图形学-神经渲染专题-神经体渲染:实时渲染KiloNeRF
- 4G-LTE技术总结
- 静态资源文件无法加载导致jsp页面渲染不成功问题
- 赠书 | 四大通证类型:价值创新的源头