算法分析
- 开辟新矩阵存放旋转后的图像。计算公式如下,H为原图像行,W原图像列,a为旋转角度,a是钝角时,三角函数需要加上绝对值
DH = H * abs(cos(a)) + W * abs(sin(a));
DW = H * abs(sin(a)) + W * abs(cos(a));
-
计算旋转后的坐标(旋转方向为逆时针)。利用原坐标点与旋转矩阵相乘,公式如下,x,y为原坐标,a为旋转角度,x\',y\'为旋转后的坐标
-
利用近邻插值给旋转后的图像赋上灰度值。由于是根据旋转后的新矩阵坐标映射回原矩阵中的坐标求其灰度值,所以对旋转矩阵求逆矩阵R,原像素位置记为src,中心点记为center1,旋转后像素位置记为dst,中心点记为center2,近邻插值(四舍五入取近似值),整理为以下公式:
src = round(R * (dst - center2) + center1)
若是彩色图则每个通道都如上赋值
双线性插值:其中i,j为当前点的坐标,u为i坐标的偏移量,v为j坐标的偏移量
f(i+u,j+v) = (1-u)(1-v)f(i,j)+u(1-v)f(i+1,j)+(1-u)vf(i,j+1)+ uvf(i+1,j+1)
近邻插值伪代码
function outputimg = myimrotate(A,angle)
% 利用近邻插值法将图像旋转
% 输入:A是读入的图像矩阵,angle是旋转角度(0-360),angle取正为逆时针旋转,取负为顺时针旋转
% 输出:outputimg是输出的图像矩阵
a = 旋转角度/180 * pi
R = 旋转矩阵
R = 求逆矩阵
[H,W,CH] = 图像的长、宽、通道
%当旋转角度为钝角(顺时针旋转)时加上绝对值
DH = 根据步骤1的公式求出新矩阵的行
DW = 根据步骤1的公式求出新矩阵的行
outputimg = 按照DH和DW新开辟一个矩阵
center1 = 原图像中心坐标
center2 = 新矩阵中心坐标
遍历新矩阵
dst = 新矩阵中当前点的坐标
src = 根据步骤3的公式求得当前点对应在原图上的点的坐标
如果src的坐标点在原图上没有越界)
outputimg(i,j,:) = 将各个通道对应点在原图的像素值赋给新矩阵
将outputimg类型转换为uint8便于显示图像;
end
双线性插值伪代码
function outputimg = myimrotate_bilinear(A,angle)
% 利用双线性插值法将图像旋转
% A是读入的图像矩阵,angle是旋转角度(0-360),angle取正为逆时针旋转,取负为顺时针旋转
% outputimg是输出的图像矩阵
a = 旋转角度/180 * pi
R = 旋转矩阵
R = 逆矩阵
[H,W,CH] = 图像的长、宽、通道
%当旋转角度为钝角(顺时针旋转)时加上绝对值
DH = 根据步骤1的公式求出新矩阵的行
DW = 根据步骤1的公式求出新矩阵的行
outputimg = 按照DH和DW新开辟一个矩阵
center1 = 原图像中心坐标
center2 = 新矩阵中心坐标
遍历新矩阵
dst = 新矩阵中的当前点
src = 根据步骤3的公式求得当前点对应在原图上的点的坐标(行、列)
%双线性插值
a = 对求得的src向下取整
offset = 计算的src的偏移量
u = i坐标(行)的偏移量
v = j坐标(列)的偏移量
i = 当前点向下取整之后行坐标
j = 当前点向下取整之后列坐标
如果i,j,并且(i+1)、(j+1)没有越界
outputimg(di,dj,:) = 将各个通道对应点根据步骤4公式所求得的在原图上的像素值赋给新矩阵
将outputimg类型转换为uint8便于显示图像
end
近邻插值代码
function outputimg = myimrotate_neighbor(A,angle)
% 利用近邻插值法将图像旋转
% A是读入的图像矩阵,angle是旋转角度
% outputimg是输出的图像矩阵
%角度转换,求旋转矩阵的逆矩阵
a = angle / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)]; %旋转矩阵
R = R\'; %求逆矩阵
%根据原图矩阵生成输出图像所需画布矩阵的大小
[H,W,CH] = size(A);
DH = ceil(H * abs(cos(a)) + W * abs(sin(a))); %当顺时针旋转时加上绝对值
DW = ceil(H * abs(sin(a)) + W * abs(cos(a)));
outputimg = zeros(DH,DW,CH);
center1 = [H;W] / 2;
center2 = [DH;DW] / 2;
for i = 1:DH
for j = 1:DW
dst = [i; j];
%利用的向量的旋转原理,再与旋转矩阵相乘
src = round(R * (dst - center2) + center1); %四舍五入近邻插值
% 逆向进行像素查找
if (src(1) >= 1 && src(1) <= H && src(2) >= 1 && src(2) <= W)
outputimg(i,j,:) = A(src(1), src(2),:);
end
end
end
outputimg = uint8(outputimg);
end
实验结果
%调用示例:
A = imread(\'cameraman.tif\');
B = myimrotate_neighbor(A,30);
subplot(1,2,1),imshow(A),title(\'原图\');
subplot(1,2,2),imshow(B),title(\'旋转30°的图像\');
灰度图逆时针30°旋转:
彩色图顺时针30°旋转(等同于逆时针旋转330°):
双线性插值代码
function outputimg = myimrotate_bilinear(A,angle)
% 利用双线性插值法将图像旋转
% A是读入的图像矩阵,angle是旋转角度
% outputimg是输出的图像矩阵
%角度转换,求旋转矩阵的逆矩阵
a = angle / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)];
R = R\';
%根据原图矩阵生成输出图像所需画布矩阵的大小
[H,W,CH] = size(A);
DH = floor(H * cos(a) + W * sin(a)); %向上取整
DW = floor(H * sin(a) + W * cos(a));
outputimg = zeros(DH,DW,CH);
center1 = [H;W] / 2;
center2 = [DH;DW] / 2;
for di = 1:DH
for dj = 1:DW
dst = [di; dj];
%利用的向量的旋转原理,再与旋转矩阵相乘
src = (R * (dst - center2) + center1);
%双线性插值
a = floor(src); %向下取整
offset = src - a; %计算的偏移量
u = offset(1); %x的偏移量
v = offset(2); %y的偏移量
i = a(1);
j = a(2);
% 逆向进行像素查找
if (src(1) >= 1 && src(1) <= H - 1 && src(2) >= 1 && src(2) <= W - 1)
outputimg(di,dj,:) = (1-u)*(1-v)*A(i, j, :) + (1 - u) * v * A(i, j + 1, :) + u * (1 - v) * A(i + 1, j, :) + u * v * A(i + 1, j + 1, :);
end
end
end
outputimg = uint8(outputimg);
end
% 调用示例:
A = imread(\'cameraman.tif\');
B = myimrotate_bilinear(A,30);
C = myimrotate_neighbor(A,30);
subplot(1,3,1),imshow(A),title(\'原图\');
subplot(1,3,2),imshow(C),title(\'近邻插值旋转\');
subplot(1,3,3),imshow(B),title(\'双线性插值旋转\');
实验结果
实验分析
- 映射关系的对应,需要根据旋转后的开辟的新矩阵找在原图中的位置,如下图所示,由原图去给新图像赋像素值的时候,有些坐标映射过来是包含小数,在原图上根本找不到,所以得到部分空点(灰度值=0)
- 新矩阵的开辟,如上图未根据算法分析步骤1开辟新矩阵,使得旋转后的图像不能完整显示
请发表评论