Subversion Repositories seema-scanner

Rev

Rev 237 | Rev 239 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 237 Rev 238
1
function MSE = alignSubScansMarkers(calibrationFileName, alnFileName)
1
function MSE = alignSubScansMarkers(calibrationFileName, alnFileName)
2
%ALIGNSUBSCANSMARKERS Determines an exact alignment of sub scans (scans
2
%ALIGNSUBSCANSMARKERS Determines an exact alignment of sub scans (scans
3
% from e.g. one revolution of the rotation stage). 
3
% from e.g. one revolution of the rotation stage). 
4
% The method searches for circular white markers of a specific diameter.
4
% The method searches for circular white markers of a specific diameter.
5
% White frames corresponding to each sub scan must be available.
5
% White frames corresponding to each sub scan must be available.
6
% A coarse alignment in the form of an aln-file must be provided. 
6
% A coarse alignment in the form of an aln-file must be provided. 
7
%
7
%
8
% 2017 Jakob Wilm, DTU
8
% 2017 Jakob Wilm, DTU
9
 
9
 
10
initialAlign = readMeshLabALN(alnFileName);
10
initialAlign = readMeshLabALN(alnFileName);
11
[alnFilePath, ~, ~] = fileparts(alnFileName);
11
[alnFilePath, ~, ~] = fileparts(alnFileName);
12
 
12
 
13
calibration = readOpenCVXML(calibrationFileName);
13
calibration = readOpenCVXML(calibrationFileName);
14
 
14
 
15
% correct for Matlab 1-indexing in principle point coordinates
15
% correct for Matlab 1-indexing in principle point coordinates
16
calibration.K0(1:2, 3) = calibration.K0(1:2, 3)+1;
16
calibration.K0(1:2, 3) = calibration.K0(1:2, 3)+1;
17
calibration.K1(1:2, 3) = calibration.K1(1:2, 3)+1;
17
calibration.K1(1:2, 3) = calibration.K1(1:2, 3)+1;
18
 
18
 
19
% full projection matrices in Matlab convention
19
% full projection matrices in Matlab convention
20
P0 = transpose(calibration.K0*[eye(3) zeros(3,1)]);
20
P0 = transpose(calibration.K0*[eye(3) zeros(3,1)]);
21
P1 = transpose(calibration.K1*[calibration.R1 calibration.T1']);
21
P1 = transpose(calibration.K1*[calibration.R1 calibration.T1']);
22
 
22
 
23
% matlab cam params for undistortion
23
% matlab cam params for undistortion
24
camParams0 = cameraParameters('IntrinsicMatrix', calibration.K0', 'RadialDistortion', calibration.k0([1 2 5]), 'TangentialDistortion', calibration.k0([3 4]));
24
camParams0 = cameraParameters('IntrinsicMatrix', calibration.K0', 'RadialDistortion', calibration.k0([1 2 5]), 'TangentialDistortion', calibration.k0([3 4]));
25
camParams1 = cameraParameters('IntrinsicMatrix', calibration.K1', 'RadialDistortion', calibration.k1([1 2 5]), 'TangentialDistortion', calibration.k1([3 4]));
25
camParams1 = cameraParameters('IntrinsicMatrix', calibration.K1', 'RadialDistortion', calibration.k1([1 2 5]), 'TangentialDistortion', calibration.k1([3 4]));
26
 
26
 
27
% matlab struct for triangulation
27
% matlab struct for triangulation
28
camStereoParams = stereoParameters(camParams0, camParams1, calibration.R1', calibration.T1');
28
camStereoParams = stereoParameters(camParams0, camParams1, calibration.R1', calibration.T1');
29
 
29
 
30
nSubScans = length(initialAlign);
30
nSubScans = length(initialAlign);
31
 
31
 
32
% 3D coordinates of markers in local camera frame
32
% 3D coordinates of markers in local camera frame
33
E = cell(nSubScans, 1);
33
E = cell(nSubScans, 1);
34
 
34
 
35
% 3D coordinates of markers in global initial alignment
35
% 3D coordinates of markers in global initial alignment
36
Eg = cell(size(E));
36
Eg = cell(size(E));
37
 
37
 
38
% find 3D markers coordinates 
38
% find 3D markers coordinates 
39
for i=1:nSubScans
39
for i=1:nSubScans
40
%for i=5:5
40
%for i=5:5
41
    % load point cloud
41
    % load point cloud
42
    pcFileName = fullfile(alnFilePath, initialAlign(i).FileName);
42
    pcFileName = fullfile(alnFilePath, initialAlign(i).FileName);
43
    pcFilePath = fileparts(pcFileName);
43
    pcFilePath = fileparts(pcFileName);
44
    pc = pcread(pcFileName);
44
    pc = pcread(pcFileName);
45
    Q = pc.Location;
45
    Q = pc.Location;
46
    idString = strsplit(initialAlign(i).FileName, {'.ply', '_'});
46
    idString = strsplit(initialAlign(i).FileName, {'.ply', '_'});
47
    idString = idString{end-1};
47
    idString = idString{end-1};
48
    
48
    
49
    % load white frames
49
    % load white frames
50
    frame0 = imread(fullfile(pcFilePath, ['sequence_' idString], 'frames0_0.png'));
50
    frame0 = imread(fullfile(pcFilePath, ['sequence_' idString], 'frames0_0.png'));
51
    frame1 = imread(fullfile(pcFilePath, ['sequence_' idString], 'frames1_0.png'));
51
    frame1 = imread(fullfile(pcFilePath, ['sequence_' idString], 'frames1_0.png'));
52
 
52
 
53
    e0Coords = autoDetectMarkers(frame0);
53
    e0Coords = autoDetectMarkers(frame0);
54
    e1Coords = autoDetectMarkers(frame1);
54
    e1Coords = autoDetectMarkers(frame1);
55
    
55
    
56
    %e0Coords = manuallyDetectMarkers(frame0);
56
    %e0Coords = manuallyDetectMarkers(frame0);
57
    %e1Coords = manuallyDetectMarkers(frame1);
57
    %e1Coords = manuallyDetectMarkers(frame1);
58
    
58
    
59
    %[e0Coords, conf0] = detectMarkersSubpix(frame0, e0Coords, P0, Q);
59
    %[e0Coords, conf0] = detectMarkersSubpix(frame0, e0Coords, P0, Q);
60
    %[e1Coords, conf1] = detectMarkersSubpix(frame1, e1Coords, P1, Q);
60
    %[e1Coords, conf1] = detectMarkersSubpix(frame1, e1Coords, P1, Q);
61
 
61
 
62
    if(length(e0Coords) < 1 || length(e1Coords) < 1)
62
    if(length(e0Coords) < 1 || length(e1Coords) < 1)
63
        continue;
63
        continue;
64
    end
64
    end
65
    
65
    
66
%     figure; 
66
%     figure; 
67
%     subplot(1,2,1);
67
%     subplot(1,2,1);
68
%     imshow(frame0);
68
%     imshow(frame0);
69
%     hold('on');
69
%     hold('on');
70
%     plot(e0Coords(:,1), e0Coords(:,2), 'rx', 'MarkerSize', 15);
70
%     plot(e0Coords(:,1), e0Coords(:,2), 'rx', 'MarkerSize', 15);
71
%     subplot(1,2,2);
71
%     subplot(1,2,2);
72
%     imshow(frame1);
72
%     imshow(frame1);
73
%     hold('on');
73
%     hold('on');
74
%     plot(e1Coords(:,1), e1Coords(:,2), 'rx', 'MarkerSize', 15);
74
%     plot(e1Coords(:,1), e1Coords(:,2), 'rx', 'MarkerSize', 15);
75
%     drawnow;
75
%     drawnow;
76
    
76
    
77
    e0Coords = undistortPoints(e0Coords, camParams0);
77
    e0Coords = undistortPoints(e0Coords, camParams0);
78
    e1Coords = undistortPoints(e1Coords, camParams1);
78
    e1Coords = undistortPoints(e1Coords, camParams1);
79
 
79
 
80
    % match ellipse candidates between cameras based on projection
80
    % match ellipse candidates between cameras based on projection
81
    E0 = projectOntoPointCloud(e0Coords, P0, Q);
81
    E0 = projectOntoPointCloud(e0Coords, P0, Q);
82
    E1 = projectOntoPointCloud(e1Coords, P1, Q);
82
    E1 = projectOntoPointCloud(e1Coords, P1, Q);
83
 
83
 
84
    matchedPairs = nan(size(E0, 1), 2);
84
    matchedPairs = nan(size(E0, 1), 2);
85
    nMatchedPairs = 0;
85
    nMatchedPairs = 0;
86
    for j=1:size(E0, 1)
86
    for j=1:size(E0, 1)
87
        
87
        
88
        % should use pdist2 instead..
88
        % should use pdist2 instead..
89
        sqDists = sum((E1 - repmat(E0(j,:), size(E1, 1), 1)).^2, 2);
89
        sqDists = sum((E1 - repmat(E0(j,:), size(E1, 1), 1)).^2, 2);
90
        
90
        
91
        [minSqDist, minSqDistIdx] = min(sqDists);
91
        [minSqDist, minSqDistIdx] = min(sqDists);
92
 
92
 
93
        if(minSqDist < 1^2)
93
        if(minSqDist < 1^2)
94
            nMatchedPairs = nMatchedPairs + 1;
94
            nMatchedPairs = nMatchedPairs + 1;
95
            matchedPairs(nMatchedPairs, :) = [j, minSqDistIdx];
95
            matchedPairs(nMatchedPairs, :) = [j, minSqDistIdx];
96
        end
96
        end
97
    end
97
    end
98
    matchedPairs = matchedPairs(1:nMatchedPairs, :);
98
    matchedPairs = matchedPairs(1:nMatchedPairs, :);
99
    
99
    
100
    figure; 
100
    figure; 
101
    subplot(1,2,1);
101
    subplot(1,2,1);
102
    imshow(frame0);
102
    imshow(frame0);
103
    hold('on');
103
    hold('on');
104
    plot(e0Coords(matchedPairs(:, 1),1), e0Coords(matchedPairs(:, 1),2), 'rx', 'MarkerSize', 15);
104
    plot(e0Coords(matchedPairs(:, 1),1), e0Coords(matchedPairs(:, 1),2), 'rx', 'MarkerSize', 15);
105
    subplot(1,2,2);
105
    subplot(1,2,2);
106
    imshow(frame1);
106
    imshow(frame1);
107
    hold('on');
107
    hold('on');
108
    plot(e1Coords(matchedPairs(:, 2),1), e1Coords(matchedPairs(:, 2),2), 'rx', 'MarkerSize', 15);
108
    plot(e1Coords(matchedPairs(:, 2),1), e1Coords(matchedPairs(:, 2),2), 'rx', 'MarkerSize', 15);
109
    drawnow;
109
    drawnow;
110
    
110
    
111
    % triangulate marker centers (lens correction has been performed)
111
%     % triangulate marker centers (lens correction has been performed)
112
    [E{i}, e] = triangulate(e0Coords(matchedPairs(:, 1),:), e1Coords(matchedPairs(:, 2),:), camStereoParams);
112
%     [E{i}, e] = triangulate(e0Coords(matchedPairs(:, 1),:), e1Coords(matchedPairs(:, 2),:), camStereoParams);
113
    E{i} = E{i}(e<3.0, :);
113
%     E{i} = E{i}(e<3.0, :);
-
 
114
%     display(e);
-
 
115
    
-
 
116
    [E{i}, e] = detectMarkersStereoSubpix(frame0, frame1, E0(matchedPairs(:, 1), :), camStereoParams, pc);
114
    display(e);
117
    display(e);
115
    
118
    
116
    % write point cloud with marker (debugging)
119
    % write point cloud with marker (debugging)
117
    pcDebug = pointCloud([pc.Location; E{i}], 'Color', [pc.Color; repmat([255, 0, 0], size(E{i}, 1), 1)]);
120
    pcDebug = pointCloud([pc.Location; E{i}], 'Color', [pc.Color; repmat([255, 0, 0], size(E{i}, 1), 1)]);
118
    pcwrite(pcDebug, 'pcDebug.ply');
121
    pcwrite(pcDebug, 'pcDebug.ply');
119
    
122
    
120
    % bring markers into initial alignment
123
    % bring markers into initial alignment
121
    [U,~,V] = svd(initialAlign(i).Rotation);
124
    [U,~,V] = svd(initialAlign(i).Rotation);
122
    Ri = U*V';
125
    Ri = U*V';
123
    Ti = initialAlign(i).Translation;
126
    Ti = initialAlign(i).Translation;
124
    
127
    
125
    Eg{i} = E{i}*Ri' + repmat(Ti', size(E{i}, 1), 1);
128
    Eg{i} = E{i}*Ri' + repmat(Ti', size(E{i}, 1), 1);
126
end
129
end
127
 
130
 
128
% show found markers in initial alignment
131
% show found markers in initial alignment
129
figure;
132
figure;
130
hold('on');
133
hold('on');
131
for i=1:nSubScans
134
for i=1:nSubScans
132
    % fix Ri to be orthogonal
135
    % fix Ri to be orthogonal
133
    [U,~,V] = svd(initialAlign(i).Rotation);
136
    [U,~,V] = svd(initialAlign(i).Rotation);
134
    Ri = U*V';
137
    Ri = U*V';
135
    
138
    
136
    % bring point cloud into initial alignment
139
    % bring point cloud into initial alignment
137
    pcFileName = fullfile(alnFilePath, initialAlign(i).FileName);
140
    pcFileName = fullfile(alnFilePath, initialAlign(i).FileName);
138
    pc = pcread(pcFileName);
141
    pc = pcread(pcFileName);
139
    tform = affine3d([Ri' [0;0;0]; initialAlign(i).Translation' 1]);
142
    tform = affine3d([Ri' [0;0;0]; initialAlign(i).Translation' 1]);
140
    pcg = pctransform(pc, tform);
143
    pcg = pctransform(pc, tform);
141
   
144
   
142
    pcshow(pcg);
145
    pcshow(pcg);
143
    xlabel('x');
146
    xlabel('x');
144
    ylabel('y');
147
    ylabel('y');
145
    zlabel('z');
148
    zlabel('z');
146
    
149
    
147
    plot3(Eg{i}(:,1), Eg{i}(:,2), Eg{i}(:,3), '.', 'MarkerSize', 15);
150
    plot3(Eg{i}(:,1), Eg{i}(:,2), Eg{i}(:,3), '.', 'MarkerSize', 15);
148
    title('Initial Alignment');
151
    title('Initial Alignment');
149
end
152
end
150
 
153
 
151
% match markers between poses using initial alignment
154
% match markers between poses using initial alignment
152
Pg = {};
155
Pg = {};
153
P = {};
156
P = {};
154
for i=1:nSubScans
157
for i=1:nSubScans
155
    for j=1:size(Eg{i}, 1)
158
    for j=1:size(Eg{i}, 1)
156
        pg = Eg{i}(j,:);
159
        pg = Eg{i}(j,:);
157
        p = E{i}(j,:);
160
        p = E{i}(j,:);
158
        matched = false;
161
        matched = false;
159
        for k=1:size(Pg, 2)
162
        for k=1:size(Pg, 2)
160
            clusterCenter = mean(cat(1, Pg{:,k}), 1);
163
            clusterCenter = mean(cat(1, Pg{:,k}), 1);
161
            if(sum((pg - clusterCenter).^2) < 3^2)
164
            if(sum((pg - clusterCenter).^2) < 3^2)
162
                % store in global frame
165
                % store in global frame
163
                Pg{i,k} = pg;
166
                Pg{i,k} = pg;
164
                % store in local frame
167
                % store in local frame
165
                P{i,k} = p;
168
                P{i,k} = p;
166
                matched = true;
169
                matched = true;
167
                break;
170
                break;
168
            end
171
            end
169
        end
172
        end
170
        % create new cluster
173
        % create new cluster
171
        if(not(matched))
174
        if(not(matched))
172
            Pg{i,end+1} = pg;
175
            Pg{i,end+1} = pg;
173
            P{i,end+1} = p;
176
            P{i,end+1} = p;
174
        end 
177
        end 
175
    end
178
    end
176
end
179
end
177
 
180
 
178
% run optimization
181
% run optimization
179
alignment = groupwiseOrthogonalProcrustes(P, initialAlign);
182
alignment = groupwiseOrthogonalProcrustes(P, initialAlign);
180
 
183
 
181
% show found markers in optimized alignment
184
% show found markers in optimized alignment
182
figure;
185
figure;
183
hold('on');
186
hold('on');
184
for i=1:nSubScans
187
for i=1:nSubScans
185
    % fix Ri to be orthogonal
188
    % fix Ri to be orthogonal
186
    [U,~,V] = svd(alignment(i).Rotation);
189
    [U,~,V] = svd(alignment(i).Rotation);
187
    Ri = U*V';
190
    Ri = U*V';
188
    Ti = alignment(i).Translation;
191
    Ti = alignment(i).Translation;
189
    
192
    
190
    Ea = E{i}*Ri' + repmat(Ti', size(E{i}, 1), 1);
193
    Ea = E{i}*Ri' + repmat(Ti', size(E{i}, 1), 1);
191
    
194
    
192
    % bring point cloud into optimized alignment
195
    % bring point cloud into optimized alignment
193
    pc = pcread(initialAlign(i).FileName);
196
    pc = pcread(initialAlign(i).FileName);
194
    tform = affine3d([Ri' [0;0;0]; initialAlign(i).Translation' 1]);
197
    tform = affine3d([Ri' [0;0;0]; initialAlign(i).Translation' 1]);
195
    pcg = pctransform(pc, tform);
198
    pcg = pctransform(pc, tform);
196
   
199
   
197
    pcshow(pcg);
200
    pcshow(pcg);
198
    xlabel('x');
201
    xlabel('x');
199
    ylabel('y');
202
    ylabel('y');
200
    zlabel('z');
203
    zlabel('z');
201
    
204
    
202
    plot3(Ea(:,1), Ea(:,2), Ea(:,3), '.', 'MarkerSize', 15);
205
    plot3(Ea(:,1), Ea(:,2), Ea(:,3), '.', 'MarkerSize', 15);
203
    title('Optimized Alignment');
206
    title('Optimized Alignment');
204
end
207
end
205
 
208
 
206
% write to ALN file
209
% write to ALN file
207
for i=1:length(alignment)
210
for i=1:length(alignment)
208
    alignment(i).FileName = initialAlign(i).FileName;
211
    alignment(i).FileName = initialAlign(i).FileName;
209
end
212
end
210
 
213
 
211
writeMeshLabALN(alignment, strrep(alnFileName, '.aln', 'Optimized.aln'));
214
writeMeshLabALN(alignment, strrep(alnFileName, '.aln', 'Optimized.aln'));
212
 
215
 
213
end
216
end
214
 
217
 
215
function e = autoDetectMarkers(frame, P, pointCloud)
218
function e = autoDetectMarkers(frame, P, pointCloud)
216
 
219
 
217
    % create mask based on morphology
220
    % create mask based on morphology
218
    g = rgb2gray(frame);
221
    g = rgb2gray(frame);
219
    % g(g>254) = 0;
222
    % g(g>254) = 0;
220
    % bw = imbinarize(g, 'adaptive', 'Sensitivity', 10^(-50));
223
    % bw = imbinarize(g, 'adaptive', 'Sensitivity', 10^(-50));
221
    bw = imbinarize(g, 0.10);
224
    bw = imbinarize(g, 0.10);
222
    cc = bwconncomp(bw);
225
    cc = bwconncomp(bw);
223
    rp = regionprops(cc, 'Area', 'Solidity', 'Eccentricity', 'Centroid');
226
    rp = regionprops(cc, 'Area', 'Solidity', 'Eccentricity', 'Centroid');
224
    idx = ([rp.Area] > 100 & [rp.Area] < 1000 & [rp.Solidity] > 0.9);
227
    idx = ([rp.Area] > 100 & [rp.Area] < 1000 & [rp.Solidity] > 0.9);
225
    
228
    
226
    e = cat(1, rp(idx).Centroid);
229
    e = cat(1, rp(idx).Centroid);
227
 
230
 
228
end
231
end
229
 
232
 
230
function e = manuallyDetectMarkers(frame, P, pointCloud)
233
function e = manuallyDetectMarkers(frame, P, pointCloud)
231
    
234
    
232
    e = [];
235
    e = [];
233
	%edges = edge(rgb2gray(frame), 'Canny', [0.08 0.1], 2);
236
	%edges = edge(rgb2gray(frame), 'Canny', [0.08 0.1], 2);
234
 
237
 
235
    figure; 
238
    figure; 
236
    hold('on');
239
    hold('on');
237
    imshow(frame);
240
    imshow(frame);
238
    title('Close figure to end.');
241
    title('Close figure to end.');
239
    set(gcf, 'pointer', 'crosshair'); 
242
    set(gcf, 'pointer', 'crosshair'); 
240
    set(gcf, 'WindowButtonDownFcn', @clickCallback);
243
    set(gcf, 'WindowButtonDownFcn', @clickCallback);
241
    
244
    
242
    uiwait;
245
    uiwait;
243
 
246
 
244
    function clickCallback(caller, ~)
247
    function clickCallback(caller, ~)
245
        
248
        
246
        p = get(gca, 'CurrentPoint'); 
249
        p = get(gca, 'CurrentPoint'); 
247
        p = p(1, 1:2);
250
        p = p(1, 1:2);
248
 
251
 
249
        e = [e; p(:, 1:2)];
252
        e = [e; p(:, 1:2)];
250
        
253
        
251
        if(not(isempty(el)))
254
        if(not(isempty(el)))
252
            figure(caller);
255
            figure(caller);
253
            hold('on');
256
            hold('on');
254
            plot(el(1), el(2), 'rx', 'MarkerSize', 15);
257
            plot(el(1), el(2), 'rx', 'MarkerSize', 15);
255
        end
258
        end
256
    end
259
    end
257
    
260
    
258
end
261
end
259
 
262
 
260
function [e, conf] = detectMarkersSubpix(frame, initGuesses, P, Q)
263
function [e, conf] = detectMarkersSubpix(frame, initGuesses, P, Q)
261
% Detect a marker in a single frame by rectifying to the image and
264
% Detect a marker in a single frame by rectifying to the image and
262
% performing image registration.
265
% performing image registration.
263
 
266
 
264
    % create mask based on morphology
267
    % create mask based on morphology
265
    g = rgb2gray(frame);
268
    g = rgb2gray(frame);
266
    g(g>254) = 0;
269
    g(g>254) = 0;
267
    bw = imbinarize(g);
270
    bw = imbinarize(g);
268
    cc = bwconncomp(bw);
271
    cc = bwconncomp(bw);
269
    labels = labelmatrix(cc);
272
    labels = labelmatrix(cc);
270
 
273
 
271
    % project point cloud into image
274
    % project point cloud into image
272
    q = [Q ones(size(Q,1),1)]*P;
275
    q = [Q ones(size(Q,1),1)]*P;
273
    q = q./[q(:,3) q(:,3) q(:,3)];
276
    q = q./[q(:,3) q(:,3) q(:,3)];
274
    
277
    
275
    e = zeros(size(initGuesses));
278
    e = zeros(size(initGuesses));
276
    conf = zeros(size(initGuesses, 1), 1);
279
    conf = zeros(size(initGuesses, 1), 1);
277
    
280
    
278
    nMarkersFound = 0;
281
    nMarkersFound = 0;
279
    
282
    
280
    for i=1:size(initGuesses, 1)
283
    for i=1:size(initGuesses, 1)
281
        
284
        
282
        labelId = labels(round(initGuesses(i,2)), round(initGuesses(i,1)));
285
        labelId = labels(round(initGuesses(i,2)), round(initGuesses(i,1)));
283
        labelMask = (labels == labelId);
286
        labelMask = (labels == labelId);
284
        labelMask = imdilate(labelMask, strel('disk', 3, 0));
287
        labelMask = imdilate(labelMask, strel('disk', 3, 0));
285
        
288
        
286
        if(sum(sum(labelMask)) < 10 || sum(sum(labelMask)) > 1000)
289
        if(sum(sum(labelMask)) < 10 || sum(sum(labelMask)) > 1000)
287
            continue;
290
            continue;
288
        end
291
        end
289
        
292
        
290
        % determine 3D points that are part of the marker
293
        % determine 3D points that are part of the marker
291
        % note: we should probably undistort labelMask
294
        % note: we should probably undistort labelMask
292
        pointMask = false(size(q, 1), 1);
295
        pointMask = false(size(q, 1), 1);
293
        for j=1:size(q,1)
296
        for j=1:size(q,1)
294
            if(round(q(j,2)) > size(labelMask, 1) || round(q(j,1)) > size(labelMask, 2) || round(q(j,2)) < 1 || round(q(j,1)) < 1)
297
            if(round(q(j,2)) > size(labelMask, 1) || round(q(j,1)) > size(labelMask, 2) || round(q(j,2)) < 1 || round(q(j,1)) < 1)
295
                continue;
298
                continue;
296
            end
299
            end
297
            
300
            
298
            if(labelMask(round(q(j,2)), round(q(j,1))))
301
            if(labelMask(round(q(j,2)), round(q(j,1))))
299
                pointMask(j) = true;
302
                pointMask(j) = true;
300
            end
303
            end
301
        end
304
        end
302
        
305
        
303
        if(sum(pointMask)) < 10
306
        if(sum(pointMask)) < 10
304
            continue;
307
            continue;
305
        end
308
        end
306
        
309
        
307
        % project 3D points onto local plane
310
        % project 3D points onto local plane
308
        [~, sc, ~] = pca(Q(pointMask, :));
311
        [~, sc, ~] = pca(Q(pointMask, :));
309
        Qlocal = sc(:, 1:2);
312
        Qlocal = sc(:, 1:2);
310
        
313
        
311
        % synthetic marker in high res. space
314
        % synthetic marker in high res. space
312
        m = zeros(151, 151);
315
        m = zeros(151, 151);
313
        [x, y] = meshgrid(1:151, 1:151);
316
        [x, y] = meshgrid(1:151, 1:151);
314
        m((x(:)-76).^2 + (y(:)-76).^2 <= 50^2) = 1.0;
317
        m((x(:)-76).^2 + (y(:)-76).^2 <= 50^2) = 1.0;
315
        
318
        
316
        % relation between marker space (px) and true marker/local plane(mm)
319
        % relation between marker space (px) and true marker/local plane(mm)
317
        % true marker diameter is 1.75mm
320
        % true marker diameter is 1.75mm
318
        mScale = 101/1.4; %px/mm
321
        mScale = 101/1.4; %px/mm
319
        mShift = 76; %px
322
        mShift = 76; %px
320
        
323
        
321
        % build homography from image to marker space
324
        % build homography from image to marker space
322
        H = fitgeotrans(q(pointMask, 1:2), mScale*Qlocal+mShift,  'projective');
325
        H = fitgeotrans(q(pointMask, 1:2), mScale*Qlocal+mShift,  'projective');
323
        %Hdlt = Hest_DLT([mScale*Qlocal+mShift, ones(size(Qlocal, 1), 1)]', q(pointMask,:)');
326
        %Hdlt = Hest_DLT([mScale*Qlocal+mShift, ones(size(Qlocal, 1), 1)]', q(pointMask,:)');
324
        %H = projective2d(Hdlt');
327
        %H = projective2d(Hdlt');
325
        
328
        
326
        % bring image of marker into marker space
329
        % bring image of marker into marker space
327
        imMarkerSpace = imwarp(frame, H, 'OutputView', imref2d(size(m)));
330
        imMarkerSpace = imwarp(frame, H, 'OutputView', imref2d(size(m)));
328
        imMarkerSpace = rgb2gray(im2double(imMarkerSpace));
331
        imMarkerSpace = rgb2gray(im2double(imMarkerSpace));
329
        
332
        
330
        %figure; imshowpair(imMarkerSpace, m);
333
        %figure; imshowpair(imMarkerSpace, m);
331
        
334
        
332
        % perform image registration
335
        % perform image registration
333
        % might be better off using subpixel image correlation
336
        % might be better off using subpixel image correlation
334
        [opt, met] = imregconfig('multimodal');
337
        [opt, met] = imregconfig('multimodal');
335
        T = imregtform(m, imMarkerSpace, 'translation', opt, met, 'DisplayOptimization', false);
338
        T = imregtform(m, imMarkerSpace, 'translation', opt, met, 'DisplayOptimization', false);
336
        
339
        
337
        rege = imwarp(m, T, 'OutputView', imref2d(size(m)));
340
        rege = imwarp(m, T, 'OutputView', imref2d(size(m)));
338
        %figure; imshowpair(imMarkerSpace, rege);
341
        %figure; imshowpair(imMarkerSpace, rege);
339
        
342
        
340
        % measure of correlation
343
        % measure of correlation
341
        confI = sum(sum(imMarkerSpace .* rege))/sqrt(sum(sum(imMarkerSpace) * sum(sum(rege))));
344
        confI = sum(sum(imMarkerSpace .* rege))/sqrt(sum(sum(imMarkerSpace) * sum(sum(rege))));
342
        %confI = 1.0;
345
        %confI = 1.0;
343
        
346
        
344
        if confI<0.4
347
        if confI<0.4
345
            continue;
348
            continue;
346
        end
349
        end
347
        
350
        
348
        fprintf('Found marker with confidence: %f\n', confI);
351
        fprintf('Found marker with confidence: %f\n', confI);
349
            
352
            
350
        % transform marker space coordinates (76,76) to frame space
353
        % transform marker space coordinates (76,76) to frame space
351
        el = T.transformPointsForward([76, 76]);
354
        el = T.transformPointsForward([76, 76]);
352
        el = H.transformPointsInverse(el);
355
        el = H.transformPointsInverse(el);
353
        
356
        
354
        nMarkersFound = nMarkersFound+1;
357
        nMarkersFound = nMarkersFound+1;
355
        e(nMarkersFound,:) = el;
358
        e(nMarkersFound,:) = el;
356
        conf(nMarkersFound) = confI;
359
        conf(nMarkersFound) = confI;
357
    end
360
    end
358
    
361
    
359
    e = e(1:nMarkersFound, :);
362
    e = e(1:nMarkersFound, :);
360
    conf = conf(1:nMarkersFound);
363
    conf = conf(1:nMarkersFound);
361
end
364
end
-
 
365
 
-
 
366
function [E, conf] = detectMarkersStereoSubpix(frame0, frame1, initGuesses, camStereoParams, pc)
-
 
367
% Detect a marker in stereo frame set by minimizing the difference to
-
 
368
% projected images of 3d marker
-
 
369
    
-
 
370
    normals = pcnormals(pc, 6);
-
 
371
 
-
 
372
    nMarkers = size(initGuesses, 2);
-
 
373
    
-
 
374
    for i=1:nMarkers
-
 
375
        
-
 
376
        pI = initGuesses(i,:);
-
 
377
    	
-
 
378
        e0 = camStereoParams.CameraParameters1.worldToImage(eye(3,3), zeros(3,1), pI);
-
 
379
        e1 = camStereoParams.CameraParameters2.worldToImage(camStereoParams.RotationOfCamera2, camStereoParams.TranslationOfCamera2, pI);
-
 
380
        
-
 
381
        % center of support region
-
 
382
        e0Center = round(e0);
-
 
383
        e1Center = round(e1);
-
 
384
        
-
 
385
        % find initial normal
-
 
386
        idx = pc.findNearestNeighbors(pI, 1);
-
 
387
        nI = normals(idx, :);
-
 
388
        
-
 
389
        margin = 10;
-
 
390
        
-
 
391
        [x,y] = meshgrid(e0Center(1)-margin:e0Center(1)+margin, e0Center(2)-margin:e0Center(2)+margin);
-
 
392
        e0ImCoords = [x(:), y(:)];
-
 
393
       
-
 
394
        [x,y] = meshgrid(e1Center(1)-margin:e1Center(1)+margin, e1Center(2)-margin:e1Center(2)+margin);
-
 
395
        e1ImCoords = [x(:), y(:)];
-
 
396
        
-
 
397
        e0UndistImCoords = undistortPoints(e0ImCoords, camStereoParams.CameraParameters1);
-
 
398
        e0NormImCoords = camStereoParams.CameraParameters1.pointsToWorld(eye(3,3), zeros(3,1), e0UndistImCoords);
-
 
399
        e1UndistImCoords = undistortPoints(e1ImCoords, camStereoParams.CameraParameters2);
-
 
400
        e1NormImCoords = camStereoParams.CameraParameters2.pointsToWorld(camStereoParams.RotationOfCamera2, camStereoParams.TranslationOfCamera2, e1UndistImCoords);
-
 
401
 
-
 
402
        x0 = [pI; nI(1:2)];
-
 
403
        
-
 
404
        
-
 
405
        
-
 
406
        
-
 
407
    end
-
 
408
    
-
 
409
    function r = circleResiduals(x)
-
 
410
        
-
 
411
        point = x(1:3);
-
 
412
        normal = [x(4:5); sqrt(1-x(4)^2-x(5)^2)];
-
 
413
        
-
 
414
        r = zeros(length(length(e0NormImCoords)) + length(e1NormImCoords), 1);
-
 
415
        
-
 
416
        for i=1:length(e0NormImCoords)
-
 
417
            
-
 
418
            % dermine z coordinate on the hypothesized plane
-
 
419
            z = 
-
 
420
            
-
 
421
        end
-
 
422
        
-
 
423
        
-
 
424
    end
-
 
425
    
-
 
426
end
362
 
427
 
363
function E = projectOntoPointCloud(e, P, pointCloud)
428
function E = projectOntoPointCloud(e, P, pointCloud)
364
% Project 2d point coordinates onto pointCloud to find corresponding 3d
429
% Project 2d point coordinates onto pointCloud to find corresponding 3d
365
% point coordinates.
430
% point coordinates.
366
 
431
 
367
    q = [pointCloud ones(size(pointCloud,1),1)]*P;
432
    q = [pointCloud ones(size(pointCloud,1),1)]*P;
368
    q = q(:,1:2)./[q(:,3) q(:,3)];
433
    q = q(:,1:2)./[q(:,3) q(:,3)];
369
 
434
 
370
    E = nan(size(e,1), 3);
435
    E = nan(size(e,1), 3);
371
    
436
    
372
    for i=1:size(e, 1)
437
    for i=1:size(e, 1)
373
        sqDists = sum((q - repmat(e(i,:), size(q, 1), 1)).^2, 2);
438
        sqDists = sum((q - repmat(e(i,:), size(q, 1), 1)).^2, 2);
374
        
439
        
375
        [sqDistsSorted, sortIdx] = sort(sqDists);
440
        [sqDistsSorted, sortIdx] = sort(sqDists);
376
        
441
        
377
        neighbors = (sqDistsSorted < 4.0^2);
442
        neighbors = (sqDistsSorted < 4.0^2);
378
        
443
        
379
        distsSorted = sqrt(sqDistsSorted(neighbors));
444
        distsSorted = sqrt(sqDistsSorted(neighbors));
380
        invDistsSorted = 1.0/distsSorted;
445
        invDistsSorted = 1.0/distsSorted;
381
        sortIdx = sortIdx(neighbors);
446
        sortIdx = sortIdx(neighbors);
382
        
447
        
383
        nNeighbors = sum(neighbors);
448
        nNeighbors = sum(neighbors);
384
        
449
        
385
        if(nNeighbors >= 2)
450
        if(nNeighbors >= 2)
386
            E(i, :) = 0;
451
            E(i, :) = 0;
387
            for j=1:nNeighbors
452
            for j=1:nNeighbors
388
                E(i, :) = E(i, :) + invDistsSorted(j)/sum(invDistsSorted) * pointCloud(sortIdx(j), :);
453
                E(i, :) = E(i, :) + invDistsSorted(j)/sum(invDistsSorted) * pointCloud(sortIdx(j), :);
389
            end
454
            end
390
        end
455
        end
391
            
456
            
392
    end    
457
    end    
393
end
458
end
394
 
459
 
395
function H = Hest_DLT(q1, q2)
460
function H = Hest_DLT(q1, q2)
396
    % Estimate the homography between a set of point correspondences using the 
461
    % Estimate the homography between a set of point correspondences using the 
397
    % direct linear transform algorithm.
462
    % direct linear transform algorithm.
398
    %
463
    %
399
    % Input:
464
    % Input:
400
    %           q1: 3xN matrix of homogenous point coordinates from camera 1. 
465
    %           q1: 3xN matrix of homogenous point coordinates from camera 1. 
401
    %           q2: 3xN matrix of corresponding points from camera 2.
466
    %           q2: 3xN matrix of corresponding points from camera 2.
402
    % Output:
467
    % Output:
403
    %           H: 3x3 matrix. The Fundamental Matrix estimate. 
468
    %           H: 3x3 matrix. The Fundamental Matrix estimate. 
404
    %
469
    %
405
    % Note that N must be at least 4.
470
    % Note that N must be at least 4.
406
    % See derivation in Aanaes, Lecture Notes on Computer Vision, 2011
471
    % See derivation in Aanaes, Lecture Notes on Computer Vision, 2011
407
 
472
 
408
    % Normalize points
473
    % Normalize points
409
    [T1,invT1] = normalizationMat(q1);
474
    [T1,invT1] = normalizationMat(q1);
410
    q1_tilde = T1*q1;
475
    q1_tilde = T1*q1;
411
 
476
 
412
    T2 = normalizationMat(q2);
477
    T2 = normalizationMat(q2);
413
    q2_tilde = T2*q2;
478
    q2_tilde = T2*q2;
414
 
479
 
415
    % DLT estimation
480
    % DLT estimation
416
    N = size(q1_tilde,2);
481
    N = size(q1_tilde,2);
417
    assert(size(q2_tilde,2)==N);
482
    assert(size(q2_tilde,2)==N);
418
 
483
 
419
    B = zeros(3*N,9);
484
    B = zeros(3*N,9);
420
 
485
 
421
    for i=1:N
486
    for i=1:N
422
        q1i = q1_tilde(:,i);
487
        q1i = q1_tilde(:,i);
423
        q2i = q2_tilde(:,i);
488
        q2i = q2_tilde(:,i);
424
        q1_x = [0 -q1i(3) q1i(2); q1i(3) 0 -q1i(1); -q1i(2) q1i(1) 0];
489
        q1_x = [0 -q1i(3) q1i(2); q1i(3) 0 -q1i(1); -q1i(2) q1i(1) 0];
425
        biT = kron(q2i', q1_x); 
490
        biT = kron(q2i', q1_x); 
426
        B(3*(i-1)+1:3*i, :) = biT;
491
        B(3*(i-1)+1:3*i, :) = biT;
427
    end
492
    end
428
 
493
 
429
    [U,S,~] = svd(B');
494
    [U,S,~] = svd(B');
430
 
495
 
431
    [~,idx] = min(diag(S));
496
    [~,idx] = min(diag(S));
432
    h = U(:,idx);
497
    h = U(:,idx);
433
 
498
 
434
    H_tilde = reshape(h, 3, 3);
499
    H_tilde = reshape(h, 3, 3);
435
 
500
 
436
    % Unnormalize H
501
    % Unnormalize H
437
    H = invT1*H_tilde*T2;
502
    H = invT1*H_tilde*T2;
438
 
503
 
439
    % Arbitrarily chose scale
504
    % Arbitrarily chose scale
440
    H = H * 1/H(3,3);
505
    H = H * 1/H(3,3);
441
end
506
end
442
 
507
 
443
function [T,invT] = normalizationMat(q)
508
function [T,invT] = normalizationMat(q)
444
    % Gives a normalization matrix for homogeneous coordinates
509
    % Gives a normalization matrix for homogeneous coordinates
445
    % such that T*q will have zero mean and unit variance.
510
    % such that T*q will have zero mean and unit variance.
446
    % See Aanaes, Computer Vision Lecture Notes 2.8.2
511
    % See Aanaes, Computer Vision Lecture Notes 2.8.2
447
    %
512
    %
448
    % q: (M+1)xN matrix of N MD points in homogenous coordinates
513
    % q: (M+1)xN matrix of N MD points in homogenous coordinates
449
    %
514
    %
450
    % Extended to also efficiently compute the inverse matrix
515
    % Extended to also efficiently compute the inverse matrix
451
    % DTU, 2013, Jakob Wilm
516
    % DTU, 2013, Jakob Wilm
452
 
517
 
453
    [M,N] = size(q);
518
    [M,N] = size(q);
454
    M = M-1;
519
    M = M-1;
455
 
520
 
456
    mu = mean(q(1:M,:),2);
521
    mu = mean(q(1:M,:),2);
457
 
522
 
458
    q_bar = q(1:M,:)-repmat(mu,1,N);
523
    q_bar = q(1:M,:)-repmat(mu,1,N);
459
 
524
 
460
    s = mean(sqrt(diag(q_bar'*q_bar)))/sqrt(2);
525
    s = mean(sqrt(diag(q_bar'*q_bar)))/sqrt(2);
461
 
526
 
462
    T = [eye(M)/s, -mu/s; zeros(1,M) 1];
527
    T = [eye(M)/s, -mu/s; zeros(1,M) 1];
463
 
528
 
464
    invT = [eye(M)*s, mu; zeros(1,M) 1];
529
    invT = [eye(M)*s, mu; zeros(1,M) 1];
465
end
530
end
466
 
531
 
467

Generated by GNU Enscript 1.6.6.
532

Generated by GNU Enscript 1.6.6.
468
 
533
 
469
 
534
 
470
 
535