图像插值算法(最近临插值算法)

对于图像缩放算法来说,最近临插值算法是最简单的。最近临插值算法的原理是在原图像中找到最近临的一个点,然后把这个点的像素值插入到目标图像中,最近临插值算法优点是算法简单,易于实现,但是缺点是由于相邻像素点的像素值相同,容易出现色块现象。

那么如何在原图像中找这个目标点呢,算法公式如下:

src_x = dst_x * (src_width / dst_width);
src_y = dst_y * (src_height / dst_height);

那么算出来呢,可能会是小数点,需要四舍五入取整,那么下面来看一个例子(一个3*3的矩阵):

234     38      22
67      44      12
89      65      63

这里呢,我们需要将上面的一个3*3矩阵变换成一个4*4的矩阵,我们根据上面的公式来计算一下,首先是目标点为(0,0),那么原图像的坐标点为(0,0),那么这个坐标点的值就应该为234,然后再来看(0,1)这个坐标点,那么纵坐标点还是0,但是横坐标点变成了1*(3/4) = 0.75,四舍五入得1,那么得到的原图像坐标为(0,1),那么这个坐标点值就应该为38,同理,最后得到的矩阵结果如下:

234	38	22	22	
67	44	12	12	
89	65	63	63	
89	65	63	63

这部分测试代码如下:

#include <stdio.h>

int main(int argc, char *argv[])
{
	int i, j, row, col;
	unsigned char mat1[3][3] = {{234, 38, 22},
				    {67, 44, 12},
				    {89, 65, 63}};
	unsigned char mat2[4][4];
	
	for (i = 0; i < 4; i++) {
		for (j = 0; j < 4; j++) {
			row = (int)(i * (3.0 / 4.0) + 0.5);
			col = (int)(j * (3.0 / 4.0) + 0.5);
			mat2[i][j] = mat1[row][col];
			printf("%d\t", mat2[i][j]);
		}
		printf("\n");
	}

	return 0;
}
关于对于图像的最近临插值算法我也写了一个测试代码(只针对bmp格式的图片,放大两倍):
#include <stdio.h>
#include <stdlib.h>

struct bitmap_fileheader {
	unsigned short	type;
	unsigned int	size;
	unsigned short	reserved1;
	unsigned short	reserved2;
	unsigned int	off_bits;
} __attribute__ ((packed));

struct bitmap_infoheader {
	unsigned int	size;
	unsigned int	width;
	unsigned int	height;
	unsigned short	planes;
	unsigned short	bit_count;
	unsigned int	compression;
	unsigned int	size_image;
	unsigned int	xpels_per_meter;
	unsigned int	ypels_per_meter;
	unsigned int	clr_used;
	unsigned int	clr_important;
} __attribute__ ((packed));

void resize_near(void *dst, void *src, int dst_width, int dst_height, int src_width, int src_height)
{
	int i, j, x, y;
	float scale_x, scale_y;

	char *buf1 = (char *)src, *buf2 = (char *)dst;

	scale_x = (float)src_width / (float)dst_width;
	scale_y = (float)src_height / (float)dst_height;

	for (i = 0; i < dst_height; i++) {
		for (j = 0; j < dst_width; j++) {
			y = (int)(i * scale_y + 0.5);
			x = (int)(j * scale_x + 0.5);
			
			buf2[i*dst_width*3 + j*3] = buf1[y*src_width*3 + x*3];
			buf2[i*dst_width*3 + j*3 + 1] = buf1[y*src_width*3 + x*3 + 1];
			buf2[i*dst_width*3 + j*3 + 2] = buf1[y*src_width*3 + x*3 + 2];
		}
	}
}

int main(int argc, char *argv[])
{
	FILE *fp1, *fp2;
	struct bitmap_fileheader fh;
	struct bitmap_infoheader ih;

	void *buf1, *buf2;

	int src_width, src_height, dst_width, dst_height;

	if (argc < 2)
		return -1;

	fp1 = fopen(argv[1], "rb");
	if (fp1 == NULL) {
		printf("open file %s failed!\n", argv[1]);
		return -1;
	}

	fread(&fh, 1, sizeof(struct bitmap_fileheader), fp1);

	fread(&ih, 1, sizeof(struct bitmap_infoheader), fp1);
	src_width = ih.width;
	src_height = ih.height;

	buf1 = malloc(ih.width * ih.height * (ih.bit_count / 8));
	fread(buf1, 1, ih.width * ih.height * (ih.bit_count / 8), fp1);

	fp2 = fopen("resize.bmp", "wb");
	if (fp2 == NULL) {
		printf("open file resize.bmp failed!\n");
		return -1;
	}

	dst_width = src_width * 2;
	dst_height = src_height * 2;

	ih.width = dst_width;
	ih.height = dst_height;

	fh.size = fh.off_bits + ih.width * ih.height * (ih.bit_count / 8);
	fwrite(&fh, 1, sizeof(struct bitmap_fileheader), fp2);

	fwrite(&ih, 1, sizeof(struct bitmap_infoheader), fp2);

	buf2 = malloc(ih.width * ih.height * (ih.bit_count / 8));
	resize_near(buf2, buf1, dst_width, dst_height, src_width, src_height);

	fwrite(buf2, 1, ih.width * ih.height * (ih.bit_count / 8), fp2);

	free(buf1);

	free(buf2);

	fclose(fp1);

	fclose(fp2);

	return 0;
}

如果用opencv来做,那就很简单了,直接使用opencv提供的cvResize函数,代码如下:

#include <highgui.h>
#include <cv.h>

int main(int argc, char *argv[])
{
	IplImage *img1, *img2;

	if (argc < 2)
		return -1;

	img1 = cvLoadImage(argv[1]);
	img2 = cvCreateImage(CvSize(img1->width*2, img1->height*2), img1->depth, img1->nChannels);
	
	cvResize(img1, img2, CV_INTER_LINEAR);
					/* 	CV_INTER_NN
						CV_INTER_LINEAR
						CV_INTER_AREA
						CV_INTER_CUBIC */

	cvSaveImage("test.jpg", img2);

	cvReleaseImage(&img1);
	cvReleaseImage(&img2);

	return 0;
}
其中参数CV_INTER_NN对应最近临插值算法,CV_INTER_LINEAR对应双线性插值算法。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值