基于非棋盘网格相机标定点自动顺序排序算法解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cuixing001/article/details/81194145

      相机标定技术是计算机视觉中最常不过的方向了,目前绝大数都是通过棋盘网格的图像进行相机标定,这是最通用最省时间的办法,因为棋盘图像标定前人已经做的非常完善,提供现成的函数或者方法流程,如OpenCV中的findChessboardCornerscalibrateCamera等函数,Matlab中如detectCheckerboardPointsestimateCameraParameters等函数。这里不会对现有的技术或者函数接口使用进行重复解析,本篇针对非棋盘网格点集排序算法进行解析和实现。

     网格点集目的提取的顺序为“从上到下,从左到右”的原则,跟OpenCV找点顺序一致。

一、示例提取顺序主代码

        在实际标定中,用网格图像代替棋盘图像(当然棋盘图像是网格图像的特例,黑白块都是正方形)更具有通用性,网格交叉点一般是m*n列角点,这些角点一般通过一定算法检测得到,这里为了方便起见,直接人工生成一些点集,点集分布如图1所示。图2 为排序后的点集。

function main_sort()
% 功能:相机标定点顺序提取,对无序点集按照“从上到下,从左到右”的原则排序。
% author:cuixingxing
% email: [email protected]
% 2018.7.23
%
%% Step1, 人工制造6*10个投影变换点,并打乱排列顺序
mode = [6,10];% 标定点模式,m*n个点
[X,Y] = meshgrid(1:mode(2),1:mode(1));
T = [-2.7379,0.2929,0.01;
    0.7426,-0.75,-0.05;
    0,0,1.00];% 手工设定的透视变换矩阵
coordates = [X(:),Y(:),ones(length(X(:)),1)];
new_coords = coordates*T;
new_coords = new_coords./new_coords(:,3);

% 制造打乱顺序的点集,数字表示坐标唯一编号
n = length(X(:));
index = randperm(n,n);
unorder_pts = new_coords(index,[1,2]);
figure;
hold on;
for i = 1:n
    plot(unorder_pts(i,1),unorder_pts(i,2),'r.','MarkerSize',20);
    text(unorder_pts(i,1)+0.2,unorder_pts(i,2),num2str(i))
end
grid on
title('unordered points')

%% Step2,算法排序
order_mat_index = CalibSort(unorder_pts,mode);

%% Step3, 结果显示,排序好的索引应用到原无序点集坐标,并逐个按顺序绘制
figure;
hold on;
n = 1;
for i = 1:mode(1)
    for j = 1:mode(2)
        index = order_mat_index(i,j);
        plot(unorder_pts(index,1),unorder_pts(index,2),'r.','MarkerSize',20);
        text(unorder_pts(index,1)+0.1,unorder_pts(index,2),num2str(n));
        n = n+1;
    end
end
grid
title('ordered points')
end

                             

                                                                图1  人工产生的6*10无序点集(数字表示序号)

                                        

                                                                                                      图2  算法排序后的点集

二、排序算法思路

 功能:相机标定点顺序提取,对无序点集按照“从上到下,从左到右”的原则排序。
 思路:首先根据四边形点集先找到对角角点(判断所有点是否在对角直线同侧),然后过角点找其紧邻的2条边线, 根据一角点边线与另一对角角点边线求交点坐标即为另外的角点,四个角点顺序确定后,通过预先规定的对应四点坐标计算透视变换矩阵,其次通过透视变换把所有点映射到到正方形上面来,最后对正方形上面的点集进行“从上到下,从左到右”的原则排序,排序好的索引应用到原无序点集即可完成。

对于第一部分代码中的第二步排序函数,order_mat_index = CalibSort(unorder_pts,mode)是核心,其中unorder_pts是无序二维坐标点集,输入大小为n*2,mode为点集行列数,如上例,就是6*10,输入大小为1*2。输出order_mat_index是一个矩阵,矩阵里面每个元素存储原始无序点集unorder_pts的索引。

获取四边形对角点实现如下:

扫描二维码关注公众号,回复: 3017500 查看本文章
function [Diag_corner1,Diag_corner2] = GetDiagPts(unorder_pts)
% 功能:由四边形点集获取一组对角角点
% 输入:unorder_pts,n*2 double无序点集
% 输出:Diag_corner1 , 1*2 double 一个角点坐标
%       Diag_corner2 , 1*2 double 另一个对角角点坐标
%
% author:cuixingxing
% email: [email protected]
% 2018.7.23
%
[~,x_creasing_Ind] = sort(unorder_pts(:,1));
[~,y_creasing_Ind] = sort(unorder_pts(:,2));
Lconner_pt = unorder_pts(x_creasing_Ind(1),:);% 对应左下角或左上角
Rconner_pt = unorder_pts(x_creasing_Ind(end),:);% 对应右下角或右上角
Uconner_pt = unorder_pts(y_creasing_Ind(1),:);
Dconner_pt = unorder_pts(y_creasing_Ind(end),:);
conners = [Lconner_pt;
    Rconner_pt;
    Uconner_pt;
    Dconner_pt];

line = struct('point1',[],'point2',[]);
for i = 1:4
    conner_i = conners(i,:);
    for j = i+1:4
        conner_j = conners(j,:);
        if ~all(conner_i== conner_j)
            line.point1 = conner_i;
            line.point2 = conner_j;
            flag = JudgeSameSide(line,unorder_pts);
            if ~flag
                Diag_corner1 = conner_i;
                Diag_corner2 = conner_j;
            end
        end
    end
end
        

                                                                                        图3     四边形4个角点位置

判定点集是否在直线同侧JudgeSameSide(),也是判定凸多边形的一种方式,

function flag = JudgeSameSide(line,unorder_pts)
% 功能:判断点/点集是否在直线同一侧
% 输入:line , 1*1 struct ,含有域point1,point2, 两点式直线。
%       unorder_pts, n*2 double 点/点集坐标
% 输出: flag, bool,true时表示点/点集在直线line同一侧(包含在直线上的点),否则不是
% 两点式方程化为标准式为:(y1-y2)*x+(x2-x1)*y = x2*y1-x1*y2
% author:cuixingxing
% email: [email protected]
% 2018.7.23
%

x1 = line.point1(1);
y1 = line.point1(2);
x2 = line.point2(1);
y2 = line.point2(2);
x = unorder_pts(:,1);
y = unorder_pts(:,2);

A = (y1-y2).*x+(x2-x1).*y - x2*y1+x1*y2;

threshold = 1.0e-3;%设定合适的阈值,避免点在直线上计算的误差
if all(A+threshold>=0)||all(A-threshold<=0)
    flag = true;
else
    flag = false;
end

接着下一步是根据角点找边线,这里直接给出结果图,如图4所示。

                                                                                      图4 边线确定

三、一些其他的无序点集排序

这里给出其他几对对比图像。

代码下载链接:https://download.csdn.net/download/cuixing001/10562090

猜你喜欢

转载自blog.csdn.net/cuixing001/article/details/81194145
今日推荐