-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathvisodom.m
210 lines (158 loc) · 6.01 KB
/
visodom.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
function visodom
%% Visual odometry example
% - stereo camera
% Copyright 2022-2023 Peter Corke, Witold Jachimczyk, Remo Pillat
if ~exist("doVisodomFigures", "var")
doVisodomFigures = false;
end
close all
%% read images
tformFcn = @(in) imcrop(im2uint8(imadjust(in)), [17 17 730 460]);
left = imageDatastore(fullfile(rvctoolboxroot,"examples","visodom", "left"));
left = left.transform(tformFcn);
right = imageDatastore(fullfile(rvctoolboxroot,"examples","visodom", "right"));
right = right.transform(tformFcn);
% % ###############################################################################
% % # Camera parameter file #
% % ###############################################################################
% %
% % [INTERNAL]
% % F = 985.939 # [pixel] focal length
% % SX = 1.0 # [pixel] pixel size in X direction
% % SY = 1.0 # [pixel] pixel size in Y direction
% % X0 = 390.255 # [pixel] X-coordinate of principle
% % Y0 = 242.329 # [pixel] Y-coordinate of principle
% %
% % [EXTERNAL]
% % B = 0.20 # [m] width of baseline of stereo camera rig
% % X = -0.83 # [m] distance of rectified images (virtual camera)
% % Y = 0.00 # [m] lateral position of rectified images (virtual camera)
% % Z = 1.28 # [m] height of rectified images (virtual camera)
% % TILT = 0.0062 # [rad] tilt angle
% % YAW = 0.0064 # [rad] yaw angle
% % ROLL = 0.0009 # [rad] roll angle
% %
% % # Notes:
% % # In a stereo camera system the internal parameters for both cameras are the
% % # same.
% % #
% % # The camera position (X, Y, Z) is given in car coordinates.
% % # For the definition of the camera and car coordinate system and the rotation
% % # angles see the image carcameracoord.png.
%%
f = 985.939; % [pixel] focal length
u0 = 390.255; % [pixel] X-coordinate of principle
v0 = 242.329; % [pixel] Y-coordinate of principle
b = 0.20; % [m] width of baseline of stereo camera rig
frameSize = size(left.read(), [1 2]);
left.reset()
camIntrinsics = cameraIntrinsics(f, [u0, v0], frameSize);
rng(0)
i=0;
figure; figure; % make two empty figures
% matching
while left.hasdata()
i = i+1;
% for every frame
L = left.read();
R = right.read();
ptsL = detectORBFeatures(L);
ptsR = detectORBFeatures(R);
[orbfL, vptsL] = extractFeatures(L, ptsL);
[orbfR, vptsR] = extractFeatures(R, ptsR);
idxPairs = matchFeatures(orbfL, orbfR, "Unique", true);
matchedPtsL = vptsL(idxPairs(:,1));
matchedPtsR = vptsR(idxPairs(:,2));
matchedfL = binaryFeatures(orbfL.Features(idxPairs(:,1), :));
[Estereo, inlierIdx] = estimateEssentialMatrix(matchedPtsL, matchedPtsR, camIntrinsics, ...
"MaxDistance", 0.2, "Confidence", 95);
inlierPtsL = matchedPtsL(inlierIdx);
inlierPtsR = matchedPtsR(inlierIdx);
inlierfL = binaryFeatures(matchedfL.Features(inlierIdx, :));
p1 = inlierPtsL.Location';
p2 = inlierPtsR.Location';
d = p1(1,:) - p2(1,:);
d(d < 5*eps("single")) = eps("single"); % Avoid division by zero
X = b * (p1(1,:) - u0) ./ d;
Y = b * (p1(2,:) - v0) ./ d;
Z = f * b ./ d;
P = [X' Y' Z'];
if i > 1 % if we have a previous frame
% show the stereo matching in the current frame
figure(1);
showMatchedFeatures(L,R, inlierPtsL, inlierPtsR);
title("Stereo matching");
drawnow;
if doVisodomFigures
if i == 10
rvcprint3('fig14_57a')
end
end
% robustly match all the inliers from this frame with the inliers
% from previous frame - temporal match
idxPairs = matchFeatures(inlierfLp, inlierfL, "Unique", true);
matchedPtsLp = inlierPtsLp(idxPairs(:,1));
matchedPtsL = inlierPtsL(idxPairs(:,2));
[Etemporal, inlierIdx] = estimateEssentialMatrix(matchedPtsL, matchedPtsLp, camIntrinsics, ...
"MaxDistance", 0.2, "Confidence", 95);
inlierPts1 = matchedPtsLp(inlierIdx);
inlierPts2 = matchedPtsL(inlierIdx);
% and plot them
figure(2);
showMatchedFeatures(L,Lp, inlierPts1, inlierPts2);
title("Left frame temporal matching");
drawnow
if doVisodomFigures
if i == 10
rvcprint3('fig14_57b')
end
end
% Isolate P entries corresponding to inliers
Psubset = Pp(idxPairs(:,1),:); % 1 for previous set of points P
Psubset = Psubset(inlierIdx,:);
% Set up and solve bundle adjustment problem. Use motion only
% bundle adjustment which simply moves the camera while leaving the
% points alone.
absPose1 = rigid3d();
[refinedPose, e] = bundleAdjustmentMotion(Psubset, inlierPts2, absPose1, ...
camIntrinsics, 'PointsUndistorted', true); % 'Verbose', true
tz(i-1) = refinedPose.Translation(3); % store the Z coordinate which is the camera displacement for the vehicle moving forward
eout(i-1) = mean(e);
end
% keep images and features for next cycle
inlierPtsLp = inlierPtsL;
inlierfLp = inlierfL;
Pp = P;
Lp = L;
Rp = R;
end
%% process the results
% time stamps
ts = load(fullfile(rvctoolboxroot,"examples","visodom","timestamps.dat"));
dts = diff(ts);
idxHighVal = dts > 0.06;
subplot(311)
plot(tz, '.-', 'MarkerSize', 15)
ylabel("Camera displacement (m)")
hold on
xdata = 1:250;
plot(tz(idxHighVal), 'x', 'MarkerSize', 15, "Xdata", xdata(idxHighVal))
legend("displacement", "missed video frame")
grid on
subplot(312)
plot(eout, '.-', 'MarkerSize', 15)
set(gca, 'YScale', 'log')
ylabel("Average error (pix)")
grid on
subplot(313)
plot(dts, '.', 'MarkerSize', 15)
ylim([0.04, 0.1]);
xlabel("Time step")
ylabel("\Delta T")
grid on
f = gcf;
f.Position = [2049 248 1672 1774];
if doVisodomFigures
rvcprint3("fig14_52");
end
end