几个图像缩放算法的比较

前段时间由于项目的需求,需要实现图像的缩放功能,期间查找了不少关于图像缩放算法的资料,现把自己的心得整理一下。

由于研究生期间没有选修过图像处理方面的课程,所以对图像缩放的原理可谓一窍不通,当时开始编写代码的时候简直就是一头雾水。而且网上虽然介绍图像处理的代码很多,但涉及图像缩放的代码却很少,因为很多软件都直接使用了windows的GDI函数库的API函数:StretchBlt,或者VCL中TCanvas类的StretchDraw。无奈这两个函数都是直接对BMP图像进行缩放,而且StretchBlt是在CDC里面调用的,结果只是在显示的时候对图像进行缩放,不能够进行缩放的存储。那些天在GDI和GDIPLUS摸索了半天,都找不到合适的函数,某天却迸出个想法来:图像放大不就是把每个象素点再多弄几个出来,而缩小不就是去掉里面一些象素点。所以就按照自己的想法写了一个比较粗糙的放大函数:

BYTE *src,*dst,*ptr,*buffer,*next;

for(int i=0,n=0; i < this->Height(); i++,n=n+rate)

{

src = this->GetLinePtr(i);

dst = tempdib->GetLinePtr(n);

ptr = dst;

for(int j=0; j < this->Width(); j++,ptr=ptr+3*rate)

{

memcpy(ptr,src+j*3,3);

for(int m=1;m<rate;m++)

memcpy(ptr+m*3,ptr,3);

}

for(int m=n+1;m<n+rate;m++)

{

buffer = dst;

next = tempdib->GetLinePtr(m);

ptr = next;

memcpy(ptr,buffer,dstwidth*3);

}

}

这段代码的效果比较粗糙,但处理的办法比较有意思。首先是读取一行的图像数据,然后在每一行循环读取一个象素的RGB值并复制到新图像的内存空间,然后根据放大的比例再作一次循环,把这个RGB值按照比例复制进内存空间。当进行完一行的处理后,在新图像的内存空间进行一次循环处理,把这行数据按照比例复制给下面几行。这样就通过象素点的复制实现了图片的放大。不过放大的效果不是特别好,图像列方向上会出现很多的毛刺,放大4倍的话图像就很模糊了。

所以还是重新去查找资料,结果在网上搜到一篇不错的文章——用线性插值算法实现图像缩放。看了文章,才发现我原先的办法还真不是一般的原始,不过思路还跟GDI里面的StretchBlt差不多。StretchBlt采用的方法在图像处理领域称为最近邻域法,其基本原理就是先取出原图的相邻四个点,然后把新位置的点跟这四个点的位置做比较,把最近一个点的RGB值赋给新位置的点。所以在放大的时候,几乎就是像我那样把前一个点的象素赋给新位置的点。这样处理的结果就是导致图像不够平滑,因为点与点之间是一个过渡的过程,不是简单的复制,稍微好点的办法就是把新点附近几个点的颜色值取平均再赋给这个点。这种方法在数值计算方法叫做线性插值。但那篇文章提供了一个更好的方法,叫做二维线性插值,其原理也是对附近的点取平均,但它对各个点的颜色值加上不同的权数,这个权数就是各个点距离这个点的位置。其计算方法如下:

P = n*b*PA + n * ( 1 – b )*PB + ( 1 – n ) * b * PC + ( 1 – n ) * ( 1 – b ) * PD

其中:n为v(映射后相应点在源图像中的Y轴坐标,一般不是整数)下面最接近的行的Y轴坐标与v的差;同样b也类似,不过它是X轴坐标。PA—PD分别是(u,v)点周围最接近的四个(左上,右上,左下,右下)源图像点的颜色(用TCanvas的 Pixels属性)。P为(u,v)点的插值颜色,即(x,y)点的近似颜色。

不过这个公式用的是浮点运算,真的用程序来实现效率有点低,所以作者在这个基础上对它进行优化,并且用C++Builder把它实现。而我所需要做的,只是把它移植到.net里面,哈,其实就是ctrl+c、ctrl+v。

int sw = this->width, sh = this->height;

int dw = tempdib->width, dh = tempdib->height;

int B, N, x, y;

BYTE *pLinePrev, *pLineNext;

BYTE *pDest;

BYTE *pA, *pB, *pC, *pD;

for(int i=0;i<dh;i++)

{

pDest = (BYTE* )tempdib->GetLinePtr(i);

y = i * sh / dh;

N = dh - i * sh % dh;

pLinePrev = (BYTE* )this->GetLinePtr(y++);

pLineNext = (N == dh) ? pLinePrev : (BYTE* )this->GetLinePtr(y);

for(int j=0;j<dw;j++)

{

x = j * sw /dw * 3;

B = dw - j * sw % dw;

pA = pLinePrev + x;

pB = pA + 3;

pC = pLineNext + x;

pD = pC +3;

if(B == dw)

{

pB = pA;

pD = pC;

}

for(int k=0;k<3;k++)

{

*pDest++ = (BYTE)(int)((B * N * (*pA++ - *pB - *pC + *pD)

+ dw * N * *pB++ +dh * B * *pC++ + (dw * dh -

dh * B - dw * N) * *pD++

+ dw *dh / 2)/(dw * dh));

}

}

}

不过这段代码还不算是最好的,后来在天鼎买了一本《VC.NET图像编程》,认真学了图像处理的原理。前面使用的方法,在图像处理里面是叫做空间域的图像处理,还有一种更有效但算法比较复杂的频域处理,它首先把图像通过傅立叶变换等等转换为频域的数据,然后用各种滤波器对图像进行处理。后来通过google在codeproject上找到这种基于频域的缩放算法。作者把它命名为2_pass_scaling,或许这是目前能找到的最好的缩放算法,实在太牛B了。作者把接口写成一个template,然后根据不同的滤波器去调用不同的算法,只要修改template的实现,就能够得到不同的缩放效果。最后的代码就这么简单:

C2PassScale<CBilinearFilter> ScaleEngine;

BYTE *psrc,*pdest;

pNewRGB = new BYTE[(this->width)*this->height*3];

pdest = pNewRGB;

for(int i=0;i<this->height;i++)

{

psrc = this->GetLinePtr(i);

for(int j=0;j<this->width;j++)

{

memcpy(pdest,psrc,3);

pdest += 3;

psrc += 3;

}

}

pNewBitmap = (BYTE* )ScaleEngine.AllocAndScale((myRGB* )pNewRGB,this->width,this->height,dstwidth,dstheight);

delete[] pNewRGB;

}

BYTE *src,*dst,*ptr,*buffer,*next;

ptr = (BYTE* )pNewBitmap;

for(int i=0;i<tempdib->height;i++)

{

src = tempdib->GetLinePtr(i);

for(int j=0;j<tempdib->width;j++,src+=3,ptr+=3)

memcpy(src,ptr,3);

}

delete pNewBitmap;

首先是根据不同的滤波器从template生成一个类,我这里用的是二次线性插值,所以就是<CBilinearFilter>,其他的滤波器还有CBoxFilter、CGaussianFilter、CHammingFilter、CBlackmanFilter。然后就只要调用ScaleEngine.AllocAndScale,把图像象素数据传进去,它就能返回一个新的内存空间,里面就是缩放后的图像数据。代码里面关于滤波器的代码比较复杂,看了半天还是看不懂,不过,好用就行 :)

几个图像缩放算法的比较相关推荐

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

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

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

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

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

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

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

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

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

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

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

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

  7. 图像缩放算法(下篇)

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

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

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

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

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

最新文章

  1. 轻松掌握nodeJS之npm
  2. BZOJ4475: [Jsoi2015]子集选取【找规律】【数学】
  3. 箭头函数参数和返回值
  4. 华硕P8B-C/2L及其他
  5. dz seo插件_河北seo优化网络推广报价单
  6. CMS系统模版引擎设计(3):Label基类的设计
  7. LeetCode——Kth Largest Element in an Array
  8. 虚拟机上使用ghost xp
  9. (二)单元测试利器 JUnit 4
  10. 消防给水及消火栓系统技术规范_消防给水及消火栓系统技术规范5.1 消防水泵 习题...
  11. 桶排序/Bucket Sort
  12. python中角度怎么表示_python – 如何知道两点之间的角度?
  13. java 如何让程序一直运行的程序_java – 如何在程序结束前让方法在后台持续运行?...
  14. Altium designer 原理图转换为pcb时出现的 unknown pin 和 failed to add class member
  15. 南京航空航天大学计算机组成原理,2017年南京航空航天大学计算机科学与技术学院829计算机专业基础之计算机组成原理考研题库...
  16. 名帖49 王羲之 小楷《黄庭经》
  17. ssm毕设项目高校学生社团管理系统n4pcu(java+VUE+Mybatis+Maven+Mysql+sprnig)
  18. DataBinding快速入门(还在用findViewById?)
  19. leetcode 37 数独问题的解答
  20. IC学习笔记1——建立时间和保持时间

热门文章

  1. http劫持软件、怎么应对这样的 HTTP 劫持
  2. 半导体术语的中英文版本
  3. python 给QQ好友发信息
  4. java计算机毕业设计培训机构运营系统源码+程序+lw文档+mysql数据库
  5. 多思计组实验实验四、数据通路实验
  6. Oracle计算偏差率的方法
  7. 测试手机的价格的软件,给大家推荐一个测心率的手机软件,不用花昂贵的价钱买设备啦~ - 薄荷减肥论坛...
  8. linux下挂载硬盘!
  9. SpringCloud - LCN分布式事务框架
  10. 写一篇基于SPEA2算法的高维多目标救灾物资分配的论文