概述
图像的放大与缩小是图像处理中很经常碰到的问题,也是现实中经常要应用的,如一张图片太小,看不行的情况下就需要对去进行放大;在一些文档排版的时候有需要对一下大的图片进行缩小。
图像的放大与缩小在物理意义上来说是图像的像素的尺寸放大或缩小相应的比例,但像素的尺寸是不能改变的,因此我们只能通过增加(或减少)相应的像素来放大(或缩小)图片。在算法实现中最简单的是等距离采样法。
算法的实现步骤:
(1)计算采样间隔
设原图的大小为W*H,将其放大(缩小)为(k1*W)*(K2*H),则采样区间为
ii=1/k1; jj=1/k2;
当k1==k2时为等比例缩小;当k1!=k2时为不等比例放大(缩小);当k1<1 && k2<1时为图片缩小,k1>1 && k2>1时图片放大。
(2)求出放大(缩小)后的图像
设原图为F(x,y)(i=1,2, ……W; j=1,2,……H),放大(缩小)的图像为G(x,y)(x=1,2, ……M; y=1,2,……N,其中M=W*k1,N=H*k2),则有
G(x,y) = f(ii*x, jj*y)
举例说明:
原图(6*4)
缩小比例k1=0.6, k2 = 0.7
f12 f13 f15 f16
f32 f33 f35 f36
f42 f43 f45 f46
当然,使用等距采样法实现图片放大与缩小有一个缺点就是:缩小时未被选取的点的信息无法反映在缩小的图像上,放大时会出现整个小块区域像素相同,图像不清晰的,特别是缩放比例很大时。如下图
2048*1536缩小为100*80时的效果 100*80放大到600*400的效果
要解决这个问题,请看下一节“图像的放大与缩小(1)——双线性插值放大与均值缩小”
算法源代码(java)
/**
* 读取图片
* @param srcPath 图片的存储位置
* @return 返回图片的BufferedImage对象
*/
public static BufferedImage readImg(String srcPath) {
BufferedImage img = null;
try {
img = ImageIO.read(new File(srcPath));
} catch (IOException e) {
e.printStackTrace();
}
return img;
}
/**
* 将图片写入磁盘
* @param img 图像的BufferedImage对象
* @param s
* @param distPath 图像要保存的存储位置
*/
public static void writeImg(BufferedImage img, String s, String distPath) {
OutputStream out = null;
try {
//int imgType = img.getType();
//System.out.println("w:" + img.getWidth() + " h:" + img.getHeight());
out = new FileOutputStream(distPath);
ImageIO.write(img, s, out);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 等间隔采样的图像放大(缩小)
* @param img 要放大(缩小)的图像对象
* @param m 放大(缩小)后图像的宽
* @param n 放大(缩小)后图像的高
* @return 返回处理后的图像对象
*/
public static BufferedImage flex(BufferedImage img, int m, int n) {
float k1 = (float)m/img.getWidth();
float k2 = (float)n/img.getHeight();
return flex(img, k1, k2);
}
/**
* 等间隔采样的图像放大(缩小)
* @param img 要放大(缩小)的图像对象
* @param k1 要放大(缩小)的列比列
* @param k2 要放大(缩小)的行比列
* @return 返回处理后的图像对象
*/
public static BufferedImage flex(BufferedImage img, float k1, float k2) {
float ii = 1/k1; //采样的行间距
float jj = 1/k2; //采样的列间距
//int m=0 , n=0;
int imgType = img.getType();
int w = img.getWidth();
int h = img.getHeight();
int m = (int) (k1*w);
int n = (int) (k2*h);
int[] pix = new int[w*h];
pix = img.getRGB(0, 0, w, h, pix, 0, w);
System.out.println(w + " * " + h);
System.out.println(m + " * " + n);
int[] newpix = new int[m*n];
for(int j=0; j<n; j++) {
for(int i=0; i<m; i++) {
newpix[j*m + i] = pix[(int)(jj*j)*w + (int)(ii*i)];
}
}
System.out.println((int)((m-1)*ii));
System.out.println("m:" + m + " n:" + n);
BufferedImage imgOut = new BufferedImage( m, n, imgType);
imgOut.setRGB(0, 0, m, n, newpix, 0, m);
return imgOut;
}