g_stabilize.m 6.22 KB
Newer Older
1
2
3
function g_stabilize(img_ref_fname,varargin)
% This function and its sub-functions stabilize all images found in the 
% working folder against a reference image. The stabilized files
Pascal Bourgault's avatar
Pascal Bourgault committed
4
5
% contain the datetime values stored in the 'DateTime' or the 'Comment'
% field of the unstabilized images.
Daniel Bourgault's avatar
Daniel Bourgault committed
6
7
% 
% Input: 
8
9
10
11
%   img_ref_fname: The complete image name, with extension (and path if 
%                  necessary), of the reference image in the current 
%                  directory.
%
Pascal Bourgault's avatar
Pascal Bourgault committed
12
13
14
15
16
17
18
%   Parameters, Name,       Value
%               roiFile,    [Defaults: roi.mat] Name of the file with roi
%                           information.
%               auto,       [Defaults: 0 (false)] If true, overrides any
%                           interaction with the user (for use in scripts)
%               suffix,     [Defaults: '_stable'] Suffix to add to the
%                           stabilized images.
Daniel Bourgault's avatar
Daniel Bourgault committed
19
20
%
% Output:
21
22
%   All stabilized images are rewritten as image files in the subfolder 
%   /stable.
Daniel Bourgault's avatar
Daniel Bourgault committed
23
%
24
% Example:
25
%   g_stabilize('IMG_4018.jpg');
26
%
Daniel Bourgault's avatar
Daniel Bourgault committed
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
%% Some parameters
% Pyramid level for the stabilization.
% See documentation in the g_stabilize folder.
% L = 4 worked well on initial application but may require adjustments for
% particular application.
L = 4;

% Number of iterative improvement. Probably ok just 1 iteration.
niter = 1;

% Parameters for equalization. See help clahs for details.
% This may not be needed fpr most application but may help other cases.
% Need to play with it if problems. 
equalize = false;
nry = 4;
nrx = 4;

% Extract the path and extension of the reference image
[pathstr,name,ext] = fileparts(img_ref_fname);

% Check for optional options
Daniel Bourgault's avatar
Daniel Bourgault committed
49
fname_suffix = '_stable';
Pascal Bourgault's avatar
Pascal Bourgault committed
50
51
52
53
54
55
56
57
58
59
60
61
62
auto = 0;
roifile = 'roi.mat';
if length(varargin) > 1
    for i=1:2:length(varargin)
        if strcmpi(varargin{i},'roiFile')
            roifile = varargin{i+1};
        elseif strcmpi(varargin{i},'auto')
            auto = varargin{i+1};
        elseif strcmpi(varargin{i},'suffix')
            fname_suffix = varargin{i+1};
        end
    end
end
Daniel Bourgault's avatar
Daniel Bourgault committed
63

Pascal Bourgault's avatar
Pascal Bourgault committed
64
hw = waitbar(0,'Preparing images');
Daniel Bourgault's avatar
Daniel Bourgault committed
65

66
67
68
69
70
71
72
%% Load the Region of interest (roi) file
display(' Loading the roi.mat file containing the region of interest (roi)');
if length(pathstr) == 0  % Images are in the current folder
    load(roifile);
else
    load([pathstr,'/',roifile]);
end
Daniel Bourgault's avatar
Daniel Bourgault committed
73
74

% Read the reference image
75
im2 = imread(img_ref_fname);
Pascal Bourgault's avatar
Pascal Bourgault committed
76

77
% Convert into gray scale if not already a B/W image
Pascal Bourgault's avatar
Pascal Bourgault committed
78
if size(im2,3) ~= 1
79
    im2 = g_rgb2gray(im2);
Pascal Bourgault's avatar
Pascal Bourgault committed
80
end
Daniel Bourgault's avatar
Daniel Bourgault committed
81

82
83
84
85
86
% May equalize with this equalizer. Careful this doesn't always work well
% and may compromise the stabilization. Use with care. 
if equalize
    im2 = clahs(im2,nry,nrx);
end
Daniel Bourgault's avatar
Daniel Bourgault committed
87
88
89
90

im2 = double(im2);

% Remove mean and divide by the standard deviation.
91
92
% This generally help the algorithm to compare images
inorm    = find(roi > 0);
Daniel Bourgault's avatar
Daniel Bourgault committed
93
94
95
im2_norm = (im2 - nanmean(im2(inorm)))./nanstd(im2(inorm));

% Take the norm of the gradient of the image. This helps the
96
97
% stabilization algorithm, nut again you may want to explore
% without it
Pascal Bourgault's avatar
Pascal Bourgault committed
98
[im2x, im2y] = gradient(im2_norm);
99
grad_im2     = sqrt(im2x.^2 + im2y.^2);
Daniel Bourgault's avatar
Daniel Bourgault committed
100

101
% The second frame is the reference frame for the stabilization algorithm.
Daniel Bourgault's avatar
Daniel Bourgault committed
102
103
frames(2).im = grad_im2;

104
%% Some figures to make sure everything seems ok
Daniel Bourgault's avatar
Daniel Bourgault committed
105
106
107
figure(1);
imagesc(im2);
colormap(gray);
108
title('Reference image. Intensity normalized over ROI');
Daniel Bourgault's avatar
Daniel Bourgault committed
109
110

figure(2);
111
imagesc(log10(grad_im2+eps));
Daniel Bourgault's avatar
Daniel Bourgault committed
112
colormap(gray);
113
title('Gradient of the reference image on a log scale');
Daniel Bourgault's avatar
Daniel Bourgault committed
114
115
116
117
118

figure(3);
imagesc(roi);
title('roi');

Pascal Bourgault's avatar
Pascal Bourgault committed
119
120
121
122
123
if ~auto
    answer = input('Happy with roi (y/n)? ','s');
    if answer == 'n'
        return
    end
Daniel Bourgault's avatar
Daniel Bourgault committed
124
end
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

%% Create the folder where to write the stable images
if length(pathstr) == 0  % Images are in the current folder
    [status,message,messageid] = mkdir('stable');
else
    [status,message,messageid] = mkdir([pathstr,'/stable']);
end

% Check for images already stablilized that would be found in the 
% stable folder. This is not yet fully implemeted. The goal would
% be not to perform the stabilization to images already stabilized
%if strcmp(message,'Directory already exists.')
%    if length(pathstr) == 0  
%        img_done = dir(['stable/*',ext]);
%    else
%        img_done = dir([pathstr,'/stable/','*',ext]);
%    end
%end

%% Read all filemanes in the current directory with the same extension as the ref img
if length(pathstr) == 0  % Images are in the current folder
    all_img = dir(['*',ext]);
else
    all_img = dir([pathstr,'/','*',ext]);
end

% Number of images to proceed
N = length(all_img);

Pascal Bourgault's avatar
Pascal Bourgault committed
154
time_per_img = 0;
155
156
157
158
159
160
161
162
163
164
165
166

for i = 1:N
    
    
    time_rem = (N-i+1)*time_per_img;
    if i > 1
        waitbar((i-1)/N,hw,sprintf('Stabilizing image #%d. %.0fh%02.2fmn remaining',...
            i,fix(time_rem/3600),rem(time_rem,3600)/60));
    else
        waitbar((i-1)/N,hw,sprintf('Stabilizing image #%d.',...
            i,fix(time_rem/3600),rem(time_rem,3600)/60));
    end
Pascal Bourgault's avatar
Pascal Bourgault committed
167
    total = tic;
168
169
170
171
172
173
174
    
    if length(pathstr) == 0
        im1     = imread(all_img(i).name);
        im_info = imfinfo(all_img(i).name);
    else
        im1     = imread([pathstr,'/',all_img(i).name]);
        im_info = imfinfo([pathstr,'/',all_img(i).name]);
Pascal Bourgault's avatar
Pascal Bourgault committed
175
    end
176
177
    
    % Convert into gray scale if not already a B/W image
Pascal Bourgault's avatar
Pascal Bourgault committed
178
    if size(im1,3) ~= 1
179
180
181
182
183
184
        im1 = g_rgb2gray(im1);
    end
    
    % May equalize with this equalizer.
    if equalize
        im1 = clahs(im1,nry,nrx);
Pascal Bourgault's avatar
Pascal Bourgault committed
185
    end
Daniel Bourgault's avatar
Daniel Bourgault committed
186
187
    
    im1 = double(im1);
Pascal Bourgault's avatar
Pascal Bourgault committed
188
    
189
    im1_norm     = (im1 - nanmean(im1(inorm)))./nanstd(im1(inorm));
Pascal Bourgault's avatar
Pascal Bourgault committed
190
    [im1x, im1y] = gradient(im1_norm);
191
    grad_im1     = sqrt(im1x.^2 + im1y.^2);
Daniel Bourgault's avatar
Daniel Bourgault committed
192
193
    
    frames(1).im = grad_im1;
194
    
Daniel Bourgault's avatar
Daniel Bourgault committed
195
196
    for iter = 1:niter
        [motion,stable] = g_videostabilize(frames,roi,L);
197
        frames(1).im    = stable(1).im;
Daniel Bourgault's avatar
Daniel Bourgault committed
198
    end
Pascal Bourgault's avatar
Pascal Bourgault committed
199
    
Daniel Bourgault's avatar
Daniel Bourgault committed
200
201
    im_stable = g_warp(im1,motion.A,motion.T);
    im_stable = uint8(im_stable);
202
    
Pascal Bourgault's avatar
Pascal Bourgault committed
203
204
205
206
207
208
209
    if isfield(im_info,'DateTime')
        datetime = im_info.DateTime;
    elseif isfield(im_info,'Comment')
        datetime = im_info.Comment;
    else
        datetime = '';
    end
210
211
212
213
214
215
216
217
218
219
    
    if length(pathstr) == 0
        stable_img_fname = ['stable/',all_img(i).name(1:end-4)]
    else
        stable_img_fname = [pathstr,'/stable/',all_img(i).name(1:end-4)]
    end
    
    imwrite(im_stable,[stable_img_fname fname_suffix ext],...
        'Quality',100,'Comment',datetime);
    
Pascal Bourgault's avatar
Pascal Bourgault committed
220
    time_per_img = toc(total);
Daniel Bourgault's avatar
Daniel Bourgault committed
221
end
222

Pascal Bourgault's avatar
Pascal Bourgault committed
223
close(hw)