文档章节

图像的放大与缩小(2)——双线性插值放大与均值缩小

自由的角马
 自由的角马
发布于 2015/01/10 13:57
字数 2165
阅读 46
收藏 0

概述

基于上一节“等距采样法”实现图片放大与缩小的缺点。要对其进行改进,对图像的缩小则可以用“局部均值法”,对于图像的放大则可以用“双线性插值法”。

效果如下:

      

                   2048*1536缩小为100*80时的效果               100*80放大到600*400的效果

局部均值法缩小图像

(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),则有原图像局部子块为

f’(x,y) = f(ii*i, jj*j)        …… f(ii*i + ii-1, jj*j)

                ……                   ……

             f(ii*i, jj*j+jj-1) …… f(ii*i + ii-1, jj*j+jj-1)

(3)求出缩小的图像

G(x, y) = f’(x,y)的均值

例:


缩小后的图像

 

 

例如g11=(f11 +f12 + f21 + f22)/4

 

算法源代码(java)

/**
	 * 局部均值的图像缩小
	 * @param img 要缩小的图像对象
	 * @param m 缩小后图像的宽
	 * @param n 缩小后图像的高
	 * @return 返回处理后的图像对象
	 */
	public static BufferedImage shrink(BufferedImage img, int m, int n) {
		float k1 = (float)m/img.getWidth();
		float k2 = (float)n/img.getHeight();		
		return shrink(img, k1, k2);
	}
	
	/**
	  * 局部均值的图像缩小
	 * @param img 要缩小的图像对象
	 * @param k1 要缩小的列比列
	 * @param k2 要缩小的行比列
	 * @return 返回处理后的图像对象
	 */
	public static BufferedImage shrink(BufferedImage img, float k1, float k2) {
		if(k1 >1 || k2>1) {//如果k1 >1 || k2>1则是图片放大,不是缩小
			System.err.println("this is shrink image funcation, please set k1<=1 and k2<=1!");
			return null;
		} 
		float ii = 1/k1;	//采样的行间距
		float jj = 1/k2; //采样的列间距		
		int dd = (int)(ii*jj); 
		//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++) {
				int r = 0, g=0, b=0;
				ColorModel cm = ColorModel.getRGBdefault();				
				for(int k=0; k<(int)jj; k++) {
					for(int l=0; l<(int)ii; l++) {
						r = r + cm.getRed(pix[(int)(jj*j+k)*w + (int)(ii*i+l)]);
						g = g + cm.getGreen(pix[(int)(jj*j+k)*w + (int)(ii*i+l)]);
						b = b + cm.getBlue(pix[(int)(jj*j+k)*w + (int)(ii*i+l)]);
					}
				}
				r = r/dd;
				g = g/dd;
				b = b/dd;
				newpix[j*m + i] = 255<<24 | r<<16 | g<<8 | b;
				//255<<24 | r<<16 | g<<8 | b  这个公式解释一下,颜色的RGB在内存中是
				//以二进制的形式保存的,从右到左1-8位表示blue,9-16表示green,17-24表示red
				//所以"<<24" "<<16" "<<8"分别表示左移24,16,8位
				
				//newpix[j*m + i] = new Color(r,g,b).getRGB();
			}
		}
		
		BufferedImage imgOut = new BufferedImage( m, n, imgType);
		
		imgOut.setRGB(0, 0, m, n, newpix, 0, m);			
		return imgOut;
	}

 
/**
	 * 局部均值的图像缩小
	 * @param img 要缩小的图像对象
	 * @param m 缩小后图像的宽
	 * @param n 缩小后图像的高
	 * @return 返回处理后的图像对象
	 */
	public static BufferedImage shrink(BufferedImage img, int m, int n) {
		float k1 = (float)m/img.getWidth();
		float k2 = (float)n/img.getHeight();		
		return shrink(img, k1, k2);
	}
	
	/**
	  * 局部均值的图像缩小
	 * @param img 要缩小的图像对象
	 * @param k1 要缩小的列比列
	 * @param k2 要缩小的行比列
	 * @return 返回处理后的图像对象
	 */
	public static BufferedImage shrink(BufferedImage img, float k1, float k2) {
		if(k1 >1 || k2>1) {//如果k1 >1 || k2>1则是图片放大,不是缩小
			System.err.println("this is shrink image funcation, please set k1<=1 and k2<=1!");
			return null;
		} 
		float ii = 1/k1;	//采样的行间距
		float jj = 1/k2; //采样的列间距		
		int dd = (int)(ii*jj); 
		//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++) {
				int r = 0, g=0, b=0;
				ColorModel cm = ColorModel.getRGBdefault();				
				for(int k=0; k<(int)jj; k++) {
					for(int l=0; l<(int)ii; l++) {
						r = r + cm.getRed(pix[(int)(jj*j+k)*w + (int)(ii*i+l)]);
						g = g + cm.getGreen(pix[(int)(jj*j+k)*w + (int)(ii*i+l)]);
						b = b + cm.getBlue(pix[(int)(jj*j+k)*w + (int)(ii*i+l)]);
					}
				}
				r = r/dd;
				g = g/dd;
				b = b/dd;
				newpix[j*m + i] = 255<<24 | r<<16 | g<<8 | b;
				//255<<24 | r<<16 | g<<8 | b  这个公式解释一下,颜色的RGB在内存中是
				//以二进制的形式保存的,从右到左1-8位表示blue,9-16表示green,17-24表示red
				//所以"<<24" "<<16" "<<8"分别表示左移24,16,8位
				
				//newpix[j*m + i] = new Color(r,g,b).getRGB();
			}
		}
		
		BufferedImage imgOut = new BufferedImage( m, n, imgType);
		
		imgOut.setRGB(0, 0, m, n, newpix, 0, m);			
		return imgOut;
	}

双线性差值法放图像

子块四个顶点的坐标分别设为(0,0)、(1,0)、(0,1)、(1,1),对应的带处理的像素的坐标(c1,c2),0<c1<1, 0<y<1.则f(x,y)由上到下得到


f(x,0) = f(0,0) + c1*(f(1,0)-f(0,0))
f(x,1) = f(0,1) + c1*(f(1,1)-f(0,1))
f(x,y) = f(x,0) + c2*f(f(x,1)-f(x,0))

例,原图的像素矩阵如下。


将其放大成2.5*1.2倍,双线性插值发,填充顶点如下:


(1)

 

(2)

1  2  3  4  5  6  7  7

2  3  4  5  7  8  8  8

3  4  5  6  7  8  9  9

3  4  5  6  7  8  9  9

(3)

算法源代码(java)


/**
	 * 双线性插值法图像的放大
	 * @param img 要缩小的图像对象
	 * @param k1 要缩小的列比列
	 * @param k2 要缩小的行比列
	 * @return 返回处理后的图像对象
	 */
	public static BufferedImage amplify(BufferedImage img, float k1, float k2) {
		if(k1 <1 || k2<1) {//如果k1 <1 || k2<1则是图片缩小,不是放大
			System.err.println("this is shrink image funcation, please set k1<=1 and k2<=1!");
			return null;
		} 
		float ii = 1/k1;	//采样的行间距
		float jj = (1/k2); //采样的列间距		
		int dd = (int)(ii*jj); 
		//int m=0 , n=0;
		int imgType = img.getType();
		int w = img.getWidth();		//原图片的宽
		int h = img.getHeight();	//原图片的宽
		int m = Math.round(k1*w);	//放大后图片的宽
		int n = Math.round(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<h-1; j++){
			for(int i=0; i<w-1; i++) {
				int x0 = Math.round(i*k1);
				int y0 = Math.round(j*k2);
				int x1, y1;
				if(i == w-2) {
					x1 = m-1;
				} else {
					x1 = Math.round((i+1)*k1);
				}				
				if(j == h-2) {
					y1 = n-1;
				} else {
					y1 = Math.round((j+1)*k2);
				}				
				int d1 = x1 - x0;
				int d2 = y1 - y0;
				if(0 == newpix[y0*m + x0]) {
					newpix[y0*m + x0] =  pix[j*w+i];
				}
				if(0 == newpix[y0*m + x1]) {
					if(i == w-2) {
						newpix[y0*m + x1] = pix[j*w+w-1];
					} else {
						newpix[y0*m + x1] =  pix[j*w+i+1];
					}					
				}
				if(0 == newpix[y1*m + x0]){
					if(j == h-2) {
						newpix[y1*m + x0] = pix[(h-1)*w+i];
					} else {
						newpix[y1*m + x0] =  pix[(j+1)*w+i];
					}					
				}
				if(0 == newpix[y1*m + x1]) {
					if(i==w-2 && j==h-2) {
						newpix[y1*m + x1] = pix[(h-1)*w+w-1];
					} else {
						newpix[y1*m + x1] = pix[(j+1)*w+i+1];
					}					
				}
				int r, g, b;
				float c;
				ColorModel cm = ColorModel.getRGBdefault();				
				for(int l=0; l<d2; l++) {
					for(int k=0; k<d1; k++) {
						if(0 == l) {
							//f(x,0) = f(0,0) + c1*(f(1,0)-f(0,0))
							if(j<h-1 && newpix[y0*m + x0 + k] == 0) {
								c = (float)k/d1;
								 r = cm.getRed(newpix[y0*m + x0]) + (int)(c*(cm.getRed(newpix[y0*m + x1]) - cm.getRed(newpix[y0*m + x0])));//newpix[(y0+l)*m + k]
								 g = cm.getGreen(newpix[y0*m + x0]) + (int)(c*(cm.getGreen(newpix[y0*m + x1]) - cm.getGreen(newpix[y0*m + x0])));
								 b = cm.getBlue(newpix[y0*m + x0]) + (int)(c*(cm.getBlue(newpix[y0*m + x1]) - cm.getBlue(newpix[y0*m + x0])));
								 newpix[y0*m + x0 + k] = new Color(r,g,b).getRGB();
							}
							if(j+1<h && newpix[y1*m + x0 + k] == 0) {
								 c = (float)k/d1;
									r = cm.getRed(newpix[y1*m + x0]) + (int)(c*(cm.getRed(newpix[y1*m + x1]) - cm.getRed(newpix[y1*m + x0])));
									g = cm.getGreen(newpix[y1*m + x0]) + (int)(c*(cm.getGreen(newpix[y1*m + x1]) - cm.getGreen(newpix[y1*m + x0])));
									b = cm.getBlue(newpix[y1*m + x0]) + (int)(c*(cm.getBlue(newpix[y1*m + x1]) - cm.getBlue(newpix[y1*m + x0])));
									newpix[y1*m + x0 + k] = new Color(r,g,b).getRGB();
							 }
							//System.out.println(c);
						} else {
							//f(x,y) = f(x,0) + c2*f(f(x,1)-f(x,0))
							c = (float)l/d2;
							r = cm.getRed(newpix[y0*m + x0+k]) + (int)(c*(cm.getRed(newpix[y1*m + x0+k]) - cm.getRed(newpix[y0*m + x0+k])));
							g = cm.getGreen(newpix[y0*m + x0+k]) + (int)(c*(cm.getGreen(newpix[y1*m + x0+k]) - cm.getGreen(newpix[y0*m + x0+k])));
							b = cm.getBlue(newpix[y0*m + x0+k]) + (int)(c*(cm.getBlue(newpix[y1*m + x0+k]) - cm.getBlue(newpix[y0*m + x0+k])));
							newpix[(y0+l)*m + x0 + k] = new Color(r,g,b).getRGB(); 
							//System.out.println((int)(c*(cm.getRed(newpix[y1*m + x0+k]) - cm.getRed(newpix[y0*m + x0+k]))));
						}				
					}					
					if(i==w-2 || l==d2-1) {	//最后一列的计算
						//f(1,y) = f(1,0) + c2*f(f(1,1)-f(1,0))
						c = (float)l/d2;
						r = cm.getRed(newpix[y0*m + x1]) + (int)(c*(cm.getRed(newpix[y1*m + x1]) - cm.getRed(newpix[y0*m + x1])));
						g = cm.getGreen(newpix[y0*m + x1]) + (int)(c*(cm.getGreen(newpix[y1*m + x1]) - cm.getGreen(newpix[y0*m + x1])));
						b = cm.getBlue(newpix[y0*m + x1]) + (int)(c*(cm.getBlue(newpix[y1*m + x1]) - cm.getBlue(newpix[y0*m + x1])));
						newpix[(y0+l)*m + x1] = new Color(r,g,b).getRGB(); 
					}
				}
			}
		}
		/*
		for(int j=0; j<50; j++){
			for(int i=0; i<50; i++) {
				System.out.print(new Color(newpix[j*m + i]).getRed() + "\t");				
			}
			System.out.println();
		}
		*/
		BufferedImage imgOut = new BufferedImage( m, n, imgType);
		
		imgOut.setRGB(0, 0, m, n, newpix, 0, m);		
		return imgOut;
	}


本文转载自:http://blog.csdn.net/luoweifu/article/details/8069883

自由的角马
粉丝 1
博文 269
码字总数 0
作品 0
文山
私信 提问
【图像处理】图像灰度级减少, 图像缩放(Reducing the Number of Gray Levels, Zooming and Shrinking)

实验要求 (1.a) 编写一个以2 的幂次方将给定图像的灰度级数从256 减少到2 的程序。图像的灰度级数以参数变量的形式传递到所编写的程序中。 (1.b) 使用图2.21(a) 以(1.a)中编写的程序生成图2...

u013165921
2018/01/14
0
0
图像的上采样(upsampling)与下采样(downsampled)

缩小图像(或称为下采样(subsampled)或降采样(downsampled))的主要目的有两个:1、使得图像符合显示区域的大小;2、生成对应图像的缩略图。放大图像(或称为上采样(upsampling)或图像...

漫步当下
2018/05/04
550
0
常用的像素操作算法:Resize、Flip、Rotate

Resize 图像缩放是把原图像按照目标尺寸放大或者缩小,是图像处理的一种。 图像缩放有多种算法。最为简单的是最临近插值算法,它是根据原图像和目标图像的尺寸,计算缩放的比例,然后根据缩放...

fengzhizi715
2017/12/14
0
0
c语言数字图像处理(二):图片放大与缩小-双线性内插法

图像内插 假设一幅大小为500 500的图像扩大1.5倍到750 750,创建一个750 * 750 的网格,使其与原图像间隔相同,然后缩小至原图大小,在原图中寻找最接近的像素(或周围的像素)进行赋值,最后...

GoleBeetle
2018/09/17
0
0
【Python】Python基于opencv的图像压缩算法实例分析

本文实例讲述了Python基于opencv的图像压缩算法。分享给大家供大家参考,具体如下: 插值方法: CVINTERNN - 最近邻插值, CVINTERLINEAR - 双线性插值 (缺省使用) CVINTERAREA - 使用象素关系...

CS青雀
2019/03/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

toast组件单元测试

先看是否存在 describe('Toast', () => { it('存在.', () => { expect(Toast).to.be.exist }) }); 看属性,我们要测 ToastVue 和 plugin.js describe('Toast', () =>......

ories
27分钟前
57
0
如何将整个MySQL数据库字符集和排序规则转换为UTF-8?

如何将整个MySQL数据库字符集转换为UTF-8并将排序规则转换为UTF-8? #1楼 在命令行外壳上 如果您是命令行外壳程序之一,则可以非常快速地执行此操作。 只需填写“ dbname”:D DB="dbname"(...

javail
今天
80
0
开源矿工系统内部的层

开源矿工系统内部的层 所谓“层”、“界”、“域”、“集合”,这些词其实是在试图表达物质系统的组成结构和运动景象中的规矩,这些不同人发明的词都是来源于对同一个规律的观察、发现、表达...

NTMiner
今天
88
0
如何将文件从一个git repo移到另一个(不是克隆),保留历史记录

我们的Git储存库是作为单个Monster SVN储存库的一部分开始的,其中每个项目都有自己的树,如下所示: project1/branches /tags /trunkproject2/branches /tags ...

技术盛宴
今天
65
0
数据结构之数组-c代码实现

在上一篇文章里讲了数组的具体内容,然后自己使用c语言对数组进行了实现。 其中定义了一个结构体,定义了长度、已使用长度和地址指针。 定义alloc函数来分配内存空间 之后便是插入元素的ins...

无心的梦呓
今天
65
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部