Subversion Repositories seema-scanner

Rev

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

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

Generated by GNU Enscript 1.6.6.
-
 
436
 
-
 
437
 
-
 
438