图像缩放——快速最近领域插值法

最近邻域插值法原理:

根据目标图像的像素点(浮点坐标)找到原始图像中的4个像素点,取距离该像素点最近的一个原始像素值作为该点的值。

未优化之前:

unsigned char* ScaleNearest(unsigned char* srcImg,
						   int dstWidth, int dstHeight, 
						   int srcWidth, int srcHeight)
{
	int i,j;
	int dstRowBytes;
	int srcRowBytes;
	float xScale;
	float yScale;
	int x,y;
	unsigned char* dst;
	unsigned char* src;
	unsigned char* dstImg;

	x = y = 0;

	dstRowBytes = (dstWidth * 3 + 3) & ~3;
	srcRowBytes = (srcWidth * 3 + 3) & ~3;
    
	dstImg = (unsigned char*)malloc(dstHeight * dstRowBytes);
	if(!dstImg)
		return NULL;
	memset(dstImg, 255, dstRowBytes * dstHeight);

	xScale = (float)srcWidth / (float)dstWidth;
	yScale = (float)srcHeight / (float)dstHeight;

	for(i = 0; i < dstHeight; i++)
	{
		for(j = 0; j < dstWidth; j++)
		{   
			//根据目标图像坐标、缩放倍数确定原始图像点,取上整
			x = (int)(j * xScale + 0.5);
			y = (int)(i * yScale + 0.5);
			//必须做边界判断,缩放后的边界会出现不想要的结果,比如,原始为白色的,缩放后的图片可能在边界出现彩色
			if(x >= srcWidth)
				x = srcWidth - 1;
			if(y >= srcHeight)
				y = srcHeight -1;
			dst = dstImg + i * dstRowBytes + 3*j;
			src = srcImg + y * srcRowBytes + 3*x;
			*dst = *src;
			dst++,src++;
			*dst = *src;
			dst++,src++;
			*dst   = *src;
		}
	}
	return dstImg;
}

优化思路:对每一行,y其实固定;对每一列,x固定,另外边界也没有必须图像中的每个点都要判断一次,所以把这几行:

			//根据目标图像坐标、缩放倍数确定原始图像点,取上整
			x = (int)(j * xScale + 0.5);
			y = (int)(i * yScale + 0.5);
			//必须做边界判断,缩放后的边界会出现不想要的结果,比如,原始为白色的,缩放后的图片可能在边界出现彩色
			if(x >= srcWidth)
				x = srcWidth - 1;
			if(y >= srcHeight)
				y = srcHeight -1;

单独处理,做成表格,以供查询。另外,这几行:

			dst = dstImg + i * dstRowBytes + 3*j;
			src = srcImg + y * srcRowBytes + 3*x;

乘法可以换成加法运算,尽量避免乘法运算。

优化之后的代码如下:

int *x_table = NULL;
int *y_table = NULL;

//创建表格
int init_scale(int dst_width, int dst_height, int src_width, int src_height)
{   
	int i;
	double x_scale;
	double y_scale;
	int x;
	int y;
	if(x_table)
		free(x_table);
	if(y_table)
		free(y_table);
	x_table = (int*)malloc(dst_width * sizeof(int));
	if(!x_table)
		return -1;
	y_table = (int*)malloc(dst_height * sizeof(int));
	if(!y_table)
	{
		free(x_table);
		x_table = NULL;
		return -1;
	}

	x_scale = (double)src_width / (double)dst_width;
	y_scale = (double)src_height / (double)dst_height;

	for(i = 0; i < dst_width; i++)
	{
		x = (int) (i * x_scale + 0.5);
		if(x >= src_width)
			x = src_width - 1;
		x_table[i] = x;
	}
	for(i = 0; i < dst_height; i++)
	{
		y = (int) (i * y_scale + 0.5);
		if(y >= src_height)
			y = src_height -1;
		y_table[i] = y;
	}
	return 0;
}

unsigned char* ScaleNearest(unsigned char* srcImg,
							int dstWidth, int dstHeight, 
							int srcWidth, int srcHeight)
{
	int i,j;
	int dstRowBytes;
	int srcRowBytes;

	int x,y;
	unsigned char* dst;
	unsigned char* src;
	unsigned char* dstImg;
	unsigned char* ptr;
    int gap;

	x = y = 0;
	dstRowBytes = (dstWidth * 3 + 3) & ~3;
	srcRowBytes = (srcWidth * 3 + 3) & ~3;
	dstImg = (unsigned char*)malloc(dstHeight * dstRowBytes);
    gap = dstRowBytes - dstWidth * 3;
	if(!dstImg)
		return NULL;
	dst = dstImg;
	src = srcImg;
	for(i = 0; i < dstHeight; i++)
	{   
		y = y_table[i];
        ptr = srcImg + y*srcRowBytes;
		for(j = 0; j < dstWidth; j++)
		{   
			x = x_table[j];
			src = ptr + (x << 1) + x;

			*dst = *src;
			dst++,src++;
			*dst = *src;
			dst++,src++;
			*dst   = *src;
			dst++;
		}
		dst += gap;
	}
	return dstImg;
}

这样处理之后,算法就比之前的快多了。顺带说一句,最近邻域插值跟二次线性、最小立方插值等缩放算法相比,主观效果差很多,但是其保留边缘,在某些特殊环境还是有其用途。



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值