Open WarpPrism opened 7 years ago
数字图像处理的第一次作业就是用图像的插值算法实现图片的放缩,在网上查了一些资料后,总结如下:
首先我们定义几个变量:
- 原图矩阵: Source - 目标图矩阵: Destination - 宽度缩放比: ratioW - 高度缩放比: ratioH
先得到原图的宽和高
Source = imread('src.png'); [srcM, srcN] = size(Source);
接着根据下面的公式计算出目标图的宽和高:
ratioW = dstM / srcM; ratioH = dstN / srcN;
新建目标图,根据目标图的大小建立一个空的Matrix,记作M
Destination = zeros(dstM, dstN); M = Destination;
然后要对M中的每个点赋值,即所谓的插值运算,这个值从哪里来呢?当然是原图。
现在 设M矩阵的坐标点为(dx, dy),则它对应的原图坐标(sx, sy)满足:
dx / sx = dstM / srcM; dy / sy = dstN / srcN;
这样我们就能求出
(sx, sy) = (dx * srcM / dstM, dy * srcN / dstN);
到此,我们就把目标图中的坐标点映射到原图中去了
但是这个坐标点不一定是整数,假如(2, 0) 映射的结果为 (0.75, 0),这显然是不科学的,怎么办呢? 第一种方法,四舍五入 得到 (1, 0),然后把原图中(1, 0)点的像素值赋给目标图的(2, 0)位置即可:
fd(2, 0) = fs(1, 0);
这种放大图像的方法就叫做 最临近插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真。
另一种算法就是双线性插值算法,它的失真情况会好很多。
算法思路是: 对于一个目的像素,映射后得到的浮点坐标为(i+u,j+v), (其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素得值 f(dx,dy) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
f(dx, dy) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
这里我们就可以由原图中的 4 个像素点推出了目标图中1个像素点,最后遍历目标图,我们就能实现图片的放缩了。
双线性插值算法代码如下所示:
% Bilinear Function function [ output_img ] = scale( input_img, Size ) % Using bilinear algorithm to change the SIZE of input_img. dstM = Size(1); dstN = Size(2); [srcM srcN]=size(input_img); output_img = zeros(dstM, dstN); for i = 1:dstM - 1 for j = 1:dstN - 1 src_i = i * (srcM / dstM); src_j = j * (srcN / dstN); int_i = fix(src_i); int_j = fix(src_j); u = src_i - int_i; v = src_j - int_j; if int_i == 0 int_i = int_i + 1; end if int_j == 0 int_j = int_j + 1; end output_img(i,j)=(1-u)*(1-v)*input_img(int_i,int_j)+(1-u)*v*input_img(int_i,int_j+1) +u*(1-v)*input_img(int_i+1,int_j)+u*v*input_img(int_i+1,int_j+1); end end output_img = uint8(output_img); figure,imshow(input_img) axis on figure,imshow(output_img) axis on end % call function scale() close all clear all clc input_img = imread('test.png') size = [100, 100] output_img = scale(input_img, size) imtool(output_img)
数字图像处理的第一次作业就是用图像的插值算法实现图片的放缩,在网上查了一些资料后,总结如下:
首先我们定义几个变量:
先得到原图的宽和高
接着根据下面的公式计算出目标图的宽和高:
新建目标图,根据目标图的大小建立一个空的Matrix,记作M
然后要对M中的每个点赋值,即所谓的插值运算,这个值从哪里来呢?当然是原图。
现在 设M矩阵的坐标点为(dx, dy),则它对应的原图坐标(sx, sy)满足:
这样我们就能求出
到此,我们就把目标图中的坐标点映射到原图中去了
但是这个坐标点不一定是整数,假如(2, 0) 映射的结果为 (0.75, 0),这显然是不科学的,怎么办呢? 第一种方法,四舍五入 得到 (1, 0),然后把原图中(1, 0)点的像素值赋给目标图的(2, 0)位置即可:
这种放大图像的方法就叫做 最临近插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真。
另一种算法就是双线性插值算法,它的失真情况会好很多。
算法思路是: 对于一个目的像素,映射后得到的浮点坐标为(i+u,j+v), (其中i、j均为浮点坐标的整数部分,u、v为浮点坐标的小数部分,是取值[0,1)区间的浮点数),则这个像素得值 f(dx,dy) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
这里我们就可以由原图中的 4 个像素点推出了目标图中1个像素点,最后遍历目标图,我们就能实现图片的放缩了。
双线性插值算法代码如下所示: