算法分析
- 開辟新矩陣存放旋轉后的圖像。計算公式如下,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開辟新矩陣,使得旋轉后的圖像不能完整顯示