基于PCA的有向包围盒(Oriented Bounding Box)生成及图像倾斜校正

前言

之前文章:PCA(主成分分析)降维可视化Matlab实现有说到过PCA(主成分分析)降维的方法。PCA使用方差来表征数据在新变量上的信息大小,它把数据进行正交变换,将原本线性相关表示的数据映射成多个线性无关新变量表示的数据。通过选取主成分(数据在该新变量上的投影方差大)来近似原始数据。PCA降维的基本思想就是找到方差最大的前K个的投影方向K<D(数据维度)

基于PCA的有向包围盒(Oriented Bounding Box)生成

对于二维图像,我们也可以使用PCA找到主方向,将数据投影到该方向及其垂直方向上。如下图,其中指向PCA的主方向,theta为相应角度:
在这里插入图片描述
那么如何实现呢?

  1. 首先进行规范化(为了后续简单我没有对数据规范化)
  2. 求出数据的协方差矩阵:covariance = cov(data)
  3. 对协方差矩阵求特征值:eigVector = eigs(covariance)
  4. 将数据乘以特征值进行映射dataMapped = data*eigVector
  5. 找到映射后坐标(包括主成分和第二主成分方向)的最大值max最小值min
  6. 包围盒的长宽分别为相应方向上的极差max-min
  7. 包围盒的中心坐标为最大最小值的平均值centerMapped = (max+min)/2反向映射后的坐标center = center/eigVector
  8. 将包围盒的半轴乘以方向的正余弦作为包围盒边界点距离中心点的偏移量offset = extends*[cosθ sinθ]

图像倾斜校正

关于图像倾斜校正部分,我们使用主成分对应的方向来进行校正,通过将数据乘上相应的旋转变量,使得主成分对应的特征向量与坐标轴平行。

如下图:
在这里插入图片描述

下面是相关Matlab代码:

% Oriented Bounding box and tilt correction using PCA(Principle component analysis)
% Coded by Weichen GU 2020/4/28th
clear,clc,clf;

% load digit_100;
% idx = 25,2,64,68,69,28
% idx = 25;
% V1=reshape(train_data(idx,:),28,28)';
% [row, col] = find(V1~=0);
% data = [col 30-row];


%data = [3.7, 4.1, 4.7, 5.2, 6.0, 6.3, 9.7, 10.0, 11.0, 12.5; 1.7, 3.8, 2.9, 2.8, 4.0, 3.6, 6.3, 4.9, 3.6, 6.4]'
data = [0 0.5 1 4 4.2; 9.2 7.1 8.2 5.2 6.9]'


covariance = cov(data);                         % Obtain covariance matrix
[eigVector, eigValue] = eigs(covariance);       % Obtain eigenVector and eigenValue

mu = mean(data);                 % Obtain the mean of dataSet
%data_Mu_0 = data-mu;            % shift data to origional
coordMapped = data*eigVector;                  % mapping data to principle components(1, 2)
theta = atan2(eigVector(2,:),eigVector(1,:));       % Obtain the angle of eigen vectors(1, 2)
theta = mod(theta,pi);           % Convert theta to [0 pi)
extends = (max(coordMapped)-min(coordMapped))/2;    % Obtain the semi-length and semi-width of bounding box
%center = mean(coordMapped);
centerMapped = (max(coordMapped)+min(coordMapped))/2;
center = centerMapped/eigVector;

offSet = (extends.*[cos(theta); sin(theta)])'
weight = [-1 1; -1 -1; 1 1; 1 -1];% Left-Top, Left-Bottom, Right-Top, Right-Bottom
coord = center + weight*offSet
coord = [coord;center];

figure(1);
plot(data(:,1),data(:,2),'b.');
num = 30;
set(gca,'XLim',[0,num]);
set(gca,'YLim',[0,num]);
axis equal;
hold on;
plot(coord(:,1),coord(:,2),'r.','Markersize',10);
line([coord(1,1) coord(2,1)],[coord(1,2) coord(2,2)]);
line([coord(1,1) coord(3,1)],[coord(1,2) coord(3,2)]);
line([coord(4,1) coord(2,1)],[coord(4,2) coord(2,2)]);
line([coord(4,1) coord(3,1)],[coord(4,2) coord(3,2)]);

draw_arrow(coord(5,:),coord(5,:)+[cos(theta(1)), sin(theta(1))],1);
a=num2str(mod(theta(1)*180/pi,180));
legend(strcat('theta = ', a, '^°'));


% Rotation transformation
if (mod(theta(1),pi) > pi/4 && mod(theta(1),pi) < 3/4*pi )
    rotAngle = pi/2-mod(theta(1),pi);
elseif(mod(theta(1),pi) < pi/4)
    rotAngle = -mod(theta(1),pi);
else
    rotAngle = pi -mod(theta(1),pi);
end
    rotMatrix = [cos(rotAngle) sin(rotAngle); -sin(rotAngle) cos(rotAngle)];
finalAngle = theta(1)+rotAngle;

dataS =(data-center) * rotMatrix + center;
hold off;


coord = (coord-center) * rotMatrix + center;;    % bbox coordinate

figure(2)
plot(dataS(:,1),dataS(:,2),'b.');
hold on;
num = 30;
set(gca,'XLim',[0,num]);
set(gca,'YLim',[0,num]);
axis equal;
plot(coord(:,1),coord(:,2),'r.','Markersize',10);
line([coord(1,1) coord(2,1)],[coord(1,2) coord(2,2)]);
line([coord(1,1) coord(3,1)],[coord(1,2) coord(3,2)]);
line([coord(4,1) coord(2,1)],[coord(4,2) coord(2,2)]);
line([coord(4,1) coord(3,1)],[coord(4,2) coord(3,2)]);
draw_arrow(center,center+[cos(finalAngle), sin(finalAngle)],1);

a=num2str(mod(finalAngle*180/pi,180));
legend(strcat('theta = ', a, '^°'));

hold off
%http://www.mathworks.com/matlabcentral/fileexchange/27475-arrow-plotter/content/draw_arrow.m
function out = draw_arrow(startpoint,endpoint,headsize)
    %by Ryan Molecke 
    % accepts two [x y] coords and one double headsize 
    v1 = headsize*(startpoint-endpoint)/2.5; 
    theta = 22.5*pi/180; 
    theta1 = -1*22.5*pi/180; 
    rotMatrix = [cos(theta)  -sin(theta) ; sin(theta)  cos(theta)];
    rotMatrix1 = [cos(theta1)  -sin(theta1) ; sin(theta1)  cos(theta1)];  
    v2 = v1*rotMatrix; 
    v3 = v1*rotMatrix1; 
    x1 = endpoint;
    x2 = x1 + v2; 
    x3 = x1 + v3; 
    hold on; 
    fill([x1(1) x2(1) x3(1)],[x1(2) x2(2) x3(2)],[0 0 0]);% this fills the arrowhead (black) 
    plot([startpoint(1) endpoint(1)],[startpoint(2) endpoint(2)],'linewidth',1,'color',[0 0 0]);
end

使用MNIST数据集的简单测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

通过PCA方法生成有向包围盒的方法直观且易于实现,对于目标中心轴最大主成分对应的方向平行的图像倾斜校正效果不错,但是对于中心轴不平行的情况,可能适得其反
在这里插入图片描述
对于数字序列,也可以做整体倾斜校正,用于校正因拍摄视角引起图像倾斜。如下:
在这里插入图片描述
下图是使用极对数-欧拉映射对印章部分字母进行校正的结果:
在这里插入图片描述

这里给出文中使用的MNIST数据的下载链接

参考链接

https://hewjunwei.wordpress.com/2013/01/26/obb-generation-via-principal-component-analysis/
https://blog.csdn.net/u013512448/article/details/52527237
https://blog.csdn.net/qing101hua/article/details/53100112

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值