分型插值算法实现图片的放大缩小.docx
- 文档编号:3786072
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:7
- 大小:24.52KB
分型插值算法实现图片的放大缩小.docx
《分型插值算法实现图片的放大缩小.docx》由会员分享,可在线阅读,更多相关《分型插值算法实现图片的放大缩小.docx(7页珍藏版)》请在冰豆网上搜索。
分型插值算法实现图片的放大缩小
前段时间接触了一些数字图像处理的问题,在1位师兄的指导下,在j2me平台,完成了一些基本的2D图像处理算法。
就当是对这段知识做一下总结,决定把这些算法写出来,和各位朋友共同探讨。
这篇文章先介绍图像放大缩小的实现,程序是以NokiaS40的机器为平台实现的。
1、实现图形缩放的基本思想:
图像的变形变换,简单的说就是把源图像每个点坐标通过变形运算转为目标图像相应点的新坐标,但是这样会导致一个问题就是目标点的坐标通常不会是整数。
所以我们在做放大变换时,需要计算生成没有被映射到的点;而在缩小变换时,需要删除一些点。
这里我们采用最简单的一种插值算法:
“最近邻域法”。
顾名思义,就是把非整数坐标作一个四舍五入,取最近的整数点。
看下面的一个图片放大的例子,左图为原始图像,右图为放大1倍的图像。
里面的数字,表示所在像素的信息
2、对于图片像素的操作:
获取Image图片像素信息:
标准的midp1.0没有提供获取图片像素信息的函数,对于NOKIA的机器,我们可以采用NokiaSDK提供的API获取像素信息。
具体程序如下:
g=image.getGraphics()
DirectGraphicsdg=DirectUtils.getDirectGraphics(g);
dg.getPixels(short[]pixels,intoffset,intscanlength,intx,inty,intwidth,intheight,intformat)
参数介绍:
short[]pixels:
用于接收像素信息的数组
intoffset:
这篇文章中的用到的地方,添0就可以了
intscanlength:
添图片的宽度就行了
intx:
添0
inty:
添0
intwidth:
图片宽度
intheight:
图片高度
intformat:
444,表示图形格式,好像NokiaS40的机器都是采用444格式表示RGB颜色的。
就是红,绿,蓝各用4位表示,至于可以表示透明色ARGB的4444格式,应该是机器硬件实现的。
想具体了解NokiaSDK的信息,可以查看NokiaSDK的帮助文档。
使用像素信息数组生成Image图片:
image=Image.createImage(w,h);
g=image.getGraphics()
DirectGraphicsdg=DirectUtils.getDirectGraphics(g);
dg.drawPixels(short[]pixels,booleantransparency,intoffset,intscanlength,intx,inty,intwidth,intheight,intmanipulation,intformat)
short[]pixels:
像素信息数组
booleantransparency:
是否包含alpha位信息
intoffset:
添0
intscanlength:
添图片的宽度就行了
intx:
添0
inty:
添0
intwidth:
图片宽度
intheight:
图片高度
intmanipulation:
添0
intformat:
444
下面开始介绍具体的算法,首先给出图像缩放的完整函数,然后对代码,分段进行解释
/*********************************
*@todo图片放大缩小
*@paramsrcImg原始图片
*@paramdesW变化后图片的宽
*@paramdesH变化后图片的高
*@return处理后的图片
*********************************/
privateImageZoomImage(ImagesrcImg,intdesW,intdesH){
intsrcW=srcImg.getWidth();//原始图像宽
intsrcH=srcImg.getHeight();//原始图像高
short[]srcBuf=newshort[srcW*srcH];//原始图片像素信息缓存
//srcBuf获取图片像素信息
ImagedesImg=Image.createImage(srcW,srcH);
if(srcImg.isMutable()){/*如果是可变图像*/
DirectUtils.getDirectGraphics(srcImg.getGraphics()).
getPixels(srcBuf,0,srcW,0,0,srcW,srcH,444);
}else{/*如果是非可变图像*/
desImg.getGraphics().drawImage(srcImg,0,0,0);
DirectUtils.getDirectGraphics(desImg.getGraphics()).
getPixels(srcBuf,0,srcW,0,0,srcW,srcH,444);
}
//计算插值表
short[]tabY=newshort[desH];
short[]tabX=newshort[desW];
intsb=0;
intdb=0;
inttems=0;
inttemd=0;
intdistance=srcH>desH?
srcH:
desH;
for(inti=0;i<=distance;i++){/*垂直方向*/
tabY[db]=(short)sb;
tems+=srcH;
temd+=desH;
if(tems>distance){
tems-=distance;
sb++;
}
if(temd>distance){
temd-=distance;
db++;
}
}
sb=0;
db=0;
tems=0;
temd=0;
distance=srcW>desW?
srcW:
desW;
for(inti=0;i<=distance;i++){/*水平方向*/
tabX[db]=(short)sb;
tems+=srcW;
temd+=desW;
if(tems>distance){
tems-=distance;
sb++;
}
if(temd>distance){
temd-=distance;
db++;
}
}
//生成放大缩小后图形像素buf
short[]desBuf=newshort[desW*desH];
intdx=0;
intdy=0;
intsx=0;
intsy=0;
intoldy=-1;
for(inti=0;i if(oldy==tabY[i]){ System.arraycopy(desBuf,dy-desW,desBuf,dy,desW); }else{ dx=0; for(intj=0;j desBuf[dy+dx]=srcBuf[sy+tabX[j]]; dx++; } sy+=(tabY[i]-oldy)*srcW; } oldy=tabY[i]; dy+=desW; } //生成图片 desImg=Image.createImage(desW,desH); DirectUtils.getDirectGraphics(desImg.getGraphics()). drawPixels(desBuf,true,0,desW,0,0,desW,desH,0,444); returndesImg; } 首先看函数的头两句,很容易,就是获取原始图片的宽度和高度 intsrcW=srcImg.getWidth();//原始图像宽 intsrcH=srcImg.getHeight();//原始图像高 接下来一句我们要定义一个short型数组,作为获取原始图片像素信息的缓存 short[]srcBuf=newshort[srcW*srcH]; 再下来一段,有的朋友可能会有些不明白,这里要解释一下。 由于getPixels()这个函数,只能获取可变图像的像素信息,非可变图像,无法获取像素信息。 所以我们要用srcImg.isMutable()来判断,原始图像是不是可变图像,然后分两种情况来处理。 如果srcImg是可变图像,我们就直接用getPixels()来获取它的像素信息,并保存在srcBuf里。 如果srcImg不是可变图像,我们就需要把srcImage画到事先生成的可变图像desImg上,然后再获取desImg的像素信息。 ImagedesImg=Image.createImage(srcW,srcH); if(srcImg.isMutable()){/*如果是可变图像*/ DirectUtils.getDirectGraphics(srcImg.getGraphics()). getPixels(srcBuf,0,srcW,0,0,srcW,srcH,444); }else{/*如果是非可变图像*/ desImg.getGraphics().drawImage(srcImg,0,0,0); DirectUtils.getDirectGraphics(desImg.getGraphics()). getPixels(srcBuf,0,srcW,0,0,srcW,srcH,444); } 再往下就是缩放算法的重点: 插值表的生成。 插值表分水平差值表和垂直插值表,我们要分别生成原始图像矩阵的2种插值表,然后利用插值表生成放大缩小后的图像矩阵。 由于这个内容比较抽象,很难用文字表述清楚,所以我们用实例进行介绍。 大家看下面这个水平的1*4的表格 ----------------- |0|1|2|3| ----------------- 如果要将这个表格放大成1*6的表格,放大的表格比原始表格多出了2个格子,我们只能对这多出来的2个格子进行插值,才能完成放大的操作。 现在结合生成水平插值表的代码来完成这个过程。 distance=srcW>desW? srcW: desW; for(inti=0;i<=distance;i++){/*水平方向*/ tabX[db]=(short)sb; tems+=srcW; temd+=desW; if(tems>distance){ tems-=distance; sb++; } if(temd>distance){ temd-=distance; db++; } } 很明显原始表格宽度srcW=4;放大后的表格宽度desW=6;所以distance=desW=6 接下来进入for循环,我们一步步的演算其循环的过程 ----------------------------------------------- |i|tabX赋值操作|tems|temd|sb|db| ----------------------------------------------- |0| tabX[0]=0| 4 | 6 | 0 | 0| ----------------------------------------------- |1| tabX[0]=0| 2 | 6 | 1 | 1| ----------------------------------------------- |2| tabX[0]=1| 6 | 6 | 1 | 2| ----------------------------------------------- |3| tabX[0]=1| 4 | 6 | 2 | 3| ----------------------------------------------- |4| tabX[0]=2| 2 | 6 | 3 | 4| ----------------------------------------------- |5| tabX[0]=3| 6 | 6 | 3 | 5| ----------------------------------------------- |6| tabX[0]=3| 4 | 6 | 4 | 6| ----------------------------------------------- 有此得到放大后1*6的表格为下图所示。 其中每一个单元格中的数字n表示这个单元格的内容,和原始表格中第n个单元格的内容一样。 -------------------------- |0|1|1|2|3|3| -------------------------- 例如,左图为原始表格,右图为放大的表格 --------------------- -------------------------------- |红|绿|兰|紫| |红|绿| 绿|兰|紫|紫| --------------------- -------------------------------- 同样,垂直方向的插值表我们也可以用相同的方法获得。 有了2个插值表,下面就可以生成放大和缩小后的图像了。 short[]desBuf=newshort[desW*desH]; intdx=0; intdy=0; intsx=0; intsy=0; intoldy=-1; for(inti=0;i if(oldy==tabY[i]){ /**********情况一**********/ System.arraycopy(desBuf,dy-desW,desBuf,dy,desW); }else{/**********情况二**********/ dx=0; for(intj=0;j desBuf[dy+dx]=srcBuf[sy+tabX[j]]; dx++; } sy+=(tabY[i]-oldy)*srcW; } oldy=tabY[i]; dy+=desW; } desBuf是用来保存放大缩小后的图像数据。 例如我们把一个4*4像素的图像A放大成6*6的图像B,据前面的介绍我们可以生成2个插值表。 tabX={0,1,1,2,3,3},tabY={0,1,1,2,3,3}。 在循环中会判断是否oldy等于tabY[i],这个操作等同于tabY[i-1]是否等于tabY[i]。 如果等于,表示图像B前一行已经生成的数据和即将要生成的第i行数据相同,则只要执行System.arraycopy(desBuf,dy-desW,desBuf,dy,desW)把上一行的数据复制过来即可;如果不等,则需要对照水平插值表tabX生成这一行的数据。 算法演示过程如下: ---------------------------- |i|oldy|tabY[i]|运算情况| ---------------------------- |0|-1 | 0 |情况2 | ---------------------------- |1|0 | 1 |情况2 | ---------------------------- |2|1 | 1 |情况1 | ---------------------------- |3|1 | 2 |情况2 | ---------------------------- |4|2 | 3 |情况2 | ---------------------------- |5|3 | 3 |情况1 | ---------------------------- 然后我们用desBuf生成最终放大或缩小后的图片 desImg=Image.createImage(desW,desH); DirectUtils.getDirectGraphics(desImg.getGraphics()). drawPixels(desBuf,true,0,desW,0,0,desW,desH,0,444); returndesImg; 下面是采用此算法实现放大缩小的效果图 最后要说明一点的是,由于该算法中使用了Image.createImage(w,h)来创建图像,这个函数会创建一个w*h像素的全白可变图像,所以透明图片放大缩小后,背景不再透明,而是白色了,这是j2me本身的缺憾和算法没有关系。 对于这个问题,有一个解决办法,就是程序的图片不采用Image来保存,而是采用short[]数组保存,画图的时候用drawPixels()来画图。 ^-^
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 分型插值 算法 实现 图片 放大 缩小