Blame view

src/g_stabilize/g_stabilize.m 9.3 KB
5934cd22   Daniel Bourgault   g_stabilize rewri...
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
972d1377   Pascal Bourgault   Voir commit prece...
4
5
% contain the datetime values stored in the 'DateTime' or the 'Comment'
% field of the unstabilized images.
7d7ce63d   Daniel Bourgault   First commit
6
7
% 
% Input: 
5934cd22   Daniel Bourgault   g_stabilize rewri...
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.
%
0f098f65   Dany Dumont   g_stabilize a ete...
12
13
14
15
16
17
18
19
20
%   Optional parameters:
%       L_level_Gaussian:   Size of the L-level Gaussian pyramid [Default: 4]
%       roi_file:           Name of the file with roi information [Default: 'roi.mat']
%       fname_suffix:       Suffix to add to the stabilized images [Default: '_stable']
%       output_folder:      Name of the output folder [Default: 'stable']
%       equalize:           Use image equalization over the roi region [Default: 0 (false)]
%       use_img_grad:       Perform the stabilization using the gradient of the image [Default: 0 (false)]
%       auto:               If true, overrides any interaction with the user 
%                           (for use in scripts) [Default: 0 (false)] 
7d7ce63d   Daniel Bourgault   First commit
21
22
%
% Output:
5934cd22   Daniel Bourgault   g_stabilize rewri...
23
%   All stabilized images are rewritten as image files in the subfolder 
0f098f65   Dany Dumont   g_stabilize a ete...
24
%   /stable (by default or other name is specified).
7d7ce63d   Daniel Bourgault   First commit
25
%
0f098f65   Dany Dumont   g_stabilize a ete...
26
27
28
% Examples:
%   Example 1: Using all default parameters
%   >> g_stabilize('IMG_4018.jpg');
96b00eee   Clark Richards   typo fixes and he...
29
%
0f098f65   Dany Dumont   g_stabilize a ete...
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
%   Example 2: Using a different L level Gaussian than the default value (4)
%   >> g_stabilize('IMG_4018.jpg','L_level_Gaussian',6);
%
%   Example 3: Using a different L level Gaussian than the default value (4)
%              and a different suffix than the default (_stable) and
%              without any image equalization
%   >> g_stabilize('IMG_4018.jpg','L_level_Gaussian',6,'fname_suffix','_very_stable','equalize',false);
%

%%
p = inputParser;

% Default values
default_L_level_Gaussian = 4;
default_roi_file         = 'roi.mat';
default_fname_suffix     = '_stable';
default_output_folder    = 'stable';
default_equalize         = false;
default_use_img_grad     = false;
default_auto             = false;

addRequired(p,'img_ref_fname',@ischar);
addParameter(p,'L_level_Gaussian',default_L_level_Gaussian,@isnumeric);
addParameter(p,'roi_file',default_roi_file,@ischar);
addParameter(p,'fname_suffix',default_fname_suffix,@ischar);
addParameter(p,'output_folder',default_output_folder,@ischar);
addParameter(p,'equalize',default_equalize,@islogical);
addParameter(p,'use_img_grad',default_use_img_grad,@islogical);
addParameter(p,'auto',default_auto,@islogical);

parse(p,img_ref_fname,varargin{:})
7d7ce63d   Daniel Bourgault   First commit
61

0f098f65   Dany Dumont   g_stabilize a ete...
62
63
64
65
66
67
68
69
img_ref_fname = p.Results.img_ref_fname;
L             = p.Results.L_level_Gaussian;
roi_file      = p.Results.roi_file;
fname_suffix  = p.Results.fname_suffix;
output_folder = p.Results.output_folder;
equalize      = p.Results.equalize;
use_img_grad  = p.Results.use_img_grad;
auto          = p.Results.auto;
5934cd22   Daniel Bourgault   g_stabilize rewri...
70

0f098f65   Dany Dumont   g_stabilize a ete...
71
72
73
74
75
76
77
78
79
80
81
disp(['   ']);
disp(['   -----------------------------------------------------------------------']);
disp(['   IMAGE STABILIZATION PARAMETERS']);
disp(['     Filename of the reference image:              ',img_ref_fname]);
disp(['     L-level Gaussian:                             ',num2str(L)]);
disp(['     Name of the ROI filename:                     ',roi_file]);
disp(['     Suffix of stabilized filenames:               ',fname_suffix]);
disp(['     Output folder:                                ',output_folder]);
disp(['     Equalize (1) or not (0) the roi region:       ',num2str(equalize)]);
disp(['     Use (1) or not (0) the gradient of the image: ',num2str(use_img_grad)]);
disp(['   -----------------------------------------------------------------------']);
5934cd22   Daniel Bourgault   g_stabilize rewri...
82

0f098f65   Dany Dumont   g_stabilize a ete...
83
%% Equalization parameters
5934cd22   Daniel Bourgault   g_stabilize rewri...
84
% Parameters for equalization. See help clahs for details.
0f098f65   Dany Dumont   g_stabilize a ete...
85
86
% This may not be needed for most applications but may help in some cases 
% where the lighting conditions changes a lot.
5934cd22   Daniel Bourgault   g_stabilize rewri...
87
% Need to play with it if problems. 
0f098f65   Dany Dumont   g_stabilize a ete...
88
89
90
91
92
93
if equalize
    nry = 8;
    nrx = 8;
end

%%
5934cd22   Daniel Bourgault   g_stabilize rewri...
94
95
96
97

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

7d7ce63d   Daniel Bourgault   First commit
98

5934cd22   Daniel Bourgault   g_stabilize rewri...
99
%% Load the Region of interest (roi) file
0f098f65   Dany Dumont   g_stabilize a ete...
100
101
disp(['   ']);
display('   Loading the file containing the region of interest (roi)...');
5934cd22   Daniel Bourgault   g_stabilize rewri...
102
if length(pathstr) == 0  % Images are in the current folder
0f098f65   Dany Dumont   g_stabilize a ete...
103
    load(roi_file);
5934cd22   Daniel Bourgault   g_stabilize rewri...
104
else
0f098f65   Dany Dumont   g_stabilize a ete...
105
    load([pathstr,'/',roi_file]);
5934cd22   Daniel Bourgault   g_stabilize rewri...
106
end
7d7ce63d   Daniel Bourgault   First commit
107
108

% Read the reference image
5934cd22   Daniel Bourgault   g_stabilize rewri...
109
im2 = imread(img_ref_fname);
972d1377   Pascal Bourgault   Voir commit prece...
110

5934cd22   Daniel Bourgault   g_stabilize rewri...
111
% Convert into gray scale if not already a B/W image
972d1377   Pascal Bourgault   Voir commit prece...
112
if size(im2,3) ~= 1
0f098f65   Dany Dumont   g_stabilize a ete...
113
    im2_BW = g_rgb2gray(im2);
4f1faf35   Daniel Bourgault   Small changes mad...
114
115
else
    im2_BW = im2;
972d1377   Pascal Bourgault   Voir commit prece...
116
end
7d7ce63d   Daniel Bourgault   First commit
117

0f098f65   Dany Dumont   g_stabilize a ete...
118
119
120
im2_BW_cooked = im2_BW;
clear im2;

5934cd22   Daniel Bourgault   g_stabilize rewri...
121
122
123
% May equalize with this equalizer. Careful this doesn't always work well
% and may compromise the stabilization. Use with care. 
if equalize
0f098f65   Dany Dumont   g_stabilize a ete...
124
    im2_BW_cooked = clahs(im2_BW_cooked,nry,nrx);
5934cd22   Daniel Bourgault   g_stabilize rewri...
125
end
7d7ce63d   Daniel Bourgault   First commit
126

0f098f65   Dany Dumont   g_stabilize a ete...
127
128
im2_BW        = double(im2_BW);
im2_BW_cooked = double(im2_BW_cooked);
7d7ce63d   Daniel Bourgault   First commit
129
130

% Remove mean and divide by the standard deviation.
0f098f65   Dany Dumont   g_stabilize a ete...
131
132
133
134
% This generally help the algorithm to compare images that have different
% light conditions
%inorm    = find(roi > 0);
%im2_BW_cooked = (im2_BW_cooked - nanmean(im2_BW_cooked(inorm)))./nanstd(im2_BW_cooked(inorm));
7d7ce63d   Daniel Bourgault   First commit
135

0f098f65   Dany Dumont   g_stabilize a ete...
136
137
138
139
140
141
142
143
if use_img_grad
    % Take the norm of the gradient of the image. This may help the
    % stabilization algorithm but not always. Use this option with care. 
    [im2x, im2y]  = gradient(im2_BW_cooked);
    im2_BW_cooked = sqrt(im2x.^2 + im2y.^2);    
end

frames(2).im = im2_BW_cooked;
7d7ce63d   Daniel Bourgault   First commit
144

0f098f65   Dany Dumont   g_stabilize a ete...
145
%% Some figures to make sure everything is ok
7d7ce63d   Daniel Bourgault   First commit
146
figure(1);
0f098f65   Dany Dumont   g_stabilize a ete...
147
imagesc(im2_BW);
7d7ce63d   Daniel Bourgault   First commit
148
colormap(gray);
0f098f65   Dany Dumont   g_stabilize a ete...
149
title('Reference image in B/W');
7d7ce63d   Daniel Bourgault   First commit
150
151

figure(2);
0f098f65   Dany Dumont   g_stabilize a ete...
152
imagesc(im2_BW_cooked);
7d7ce63d   Daniel Bourgault   First commit
153
colormap(gray);
0f098f65   Dany Dumont   g_stabilize a ete...
154
title('Reference image manipulated (if so)');
7d7ce63d   Daniel Bourgault   First commit
155
156

figure(3);
0f098f65   Dany Dumont   g_stabilize a ete...
157
158
159
160
161
162
163
% Produce a mask over non-ROI region and plot it
iNaN = find(roi == 0);
roi_with_NaN = roi;
roi_with_NaN(iNaN) = NaN;
imagesc(im2_BW_cooked.*roi_with_NaN);
colormap(gray);
title('Reference image manipulated with mask over non-ROI');
7d7ce63d   Daniel Bourgault   First commit
164

0f098f65   Dany Dumont   g_stabilize a ete...
165
166
167
168
169
170
171
172
173
%if ~auto
%    disp([' '])
%    answer = input('   Happy with roi and parameters (y/n)? ','s');
%    if answer == 'n'
%        return
%    end
%end

display(['    ']);
5934cd22   Daniel Bourgault   g_stabilize rewri...
174
175
176

%% Create the folder where to write the stable images
if length(pathstr) == 0  % Images are in the current folder
0f098f65   Dany Dumont   g_stabilize a ete...
177
178
    [status,message,messageid] = mkdir(output_folder);
    save([output_folder,'/g_stabilize_info.mat'],'p','roi');
5934cd22   Daniel Bourgault   g_stabilize rewri...
179
else
0f098f65   Dany Dumont   g_stabilize a ete...
180
181
    [status,message,messageid] = mkdir([pathstr,'/',output_folder]);
    save([pathstr,'/',output_folder,'/g_stabilize_info.mat'],'p','roi');
5934cd22   Daniel Bourgault   g_stabilize rewri...
182
183
end

5934cd22   Daniel Bourgault   g_stabilize rewri...
184
185
186
187
188
189
190
191
192
193
%% 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);

972d1377   Pascal Bourgault   Voir commit prece...
194
time_per_img = 0;
5934cd22   Daniel Bourgault   g_stabilize rewri...
195
196
197

for i = 1:N
    
5934cd22   Daniel Bourgault   g_stabilize rewri...
198
    time_rem = (N-i+1)*time_per_img;
0f098f65   Dany Dumont   g_stabilize a ete...
199
    
972d1377   Pascal Bourgault   Voir commit prece...
200
    total = tic;
5934cd22   Daniel Bourgault   g_stabilize rewri...
201
202
203
204
205
206
207
    
    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]);
972d1377   Pascal Bourgault   Voir commit prece...
208
    end
4f1faf35   Daniel Bourgault   Small changes mad...
209
        
0f098f65   Dany Dumont   g_stabilize a ete...
210
211
212
213
214
215
216
217
218
219
    if i == 1
        display(['   Processing image: ',all_img(i).name]);
        display(['   Time remaining:   Yet undetermined. Please wait until next image.']);
        display(['  ']);
    else
        display(['   Processing image: ',all_img(i).name]);
        display(['   Time remaining:   ',datestr(time_rem/86400,'HH:MM:SS')]);
        display(['  ']);
    end

5934cd22   Daniel Bourgault   g_stabilize rewri...
220
    % Convert into gray scale if not already a B/W image
972d1377   Pascal Bourgault   Voir commit prece...
221
    if size(im1,3) ~= 1
0f098f65   Dany Dumont   g_stabilize a ete...
222
        im1_BW = g_rgb2gray(im1);
4f1faf35   Daniel Bourgault   Small changes mad...
223
224
    else
        im1_BW = im1;
5934cd22   Daniel Bourgault   g_stabilize rewri...
225
226
    end
    
0f098f65   Dany Dumont   g_stabilize a ete...
227
    im1_BW_cooked = im1_BW;
4f1faf35   Daniel Bourgault   Small changes mad...
228
        
5934cd22   Daniel Bourgault   g_stabilize rewri...
229
230
    % May equalize with this equalizer.
    if equalize
0f098f65   Dany Dumont   g_stabilize a ete...
231
        im1_BW_cooked = clahs(im1_BW_cooked,nry,nrx);
972d1377   Pascal Bourgault   Voir commit prece...
232
    end
7d7ce63d   Daniel Bourgault   First commit
233
    
0f098f65   Dany Dumont   g_stabilize a ete...
234
235
236
237
238
    im1_BW_cooked = double(im1_BW_cooked);    
    im1_BW        = double(im1_BW);

    % Normalize the image over the ROI.
    %im1_BW_cooked     = (im1_BW_cooked - nanmean(im1_BW_cooked(inorm)))./nanstd(im1_BW_cooked(inorm));
972d1377   Pascal Bourgault   Voir commit prece...
239
    
0f098f65   Dany Dumont   g_stabilize a ete...
240
241
242
243
    if use_img_grad
        [im1x, im1y]  = gradient(im1_BW_cooked);
        im1_BW_cooked = sqrt(im1x.^2 + im1y.^2);
    end
7d7ce63d   Daniel Bourgault   First commit
244
    
0f098f65   Dany Dumont   g_stabilize a ete...
245
    frames(1).im = im1_BW_cooked;
4f1faf35   Daniel Bourgault   Small changes mad...
246
        
0f098f65   Dany Dumont   g_stabilize a ete...
247
    [motion,stable] = g_videostabilize(frames,roi,L);
972d1377   Pascal Bourgault   Voir commit prece...
248
    
0f098f65   Dany Dumont   g_stabilize a ete...
249
250
251
252
253
    % Warp the original image and not the image that has been manipulated
    % for the stabilization.
    Acum        = [1 0 ; 0 1];
    Tcum        = [0 ; 0];
    [Acum,Tcum] = g_accumulatewarp(Acum, Tcum, motion(1).A, motion(1).T);
5934cd22   Daniel Bourgault   g_stabilize rewri...
254
    
0f098f65   Dany Dumont   g_stabilize a ete...
255
256
257
258
259
260
261
262
263
264
265
266
267
    RGB = true;
    if RGB
        for j = 1:3
            im1_stable(:,:,j) = g_warp(double(im1(:,:,j)), Acum, Tcum);
        end
        % Uncomment if wanna use the previous stabilized image as the reference image  
        %frames(2).im = (im1_stable(:,:,1) + im1_stable(:,:,2) + im1_stable(:,:,3))/3;
    else
        im1_stable   = g_warp(im1_BW, Acum, Tcum);
        % Uncomment if wanna use the previous stabilized image as the reference image  
        %frames(2).im = im1_stable;
    end

972d1377   Pascal Bourgault   Voir commit prece...
268
269
270
271
272
273
274
    if isfield(im_info,'DateTime')
        datetime = im_info.DateTime;
    elseif isfield(im_info,'Comment')
        datetime = im_info.Comment;
    else
        datetime = '';
    end
5934cd22   Daniel Bourgault   g_stabilize rewri...
275
276
    
    if length(pathstr) == 0
0f098f65   Dany Dumont   g_stabilize a ete...
277
        stable_img_fname = [output_folder,'/',all_img(i).name(1:end-4)];
5934cd22   Daniel Bourgault   g_stabilize rewri...
278
    else
0f098f65   Dany Dumont   g_stabilize a ete...
279
        stable_img_fname = [pathstr,output_folder,'/',all_img(i).name(1:end-4)];
5934cd22   Daniel Bourgault   g_stabilize rewri...
280
281
    end
    
0f098f65   Dany Dumont   g_stabilize a ete...
282
283
    imwrite(uint8(im1_stable),[stable_img_fname fname_suffix ext],...
           'Quality',100,'Comment',datetime);
5934cd22   Daniel Bourgault   g_stabilize rewri...
284
    
972d1377   Pascal Bourgault   Voir commit prece...
285
    time_per_img = toc(total);
0f098f65   Dany Dumont   g_stabilize a ete...
286
287
    
end