图像缩放算法(下篇)

=================================

转载别人的,但是这篇文章写得确实太好了,所以想分享出来。
原文地址:http://blog.chinaunix.net/uid-22915173-id-2185545.html

=======================================================

摘要:首先给出一个基本的图像缩放算法,然后一步一步的优化其速度和缩放质量;

高质量的快速的图像缩放 全文 分为:
上篇 近邻取样插值和其速度优化
中篇 二次线性插值和三次卷积插值
下篇 三次线性插值和MipMap链

正文:

A:对于前一篇文章中的二次线性插值、三次卷积插值算法,但它们处理缩小到0.5倍以下的
时候效果就会越来越差;这是因为插值的时候自考虑了附近点的原因;如下图:

原图 近邻取样 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍

二次线性插值 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍

三次卷积插值 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍

可以看出:当缩小的比例很大的时候,插值算法的效果和近邻取样的效果差不多了:( ;
一种可行的解决方案就是:缩小时考虑更多的点; 但这种解决方案有很多缺点:函数编写麻烦,
速度也许会很慢,优化也不容易做; 还有一个方案就是预先建立一个缩放好的大小不同的图片
列表,每一张图片都是前一张的0.5倍(这种图片列表就是MipMap链),缩放的时候根据需要缩放
的比例从表中选择一张大小接近的图片来作为缩放的源图片; 该方案的优点:不需要编写新的
底层缩放算法,直接使用前面优化好的插值算法; 缺点:需要预先建立MipMap链,它需要时间,
并且它的储存需要多占用原图片的1/3空间(0.52+0.54+0.5^6+…=1/3);还有一个不太明显
的小问题,就是在一张图片的连续的比例不同的缩放中,选择会从MipMap的一张源图片跳到另
一张图片,视觉效果上可能会有一个小的跳跃(我在《魔兽世界》里经常看到这种效应:);一种
改进方案就是选择MipMap图片的时候,选择出附近的两张图片作为缩放的源图片;对两张图片
单独进行插值(和原来一致)输出两个值,然后把这两个值线性插值为最终结果;还有一个比较
大的缺点就是当缩放比例不均匀时(比如x轴放大y轴缩小),缩放效果也不好;
(当前很多显卡都提供了MipMap纹理和对应的插值方案,OpenGL和DirectX都提供了操作接口)

("三次线性插值和MipMap链"其实比较简单,这里只给出关键代码或算法)

B: MipMap图片的生成:
原图片缩放到0.5倍(宽和高都为原图片的1/2),在把0.5倍的图片缩放到0.25倍,…
直到宽和高都为1个像素,如果有一个长度先到1就保持1; 缩放过程中,可以可采用前面的缩放插值算法;
如果为了速度可以考虑这样的方案,要求原图片的宽和高必须是2的整数次方的数值,缩放时就可以直接将
2x2的像素快速合并为一个像素(如果允许原图片宽和高为任何值,可以考虑在合并时引入Alpha通道);

C: MipMap链图片的储存方案:

MipMap链图片示意图

可能的一种物理储存方案(我对每张图片加了一个边框)

D: 定义MipMap数据结构:
MipMap数据结构可以定义为一个TPicRegion数组和该数组的大小;
(MipMap图片的储存参见上面的图示)
比如:

#include
typedef std::vectorTMipMap;
//其中,第一个元素TMipMap[0]指向原始图片,后面的依次为缩小图片;

E: MipMap的选择函数和偏好:
在进行缩放时,根据目标图片缓冲区的大小来动态的选者MipMap中的一幅图片来作为源图片;这就需要一个
选择函数;比如:

longSelectBestPicIndex(constTMipMap& mip,constlongdstWidth,constlongdstHeight)
{
longoldS=mip[0].widthmip[0].height;
longdstS=dstWidth
dstHeight;
if( (dstS>=oldS) || (mip.size()==1) )
return0;
elseif(dstS<=1)
returnmip.size()-1;
else
return(long)(log(oldS/dstS)*0.5+0.5);
}
选择函数可以增加一个偏好参数:
mip选择偏好:0.5没有偏好,靠近0偏向选择小图片,靠近1偏向选择大图片(质量好一些)

floatpublic_mip_bias=0.5;//[0…1]

longSelectBestPicIndex(constTMipMap& mip,constlongdstWidth,constlongdstHeight)
{
longoldS=mip[0].widthmip[0].height;
longdstS=dstWidth
dstHeight;
if( (dstS>=oldS) || (mip.size()==1) )
return0;
elseif(dstS<=1)
returnmip.size()-1;
else
return(long)(log(oldS/dstS)*0.5+public_mip_bias);
}
F:利用MipMap后的缩放效果:

MipMap+近邻取样 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍
(利用MipMap做一次近邻取样)

MipMap+二次线性插值 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍
(利用MipMap做一次二次线性插值)

MipMap+三次卷积插值 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍
(利用MipMap做一次三次卷积插值)

G: 在MipMap的两张图片之间插值:
选择MipMap的时候,同时可以选择相邻的两张MipMap图片;分别进行插值算法后得到两个颜色结果;
对两个MipMap图片产生的评价值可以作为这两个颜色的插值权重,得到最终的颜色插值结果;优点是
缩放效果好,避免跳跃;缺点是速度慢:)

选择和权重函数的一个可能实现:

structTMipWeight {
longBigMip;
longSmallMip;
floatBigMipWeight;//[0…1]
};

TMipWeight SelectBestPicIndexEx(constTMipMap& mip,constlongdstWidth,constlongdstHeight)
{
longoldS=mip[0].widthmip[0].height;
longdstS=dstWidth
dstHeight;
TMipWeight result;
if( (dstS>=oldS) || (mip.size() == 1) )
{
result.BigMip=0;
result.SmallMip=0;
result.BigMipWeight=1.0;
}
elseif(dstS<=1)
{
result.BigMip=mip.size()-1;
result.SmallMip=mip.size()-1;
result.BigMipWeight=1.0;
}
else
{
floatbestIndex=log(oldS/dstS)*0.5+0.5;//or + public_mip_bias
result.BigMip=(long)bestIndex;
if(bestIndex==mip.size()-1)
{
result.SmallMip=mip.size()-1;
result.BigMipWeight=1.0;
}
else
{
result.SmallMip=result.BigMip+1;
result.BigMipWeight=1.0-(bestIndex-result.BigMip);
}
}
returnresult;
}

H:MipMap间插值效果:

MipMap+两次近邻取样 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍
(利用MipMap做两次近邻取样输出两个值,然后线性插值为最终结果)

三次线性插值缩放到0.4倍 缩放到0.2倍 缩放到0.1倍
(三次线性插值:利用MipMap做两次二次线性插值输出两个值,然后线性插值为最终结果)

MipMap+两次三次卷积插值 缩放到0.4倍 缩放到0.2倍 缩放到0.1倍
(利用MipMap做两次三次卷积插值输出两个值,然后线性插值为最终结果)

(图像缩放系列终于写完了,计划中写图像任意角度的高质量的快速旋转、Alpha图片混合等,尽请期待:)

(ps: 思考中的一个图片压缩方法:利用MipMap来压缩图像数据;输入一张图片,然后生成MipMap链,保存相邻之间图片的差(数值差可能很小,很容易找好的算法压缩得很小)和最顶的一张图片(一个点); 解压的时候依次求和就得到原图片了; 该算法为无损压缩,适合于人物风景等过渡比较多的图片的压缩,不太适合线条类等相邻间颜色变化剧烈的图片;)

图像缩放算法(下篇)相关推荐

  1. 图像缩放算法(中篇)

    图像缩放算法(中篇) ================================= 转载别人的,但是这篇文章写得确实太好了,所以想分享出来. 原文地址:http://blog.chinaunix ...

  2. 图形图像处理 —— 图像缩放算法

    转自:http://blog.chinaunix.net/space.php?uid=22915173&do=blog&id=2185545 摘要:首先给出一个基本的图像缩放算法,然后 ...

  3. 几个图像缩放算法的比较

    几个图像缩放算法的比较 前段时间由于项目的需求,需要实现图像的缩放功能,期间查找了不少关于图像缩放算法的资料,现把自己的心得整理一下. 由于研究生期间没有选修过图像处理方面的课程,所以对图像缩放的原理 ...

  4. 计算机视觉-图像缩放算法-cuda实现

    一.CUDA CUDA是显卡厂商NVIDIA(英伟达)推出的运算平台,能够将数据数据复制到GPU,在GPU中进行计算,然后再返回给CPU端.CUDA将GPU称为设备侧或者Device,将CPU称为Ho ...

  5. [图像]图像缩放算法-双线性内插法

    原创文章,欢迎转载.转载请注明:转载自 祥的博客 原文链接:http://blog.csdn.net/humanking7/article/details/45014879 简介: 图像缩放算法–双线 ...

  6. 图像缩放算法及速度优化

    原文来自:博客园 小欣子 图像缩放算法及速度优化--(一)最近邻插值 图像缩放算法及速度优化--(二)双线性插值 --------------------以下为原文------------------ ...

  7. 基于FPGA 的图像缩放算法设计

    介绍双线性插值算法来实现图像缩放,FPGA 硬件实现方法,包括图像数据缓冲单元.插值系数生成单元以及插值计算单元等. 图像是人类感知世界的视觉基础,是人类获取信息.表达信息的重要手段.现在研究较多的是 ...

  8. 图像缩放算法_技术专栏|基于无人机LK光流算法的适用性及其优化方法探究

    点击上方蓝字关注我们 问题描述 ◆ ◆ ◆ 一般的LK光流算法存在一个比较明显的局限性.我们知道,一般的LK光流算法必须包含三个假设: (1)亮度恒定: (2)时间连续或者运动是小运动: (3)空间一 ...

  9. 图像缩放算法_opencv缩放算法

    1.opencv插值介绍 opencv提供resize函数用来做图像缩放,该函数有6个参数: (1)输入图像,Mat型 (2)输出图像,Mat型 (3)输出图像大小,可用cv::Size(out_im ...

最新文章

  1. 互联互通下的超级App价值重构
  2. 艾伟也谈项目管理,如何做一个合格的项目经理
  3. 线程池什么时候调用shutdown方法_ThreadPoolExecutor.shutdown()?
  4. android旋转动画和平移动画具体解释,补充说一下假设制作gif动画放到csdn博客上...
  5. 洛谷 P1064 金明的预算方案【有依赖的分组背包】
  6. php实现微信公众号半匹配,半全局块匹配(Semi-Global Block Matching)算法
  7. gdb当前哪一行_GDB原理之ptrace实现原理
  8. php js树状菜单,php+mysql+js实现树形菜单代码
  9. js拼接json对象_JS实现合并json对象的方法
  10. linux安装p12,用命令行安装mobileprovision和p12证书
  11. 【深度】美俄机器人集群军事作战应用研究现状!三大关键技术体系分析
  12. python打开sql,Python打开Microsoft SQL Server MDF文件
  13. 迷你HTTP服务器+小型博客
  14. 个人音乐流媒体服务器mStream
  15. 对QQ保镖检测结果的几点疑问
  16. FFMPEG之音频播放
  17. 数学牛人们的轶事[下]
  18. 不同tab页sessionStorage共享情况
  19. 计算机二级工作表不会,计算机二级Office:Excel工作簿与工作表操作
  20. 2022煤矿井下爆破考试题库模拟考试平台操作

热门文章

  1. 带权二分图匹配(最小费用最大流) 8.2牛客暑期多校训练营五 E
  2. css页脚怎么这只,纯css实现内容不足时页脚在底部
  3. 常见公告栏信息效果的实现
  4. 完美解决W: 无法下载 /shiftkey/desktop/any/dists/any/InRelease
  5. Macbook Pro 201 装Win10 声卡_苹果MacBook全家桶将发布:重点不是Pro系列
  6. Hbuilder ios证书申请
  7. 如何辨别家谱的真伪?家谱面临断代危机,互联网家谱如何力挽狂澜
  8. [软件试用3]AI写作软件AI-WRITER.COM:博客思路及成文解析
  9. 关于中国移动M-Market市场定位问题的思考
  10. [linux学习](linuxprobe课程)九 使用ssh服务管理远程主机