图像放缩之双线性内插值

简介: 一:数学原理 在临近点插值的数学基础上,双线性插值,不是简单copy源像素的值,而是获取四个最邻 近目标像素的像素值乘以权重系数,简单的数学公式可以表示为: D(x, y) = S(j, k) * a + S(j+1, k) *b + S(j+1,k+1) * c + S(j, K+1...

一:数学原理

在临近点插值的数学基础上,双线性插值,不是简单copy源像素的值,而是获取四个最邻

近目标像素的像素值乘以权重系数,简单的数学公式可以表示为:

D(x, y) = S(j, k) * a + S(j+1, k) *b + S(j+1,k+1) * c + S(j, K+1) * d             公式一

 

问题转化如何提取源像素的中四个临近点,根据临近点插值中从目标像素寻找最临近的源像

素点的方法:

Sx= Dx * (Sh/Dh) // row

Sy= Dy * (Sw/Dw) // column

公式的详细说明参见这里http://blog.csdn.net/jia20003/article/details/6907152

计算出来的值是浮点数坐标,分别取整数部分坐标为(j, k), 小数部分坐标为(t, u)


根据小数部分的(t,u)坐标,首先进行水平方向的权重计算得出

Q11 = S(j,k) * (1-t) + S(j, k+1) * t;

Q22 = S(j+1, k) * (1-t) + S(j+1,K+1) *t

利用Q11, Q22的值,进行垂直方向权重计算得出计算采样点值

D(x, y) = Q11*(1-u) + Q22 * u; 把Q11, Q22带入,最终有等式:

D(x, y) = S(j, k) *(1-t)*(1-u) + S(j, k+1)*t*(1-u) + S(j+1,k)*(1-t)*u + S(j+1,k+1)*t*u

从而得出四个对应的权重系数分别为:

a = (1-t)*(1-u)

b = (1-t)*u

c = t*u

d = t*(1-u)

带入公式一,即可得出目标像素的值。

 

二:双线性内插值算法优缺点

双线性内插值算法在图像的放缩处理中,具有抗锯齿功能, 是最简单和常见的图像放缩算法,但是双线性内插值算法没有考虑边缘和图像的梯度变化,相比之下双立方插值算法更好解决这些问题。

 

三:关键程序代码解析

根据目标像素坐标,计算采样点浮点数坐标的代码如下:

float rowRatio = ((float)srcH)/((float)destH);

float colRatio = ((float)srcW)/((float)destW);

double srcRow = ((float)row)*rowRatio;

double srcCol = ((float)col)*colRatio;

 

计算采样点的整数坐标和小数部分坐标代码如下:

double j = Math.floor(srcRow);

double t = srcRow – j

double k = Math.floor(srcCol);

double u = srcCol - k;

 

根据小数坐标(t,u)来计算四个相邻像素点权重系数代码如下:

double coffiecent1 = (1.0d-t)*(1.0d-u);

double coffiecent2 = (t)*(1.0d-u);

double coffiecent3 = t*u;

double coffiecent4 = (1.0d-t)*u;

 

处理边缘像素代码如下:

return x>max ? max : x<min? min : x;

 

四:程序运行效果如下


左边为源图像,右边为基于双线性内插值放大两倍以后的图像


五:双线性内插值JAVA算法代码

public class BilineInterpolationScale implements ImageScale {
	public BilineInterpolationScale() {
		
	}
	/**
	 * 
	 */
	@Override
	public int[] imgScale(int[] inPixelsData, int srcW, int srcH, int destW, int destH) {
		double[][][] input3DData = processOneToThreeDeminsion(inPixelsData, srcH, srcW);
		int[][][] outputThreeDeminsionData = new int[destH][destW][4];
		float rowRatio = ((float)srcH)/((float)destH);
		float colRatio = ((float)srcW)/((float)destW);
		for(int row=0; row<destH; row++) {
			// convert to three dimension data
			double srcRow = ((float)row)*rowRatio;
			double j = Math.floor(srcRow);
			double t = srcRow - j;
			for(int col=0; col<destW; col++) {
				double srcCol = ((float)col)*colRatio;
				double k = Math.floor(srcCol);
				double u = srcCol - k;
				double coffiecent1 = (1.0d-t)*(1.0d-u);
				double coffiecent2 = (t)*(1.0d-u);
				double coffiecent3 = t*u;
				double coffiecent4 = (1.0d-t)*u;
				
				
				outputThreeDeminsionData[row][col][0] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][0] +
				coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][0] +
				coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0] +
				coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][0]); // alpha
				
				outputThreeDeminsionData[row][col][1] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][1] +
						coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][1] +
						coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1] +
						coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][1]); // red
				
				outputThreeDeminsionData[row][col][2] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][2] +
						coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][2] +
						coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2] +
						coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][2]);// green
				
				outputThreeDeminsionData[row][col][3] = (int)(coffiecent1 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)k,srcW-1, 0)][3] +
						coffiecent2 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)k,srcW-1,0)][3] +
						coffiecent3 * input3DData[getClip((int)(j+1),srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3] +
						coffiecent4 * input3DData[getClip((int)j,srcH-1,0)][getClip((int)(k+1),srcW-1,0)][3]); // blue
			}
		}
		
		return convertToOneDim(outputThreeDeminsionData, destW, destH);
	}
	
	private int getClip(int x, int max, int min) {
		return x>max ? max : x<min? min : x;
	}
	
	/* <p> The purpose of this method is to convert the data in the 3D array of ints back into </p>
	 * <p> the 1d array of type int. </p>
	 * 
	 */
	public int[] convertToOneDim(int[][][] data, int imgCols, int imgRows) {
		// Create the 1D array of type int to be populated with pixel data
		int[] oneDPix = new int[imgCols * imgRows * 4];


		// Move the data into the 1D array. Note the
		// use of the bitwise OR operator and the
		// bitwise left-shift operators to put the
		// four 8-bit bytes into each int.
		for (int row = 0, cnt = 0; row < imgRows; row++) {
			for (int col = 0; col < imgCols; col++) {
				oneDPix[cnt] = ((data[row][col][0] << 24) & 0xFF000000)
						| ((data[row][col][1] << 16) & 0x00FF0000)
						| ((data[row][col][2] << 8) & 0x0000FF00)
						| ((data[row][col][3]) & 0x000000FF);
				cnt++;
			}// end for loop on col


		}// end for loop on row


		return oneDPix;
	}// end convertToOneDim
	
	private double [][][] processOneToThreeDeminsion(int[] oneDPix2, int imgRows, int imgCols) {
		double[][][] tempData = new double[imgRows][imgCols][4];
		for(int row=0; row<imgRows; row++) {
			
			// per row processing
			int[] aRow = new int[imgCols];
			for (int col = 0; col < imgCols; col++) {
				int element = row * imgCols + col;
				aRow[col] = oneDPix2[element];
			}
			
			// convert to three dimension data
			for(int col=0; col<imgCols; col++) {
				tempData[row][col][0] = (aRow[col] >> 24) & 0xFF; // alpha
				tempData[row][col][1] = (aRow[col] >> 16) & 0xFF; // red
				tempData[row][col][2] = (aRow[col] >> 8) & 0xFF;  // green
				tempData[row][col][3] = (aRow[col]) & 0xFF;       // blue
			}
		}
		return tempData;
	}


}


目录
相关文章
|
测试技术
Fiddler 使用fiddler无法抓取苹果手机https请求问题解决方案
Fiddler 使用fiddler无法抓取苹果手机https请求问题解决方案
566 0
|
3天前
|
弹性计算 人工智能 安全
云上十五年——「弹性计算十五周年」系列客户故事(第二期)
阿里云弹性计算十五年深耕,以第九代ECS g9i实例引领算力革新。携手海尔三翼鸟、小鹏汽车、微帧科技等企业,实现性能跃升与成本优化,赋能AI、物联网、智能驾驶等前沿场景,共绘云端增长新图景。
|
9天前
|
存储 弹性计算 人工智能
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
2025年9月24日,阿里云弹性计算团队多位产品、技术专家及服务器团队技术专家共同在【2025云栖大会】现场带来了《通用计算产品发布与行业实践》的专场论坛,本论坛聚焦弹性计算多款通用算力产品发布。同时,ECS云服务器安全能力、资源售卖模式、计算AI助手等用户体验关键环节也宣布升级,让用云更简单、更智能。海尔三翼鸟云服务负责人刘建锋先生作为特邀嘉宾,莅临现场分享了关于阿里云ECS g9i推动AIoT平台的场景落地实践。
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
|
8天前
|
人工智能 自然语言处理 自动驾驶
关于举办首届全国大学生“启真问智”人工智能模型&智能体大赛决赛的通知
关于举办首届全国大学生“启真问智”人工智能模型&智能体大赛决赛的通知
|
8天前
|
云安全 人工智能 自然语言处理
阿里云x硅基流动:AI安全护栏助力构建可信模型生态
阿里云AI安全护栏:大模型的“智能过滤系统”。
|
9天前
|
编解码 自然语言处理 文字识别
Qwen3-VL再添丁!4B/8B Dense模型开源,更轻量,仍强大
凌晨,Qwen3-VL系列再添新成员——Dense架构的Qwen3-VL-8B、Qwen3-VL-4B 模型,本地部署友好,并完整保留了Qwen3-VL的全部表现,评测指标表现优秀。
662 7
Qwen3-VL再添丁!4B/8B Dense模型开源,更轻量,仍强大
|
4天前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
|
11天前
|
存储 机器学习/深度学习 人工智能
大模型微调技术:LoRA原理与实践
本文深入解析大语言模型微调中的关键技术——低秩自适应(LoRA)。通过分析全参数微调的计算瓶颈,详细阐述LoRA的数学原理、实现机制和优势特点。文章包含完整的PyTorch实现代码、性能对比实验以及实际应用场景,为开发者提供高效微调大模型的实践指南。
790 2