目录
前言
fitgeotrans 求变换矩阵
imwarp 根据变换信息转换图像
imref2d
程序
前言
差不多两个月没写了,要毕业了,写毕业论文,腾不出来心思写东西。
今天,在写毕业论文时需要插一个实验材料(一块钢板)的图片,我翻了翻相册,发现之前做实验时拍的不好,钢板放歪了,如图1-1所示。
图1-1 放歪的实验钢板
Fig1.1 @#$&^&*(&^&^
这直接插到论文里不太好,还是想把它给放正了。于是在网上搜“怎么把图片中的物体摆正”,结果都是用PS做的。
我电脑没装PS啊!
我就想了想,这玩意不就是做一个透视变换么?MATLAB有现成的工具箱能用啊,哎,还是花几分钟写几行MATLAB程序处理一下吧。
老早前看过一点点MATLAB图像处理的书,对一些函数和概念还有一些模糊的印象。
下面先介绍三个关键的函数/类,然后再给出程序。
fitgeotrans 求变换矩阵
Fit geometric transformation to control point pairs
tform = fitgeotrans(movingPoints,fixedPoints,transformationType)
takes the pairs of control points, movingPoints and fixedPoints, and uses them to infer the geometric transformation specified by transformationType.
这个函数需要:
-
movingPoints 原图中的几个控制点(根据需要选取);
-
fixedPoints 变换后的控制点;
-
transformationType 变换的类型。
返回一个对象,包含了变换矩阵的信息。
这里我要做的是透视变换(透视变换等价于中心投影变换),所以transformationType就选取projective,别的就不说了。
有个需要注意的(后面会用到),我们选择的第一个控制点对应的变换后的点,是变换后的图像的世界坐标系的原点(时间久了,不确定是不是这么说的,反正我记得是这么理解的)。
图2-1 图像的世界坐标系
Fig2.1 ^&*#%&#%$&*#
imwarp 根据变换信息转换图像
Apply geometric transformation to image
B = imwarp(A,tform, Name, Value)
transforms the numeric, logical, or categorical image A according to the geometric transformation tform. The function returns the transformed image in B. Specifies name-value pair arguments to control various aspects of the geometric transformation.
这个就根据上面计算出来的包含变换矩阵信息的对象tform将图像A变换成图像B。通过指定Name-Value可以设置一些转换的效果。
Name-Value这我就用了'OutputView'这个属性,还有两个我没用上,大家可以自己看看帮助文档。
B = imwarp(A,tform, 'OutputView', imref2d)
imref2d 是一个类,下面单独介绍一下
imref2d
Reference 2-D image to world coordinates
An imref2d object stores the relationship between the intrinsic coordinates anchored to the rows and columns of a 2-D image and the spatial location of the same row and column locations in a world coordinate system.
The image is sampled regularly in the planar world-x and world-y coordinate system such that intrinsic-x values align with world-x values, and intrinsic-y values align with world-y values. The resolution in each dimension can be different.
这是一个MATLAB的类,我用的时候就关注了它的三个properties,别的也没多想:
-
ImageSize:设置一下转化后的图像的长和宽
-
XWorldLimits:设置图像的世界坐标系X方向的范围
-
YWorldLimits:设置一下图像的世界坐标系Y方向的范围
只显示XWorldLimits和YWorldLimits范围内的图像。
世界坐标系的原点就是我们开始时选的第一个控制点
程序
clc
clear
close all
%% 读入图片
pic = imread('perspective.jpg');
%% 显示原图
fig1 = figure('Name', 'Original', 'ToolBar', 'none');
ax1 = axes('Parent', fig1, 'NextPlot', 'add');
imshow(pic, 'Parent', ax1);
%% 标定顶点,逆时针(如果 顺时针结果不大对劲,可能是我再后面的控制点没对应上)
coor1 = ginput(1); % 左下
scatter(coor1(1), coor1(2), 'Marker', 'o', 'MarkerFaceColor', 'r', 'Parent', ax1);
coor2 = ginput(1); % 右下
scatter(coor2(1), coor2(2), 'Marker', 'o', 'MarkerFaceColor', 'r', 'Parent', ax1);
line([coor1(1), coor2(1)], [coor1(2), coor2(2)], 'Color', 'k', 'LineWidth', 2);
coor3 = ginput(1); % 右上
scatter(coor3(1), coor3(2), 'Marker', 'o', 'MarkerFaceColor', 'r', 'Parent', ax1);
line([coor2(1), coor3(1)], [coor2(2), coor3(2)], 'Color', 'k', 'LineWidth', 2);
coor4 = ginput(1); % 左上
scatter(coor4(1), coor4(2), 'Marker', 'o', 'MarkerFaceColor', 'r', 'Parent', ax1);
line([coor3(1), coor4(1)], [coor3(2), coor4(2)], 'Color', 'k', 'LineWidth', 2);
line([coor4(1), coor1(1)], [coor4(2), coor1(2)], 'Color', 'k', 'LineWidth', 2);
coors = [coor1; coor2; coor3; coor4];
% 计算图中的物体的长宽,用于算出变换后的坐标
width = sqrt(sum( (coor2 - coor1).^2) );
height = sqrt(sum( (coor4 - coor1).^2) );
%% 根据图中物体的长宽,计算出投影变换后的大致的 与上述标定顶点 对应的坐标点
base_coors = [1, 1; ...
width+1, 1; ...
width+1, height+1; ...
1, height+1];
%% 获取变换矩阵
% 根据变换前和变换后的点计算出变换矩阵
tform = fitgeotrans(coors, base_coors, 'projective');
%% 根据变换矩阵求出变换后的结果,并裁剪出我们想要的部分
% 第一个标定的点是世界坐标系的原点
output_view = imref2d;
output_view.ImageSize = [fix(height), fix(width)]; % 高是多少行,宽是多少列
output_view.XWorldLimits = [1, width+1]; % 世界坐标系 x 的范围(多宽)
output_view.YWorldLimits = [1, height+1]; % 世界坐标系 y 的范围(多高)
pic_perspective = imwarp(pic, tform, 'OutputView', output_view); % ,'XData',[1 width+1],'YData',[1 height+1]
%% 显示变换后的结果
fig2 = figure('Name', 'Perspective');
ax2 = axes('Parent', fig2, 'NextPlot', 'add');
imshow(pic_perspective, 'Parent', ax2);
测试结果1:
看上去还凑合吧,下面我再拿我的一卡通试试看看。
测试结果2:
这还行。