几个图像缩放算法的比较

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

由于研究生期间没有选修过图像处理方面的课程,所以对图像缩放的原理可谓一窍不通,当时开始编写代码的时候简直就是一头雾水。而且网上虽然介绍图像处理的代码很多,但涉及图像缩放的代码却很少,因为很多软件都直接使用了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. 这可能是今年最硬核的AI交流会,李飞飞、图灵奖得主Pearl等共同探讨AI未来
  2. ICCV 2019 | COCO-GAN:通过条件坐标的部分图像生成
  3. php关于ob_start('ob_gzhandler')启用GZIP压缩的bug
  4. 学习过程中的一些细节
  5. iOS Programming UIWebView 2
  6. JBoss Tools安装
  7. PHP防注入安全代码
  8. java的泛,java_泛型
  9. Canvas 通过改变渐变色渐变百分比位置做飞线效果
  10. poi导出excel写入公式_POI导出Excel增加公式核心代码
  11. C# Ftp创建文件夹
  12. 计算机创客教育,浅析职业教育中计算机学科的创客教育
  13. 捷豹:车到用时方知养,可知彼时恨太迟
  14. OpenStack安装Placement组件部署(四)
  15. c++语言 tcp例子,C++ boost::asio编程-同步TCP详解及实例代码
  16. VSCode远程开发 Resolver error: Error: Failed to install the VS Code Server
  17. LSTM长短期记忆人工神经网络简述
  18. c语言体重指数bmi计算器,身高106cm体重19.5kg的女性标准体重与BMI指数 - BMI计算器...
  19. Building a Restful Web Service(最好的Spring入门教程 --来自Spring官网的Guides)
  20. java两个日期比较相等

热门文章

  1. yii ajax验证失败返回提示,Yii使用ajax验证显示错误messagebox的解决方法
  2. ThreeJS加载geojson数据实现3D地图
  3. NIOS II 软核中EPCS配置芯片的存储操作
  4. 解析eBay BASE模式、去哪儿及蘑菇街分布式架构
  5. ubuntu18.04上使用7z分卷压缩和解压
  6. 小米盒子4S Pro好不好?对比当贝盒子B1值得买吗?
  7. Unity 的协程的原理
  8. 跨境运营培训做亚马逊广告要注意什么
  9. 高可用架构之高可用的应用和服务
  10. 暗原色先验图像去雾算法研究_先验算法