Skip to content

Commit

Permalink
re #375
Browse files Browse the repository at this point in the history
Enable construction/init of CalRigMLStro from "Rig Specification" (official name tbd) YAML file. This empowers users with calibration parameters from 3rd party sources.

Note that CalRigMLStro relies on MATLAB/Vision routines for vision, triangulation, etc.
  • Loading branch information
allenleetc committed Apr 4, 2022
1 parent 488e82e commit 54f8bf5
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 8 deletions.
30 changes: 30 additions & 0 deletions matlab/CalibratedCamera.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
classdef CalibratedCamera < handle
properties
ImageSize % [nr nc]
FocalLengths % [fx fy]
PrincipalPoint % [px py]
Skew % scalar
RadialDistortions % [k2 k4]
Rotation % [rx ry rz] rodrigues vec
Translation % [tx ty tz]
end
methods
function obj = CalibratedCamera(s)
for fn = fieldnames(s)', f=fn{1};
try
obj.(f) = s.(f);
catch
warning('Ignoring unrecognized field: %s', f);
end
end
end

function camInts = getMatlabCameraIntrinsics(obj)
camInts = cameraIntrinsics(...
obj.FocalLengths,obj.PrincipalPoint,obj.ImageSize,...
'Skew',obj.Skew,...
'RadialDistortion',obj.RadialDistortions...
);
end
end
end
59 changes: 59 additions & 0 deletions matlab/CameraSet.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
classdef CameraSet < handle
properties
NumCameras
CameraNames
Cameras
end

methods
function obj = CameraSet(s)
if ischar(s)
s = ReadYaml(s);
end
obj.NumCameras = s.NumCameras;
obj.CameraNames = s.CameraNames;

for icam=1:s.NumCameras
cam = s.CameraNames{icam};
camObjs(icam) = CalibratedCamera(s.(cam)); %#ok<AGROW>
end
fprintf(1,'Read information for %d cameras: %s.\n',s.NumCameras, ...
String.cellstr2CommaSepList(s.CameraNames));

obj.Cameras = camObjs;
end

function [R,t] = getXformCams(obj,cam1,cam2)
% Get/compute matrices R,T that convert from cam1 coordsys to
% cam2coordsys; defined by
%
% [x2;y2;z2] = R*[x1;y1;z1] + t

c1 = obj.Cameras(cam1);
c2 = obj.Cameras(cam2);

R1 = rodrigues(c1.Rotation);
t1 = c1.Translation(:);
R2 = rodrigues(c2.Rotation);
t2 = c2.Translation(:);

R = R2/R1;
t = -R*t1 + t2;
end

function sp = getMatlabStereoParameters(obj)
if obj.NumCameras~=2
error('stereoParameters conversion only avaiable when NumCameras==2.');
end

cams = obj.Cameras;
sp = struct();
sp.CameraParameters1 = cams(1).getMatlabCameraIntrinsics;
sp.CameraParameters2 = cams(2).getMatlabCameraIntrinsics;

[R,t] = obj.getXformCams(1,2);
sp.RotationOfCamera2 = R;
sp.TranslationOfCamera2 = t;
end
end
end
48 changes: 40 additions & 8 deletions matlab/user/CalRigMLStro.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
% Note: ML Stro Calib App requires all ims/views to have the same size.

properties
calSess % scalar Session from ML Stro calibration
nonMLinit = false; % if true, obj is not initialized from MATLAB stereo calibration
calSess % scalar Session from ML Stro calibration; or if .nonMLinit, scalar struct mirroring calSession object

eplineComputeMode = 'mostaccurate'; % either 'mostaccurate' or 'fastest'
end
Expand Down Expand Up @@ -62,30 +63,50 @@
methods

function obj = CalRigMLStro(calSess,varargin)
% calibSession: either a char filename for saved result from ML
% Stereo Calib App; or the object within
% obj = CalRigMLStro(calSess)
% calSess: one of:
% 1. a char filename for saved result from ML Stereo Calib App;
% 2. the ML calibration Session object saved therein;
% 3. char filename for APT-style rig config/param YAML file;
% 4. a YAML struct for such YAML contents

offerSave = myparse(varargin, ...
'offerSave',true...
);

isYamlRig = false;
if ischar(calSess)
s = load(calSess,'-mat','calibrationSession');
calSessObj = s.calibrationSession;
[~,~,ext] = fileparts(calSess);
switch ext
case '.yaml'
s = ReadYaml(calSess);
calSessObj = CalRigMLStro.rigYaml2CalSess(s);
isYamlRig = true;
case '.mat'
s = load(calSess,'-mat','calibrationSession');
calSessObj = s.calibrationSession;
end
elseif isa(calSess,'vision.internal.calibration.tool.Session')
calSessObj = calSess;
elseif isstruct(calSess) && isfield(calSess,'NumCameras')
calSessObj = CalRigMLStro.rigYaml2CalSess(calSess);
isYamlRig = true;
else
error('Input argument must be a MATLAB Stereo Calibration Session.');
end

obj.calSess = calSessObj;
obj.nonMLinit = isYamlRig;
obj.int = obj.getInt();

obj.eplineComputeMode = 'mostaccurate';
%obj.autoCalibrateProj2NormFuncTol();
obj.proj2NormFuncTol = nan; % AL20220302 no longer used
obj.autoCalibrateEplineZrange();
obj.runDiagnostics();

if ~isYamlRig
obj.autoCalibrateEplineZrange();
obj.runDiagnostics();
end

if offerSave
if ischar(calSess)
Expand Down Expand Up @@ -836,7 +857,12 @@ function rperrPlot(rperrcam1,rperrcam2)
xp1ud = cat(1,xp1ud{:});
xp2ud = arrayfun(@(i)undistortPoints(xp2(:,i)',cp2),(1:n)','uni',0);
xp2ud = cat(1,xp2ud{:});
X1 = triangulate(xp1ud,xp2ud,sp);
cm1 = cameraMatrix(cp1,eye(3),[0 0 0]);
cm2 = cameraMatrix(cp2,sp.RotationOfCamera2,sp.TranslationOfCamera2);
X1 = triangulate(xp1ud,xp2ud,cm1,cm2);
% X1 = triangulate(...,sp);
% Don't use this sig beacuse in the case of .nonMLinit, MATLAB/Vision
% doesn't ducktype and requires a real stereoParameters type

xp1rp = worldToImage(cp1,eye(3),[0;0;0],X1,'applyDistortion',true);
xp2rp = worldToImage(cp2,...
Expand Down Expand Up @@ -904,6 +930,12 @@ function rperrPlot(rperrcam1,rperrcam2)
alpha_c = camParams.Skew;
assert(isscalar(alpha_c));
end
function cs = rigYaml2CalSess(s)
% s: struct, rig yaml
cs = struct();
cs.cameraSet = CameraSet(s);
cs.CameraParameters = cs.cameraSet.getMatlabStereoParameters();
end
end

end

0 comments on commit 54f8bf5

Please sign in to comment.