source: trunk/src/series/sub_background.m @ 453

Last change on this file since 453 was 451, checked in by sommeria, 12 years ago

bugs repaired in aver_stat and check_data_file

sub_background largely modified. Tests needed
other functions not yet translated

File size: 20.3 KB
Line 
1%'sub_background': substract background to an image series, used with series.fig
2%------------------------------------------------------------------------
3% Method:
4    %calculate the background image by sorting the luminosity of each point
5    % over a sliding sub-sequence of 'nbaver_ima' images.
6    % The luminosity value of rank 'rank' is selected as the
7    % 'background'. rank=nbimages/2 gives the median value.  Smaller values are appropriate
8    % for a dense set of particles. The extrem value rank=1 gives the true minimum
9    % luminosity, but it can be polluted by noise.
10% Organization of image indices:
11    % The program is working on a series of images, labelled by two indices i and j, given
12    % by the input matlab vectors num_i1 and num_j1 respectively. In the list, j is the fastest increasing index.
13    % The processing can be done in slices (number nbslice), with bursts of
14    % nbfield2 successive images for a given slice (mode 'multilevel')
15    % In the mode 'volume', nbfield2=1 (1 image at each level)
16   
17% function GUI_input=sub_background(Param)
18%
19%%%%%%%%%%% GENERAL TO ALL SERIES ACTION FCTS %%%%%%%%%%%%%%%%%%%%%%%%%%%
20%OUTPUT
21% GUI_input=list of options in the GUI series.fig needed for the function
22%
23%INPUT:
24% In run mode, the input parameters are given as a Matlab structure Param copied from the GUI series.
25% In batch mode, Param is the name of the corresponding xml file containing the same information
26% In the absence of input (as activated when the current Action is selected
27% in series), the function ouput GUI_input set the activation of the needed GUI elements
28%
29% Param contains the elements:(use the menu bar command 'export/GUI config' in series to see the current structure Param)
30%    .InputTable: cell of input file names, (several lines for multiple input)
31%                      each line decomposed as {RootPath,SubDir,Rootfile,NomType,Extension}
32%    .OutputSubDir: name of the subdirectory for data outputs
33%    .OutputDir: directory for data outputs, including path
34%    .Action: .ActionName: name of the current activated function
35%             .ActionPath:   path of the current activated function
36%    .IndexRange: set the file or frame indices on which the action must be performed
37%    .FieldTransform: .TransformName: name of the selected transform function
38%                     .TransformPath:   path  of the selected transform function
39%                     .TransformHandle: corresponding function handle
40%    .InputFields: sub structure describing the input fields withfields
41%              .FieldName: name of the field
42%              .VelType: velocity type
43%              .FieldName_1: name of the second field in case of two input series
44%              .VelType_1: velocity type of the second field in case of two input series
45%    .ProjObject: %sub structure describing a projection object (read from ancillary GUI set_object)
46%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
47
48   
49function GUI_input=sub_background (Param)
50
51%% set the input elements needed on the GUI series when the action is selected in the menu ActionName
52if ~exist('Param','var') % case with no input parameter
53    GUI_input={'NbViewMax';1;...% max nbre of input file series (default='' , no limitation)
54        'AllowInputSort';'off';...% allow alphabetic sorting of the list of input files (options 'off'/'on', 'off' by default)
55        'NbSlice';'on'; ...%nbre of slices ('off' by default)
56        'VelType';'off';...% menu for selecting the velocity type (options 'off'/'one'/'two',  'off' by default)
57        'FieldName';'off';...% menu for selecting the field (s) in the input file(options 'off'/'one'/'two', 'off' by default)
58        'FieldTransform'; 'off';...%can use a transform function
59        'ProjObject';'off';...%can use projection object(option 'off'/'on',
60        'Mask';'off';...%can use mask option   (option 'off'/'on', 'off' by default)
61        'OutputDirExt';'.sbk';...%set the output dir extension
62               ''};
63        return
64end
65
66%%%%%%%%%%%% STANDARD PART (DO NOT EDIT) %%%%%%%%%%%%
67%% get input parameters, file names and indices
68% BATCH  case: read the xml file for batch case
69if ischar(Param) && ~isempty(find(regexp(Param,'.xml$')))
70    Param=xml2struct(Param);
71    checkrun=0;
72% RUN case: parameters introduced as the input structure Param 
73else
74    hseries=guidata(Param.hseries);%handles of the GUI series
75    WaitbarPos=get(hseries.waitbar_frame,'Position');%position of the waitbar on the GUI series
76    checkrun=1; % indicate the RUN option is used
77end
78% get the set of input file names (cell array filecell), and the lists of
79% input file or frame indices i1_series,i2_series,j1_series,j2_series
80[filecell,i1_series,i2_series,j1_series,j2_series]=get_file_series(Param);
81% filecell{iview,fileindex}: cell array representing the list of file names
82%        iview: line in the table corresponding to a given file series
83%        fileindex: file index within  the file series,
84% i1_series(iview,ref_j,ref_i)... are the corresponding arrays of indices i1,i2,j1,j2, depending on the input line iview and the two reference indices ref_i,ref_j
85% i1_series(iview,fileindex) expresses the same indices as a 1D array in file indices
86% set of frame indices used for movie or multimage input
87if ~isempty(j1_series)
88    frame_index=j1_series;
89else
90    frame_index=i1_series;
91end
92
93%% root input file(s) and type
94RootPath=Param.InputTable(:,1);
95RootFile=Param.InputTable(:,3);
96SubDir=Param.InputTable(:,2);
97NomType=Param.InputTable(:,4);
98FileExt=Param.InputTable(:,5);
99
100% numbers of slices and file indices
101NbSlice=1;%default
102if isfield(Param.IndexRange,'NbSlice')
103    NbSlice=Param.IndexRange.NbSlice;
104end
105nbview=size(i1_series,1);%number of input file series (lines in InputTable)
106nbfield_j=size(i1_series,2); %nb of consecutive fields at each level(burst
107nbfield=nbfield_j*size(i1_series,3); %total number of files or frames
108nbfield_i=floor(nbfield/NbSlice);%total number of i indexes (adjusted to an integer number of slices)
109nbfield=nbfield_i*nbfield_j; %total number of fields after adjustement
110
111%determine the file type on each line from the first input file
112ImageTypeOptions={'image','multimage','mmreader','video'};
113NcTypeOptions={'netcdf','civx','civdata'};
114   
115% % for iview=1:nbview
116%     if ~exist(filecell{iview,1}','file')
117%         msgbox_uvmat('ERROR',['the first input file ' filecell{iview,1} ' does not exist'])
118%         return
119%     end
120%     [FileType{iview},FileInfo{iview},Object{iview}]=get_file_type(filecell{iview,1});
121%     CheckImage{iview}=~isempty(find(strcmp(FileType{iview},ImageTypeOptions)));% =1 for images
122%     CheckNc{iview}=~isempty(find(strcmp(FileType{iview},NcTypeOptions)));% =1 for netcdf files
123% end
124
125[FileType,FileInfo,MovieObject]=get_file_type(filecell{1,1});
126CheckImage=~isempty(find(strcmp(FileType,ImageTypeOptions)));% =1 for images
127
128%% calibration data and timing: read the ImaDoc files
129%not relevant here
130
131%% check coincidence in time for several input file series
132%not relevant here
133
134%% coordinate transform or other user defined transform
135%not relevant here
136
137%%%%%%%%%%%% END STANDARD PART  %%%%%%%%%%%%
138 % EDIT FROM HERE
139
140 %% check the validity of  input file types
141if CheckImage
142    FileExtOut='.png'; % write result as .png images for image inputs
143    NomTypeOut='_1_1';
144else
145    msgbox_uvmat('ERROR',['invalid file type input: ' FileType{1} ' not an image'])
146    return
147end
148%
149% NomTypeOut='_1-2_1';% output file index will indicate the first and last ref index in the series
150% if NbSlice~=nbfield_j
151%     answer=msgbox_uvmat('INPUT_Y-N',['will not average slice by slice: for so cancel and set NbSlice= ' num2str(nbfield_j)]);
152%     if ~strcmp(answer,'Yes')
153%         return
154%     end
155% end
156
157%% Set field names and velocity types
158%not relevant here
159
160
161%% Initiate output fields
162%not relevant here
163 
164%%% SPECIFIC PART BEGINS HERE
165NbSlice=Param.IndexRange.NbSlice; %number of slices
166siz=size(i1_series);
167nbaver_init=23;%approximate number of images used for the sliding background: to be adjusted later to include an integer number of bursts
168j1=[];%default
169
170%% apply the image rescaling function 'level' (avoid the blinking effects of bright particles)
171answer=msgbox_uvmat('INPUT_Y-N','apply image rescaling function levels.m after sub_background');
172test_level=isequal(answer,'Yes');
173
174%% adjust the proposed number of images in the sliding average to include an integer number of bursts
175if siz(3)~=1
176    nbaver=floor(nbaver_init/siz(2)); % number of bursts used for the sliding background,
177    if isequal(floor(nbaver/2),nbaver)
178        nbaver=nbaver+1;%put the number of burst to an odd number (so the middle burst is defined)
179    end
180    nbaver_init=nbaver*siz(2);%propose by default an integer number of bursts
181end
182
183%% set processing parameters
184prompt = {'Number of images for the sliding background (MUST FIT IN COMPUETER MEMORY)';'The number of positions (laser slices)';'volume scan mode (Yes/No)';...
185    'the luminosity rank chosen to define the background (0.1=for dense particle seeding, 0.5 (median) for sparse particles'};
186dlg_title = ['get (slice by slice) a sliding background and substract to each image, result in subdir ' Param.OutputDir];
187num_lines= 3;
188def     = { num2str(nbaver_init);num2str(NbSlice);'No';'0.1'};
189answer = inputdlg(prompt,dlg_title,num_lines,def);
190set(hseries.ParamVal,'String',answer([1 [3:4]]))
191set(hseries.ParamVal,'Visible','on')
192
193nbaver_ima=str2num(answer{1});%number of images for the sliding background
194nbaver=ceil(nbaver_ima/siz(2));%number of bursts for the sliding background
195if isequal(floor(nbaver/2),nbaver)
196    nbaver=nbaver+1;%put the number of burst to an odd number (so the middle burst is defined)
197end
198step=siz(2);%case of bursts: the sliding background is shifted by one burst
199vol_test=answer{3};
200if isequal(vol_test,'Yes')
201    nbfield2=1;%case of volume: no consecutive series at a given level
202    NbSlice=siz(2);%number of slices
203else
204    nbfield2=siz(2); %nb of consecutive images at each level(burst)
205    if siz(3)>1
206        % NbSlice=str2num(answer{2})/(num_i1(1,2)-num_i1(1,1));% number of slices
207        NbSlice=str2num(answer{2})/(i1_series(1,1,2)-i1_series(1,1,1));% number of slices
208    else
209        NbSlice=1;
210    end
211    if ~isequal(floor(NbSlice),NbSlice)
212        msgbox_uvmat('ERROR','the number of slices must be a multiple of the i increment')
213        return
214    end
215end
216rank=floor(str2num(answer{4})*nbaver_ima);
217if rank==0
218    rank=1;%rank selected in the sorted image series
219end
220lengthtot=siz(2)*siz(3);
221nbfield=floor(lengthtot/(nbfield2*NbSlice));%total number of i indexes (adjusted to an integer number of slices)
222nbfield_slice=nbfield*nbfield2;% number of fields per slice
223if nbaver_ima > nbfield*nbfield2
224    msgbox_uvmat('ERROR','number of images in a slice smaller than the proposed number of images for the sliding average')
225    return
226end
227nbfirst=(ceil(nbaver/2))*step;
228if nbfirst>nbaver_ima
229    nbfirst=ceil(nbaver_ima/2);
230    step=1;
231    nbaver=nbaver_ima;
232end
233
234%% prealocate memory for the sliding background
235Afirst=read_image(filecell{1,1},FileType{1},MovieObject,i1_series(1,1));
236[npy,npx]=size(Afirst);
237try
238    Ak=zeros(npy,npx,nbaver_ima,'uint16'); %prealocate memory
239    Asort=zeros(npy,npx,nbaver_ima,'uint16'); %prealocate memory
240catch ME
241    msgbox_uvmat('ERROR',ME.message)
242    return
243end
244
245%% update the xml file
246SubDirBase=regexprep(Param.InputTable{1,2},'\..*','');%take the root part of SubDir, before the first dot '.'
247filexml=fullfile(RootPath{1},[SubDirBase '.xml']);
248if ~exist(filexml,'file') && exist([filebase '.xml'],'file')% xml inside the image directory
249    copyfile([filebase '.xml'],filexml);% copy the .xml file
250end
251if exist(filexml,'file')
252    t=xmltree(filexml); 
253    %update information on the first image name in the series
254    uid_Heading=find(t,'ImaDoc/Heading');
255    if isempty(uid_Heading)
256        [t,uid_Heading]=add(t,1,'element','Heading');
257    end
258    uid_ImageName=find(t,'ImaDoc/Heading/ImageName');
259    if ~isempty(j1_series{1})
260        j1=j1_series{1}(1);
261    end
262    ImageName=fullfile_uvmat([dir_images term],'',RootFile{1},'.png',NomType,i1_series(1,1),[],j1);
263    [pth,ImageName]=fileparts(ImageName);
264    ImageName=[ImageName '.png'];
265    if isempty(uid_ImageName)
266        [t,uid_ImageName]=add(t,uid_Heading,'element','ImageName');
267    end
268    uid_value=children(t,uid_ImageName);
269    if isempty(uid_value)
270        t=add(t,uid_ImageName,'chardata',ImageName);%indicate  name of the first image, with ;png extension
271    else
272        t=set(t,uid_value(1),'value',ImageName);%indicate  name of the first image, with ;png extension
273    end
274   
275    %add information about image transform
276    [t,new_uid]=add(t,1,'element','ImageTransform');
277    [t,NameFunction_uid]=add(t,new_uid,'element','NameFunction');
278    [t]=add(t,NameFunction_uid,'chardata','sub_background');
279    if test_level
280        [t,NameFunction_uid]=add(t,new_uid,'element','NameFunction');
281        [t]=add(t,NameFunction_uid,'chardata','levels');
282    end
283    [t,NbSlice_uid]=add(t,new_uid,'element','NbSlice');
284    [t]=add(t,new_uid,'chardata',num2str(NbSlice));
285    [t,NbSlidingImages_uid]=add(t,new_uid,'element','NbSlidingImages');
286    [t]=add(t,NbSlidingImages_uid,'chardata',num2str(nbaver));
287    [t,LuminosityRank_uid]=add(t,new_uid,'element','RankBackground');
288    [t]=add(t,LuminosityRank_uid,'chardata',num2str(rank));% luminosity rank almong the nbaver sliding images
289    save(t,filexml)
290end
291%copy the mask
292% if exist([filebase '_1mask_1'],'file')
293%     copyfile([filebase '_1mask_1'],[filebase_b '_1mask_1']);% copy the mask file
294% end
295
296%MAIN LOOP ON SLICES
297for islice=1:NbSlice
298    %% select the series of image indices at the level islice
299    for ifield=1:nbfield
300        for iburst=1:nbfield2
301            indselect(iburst,ifield)=((ifield-1)*NbSlice+(islice-1))*nbfield2+iburst;
302        end
303    end
304   
305    %% read the first series of nbaver_ima images and sort by luminosity at each pixel
306    for ifield = 1:nbaver_ima
307        ifile=indselect(ifield);
308        filename=filecell{1,ifile};
309        Aread=read_image(filename,FileType,MovieObject,i1_series{1}(ifile));
310        Ak(:,:,ifield)=Aread;
311    end
312    Asort=sort(Ak,3);%sort the luminosity of images at each point
313    B=Asort(:,:,rank);%background image
314    display( 'first background image will be substracted')
315    for ifield=1:nbfirst
316        Acor=double(Ak(:,:,ifield))-double(B);%substract background to the current image
317        Acor=(Acor>0).*Acor; % put to 0 the negative elements in Acor
318        C=uint16(Acor);% set to integer 16 bits
319        ifile=indselect(ifield);
320        %             newname=name_generator(filebase_b,num_i1(ifile),num_j1(ifile),'.png',NomType)% makes the new file name
321        if ~isempty(j1_series{1})
322            j1=j1_series{1}(ifile);
323        end
324        newname=fullfile_uvmat(RootPath{1},Param.OutputSubDir,RootFile{1},FileExtOut,NomTypeOut,i1_series(1,ifile),[],i_slice,[]);
325%         newname=fullfile_uvmat(RootPath{1},SubdirResult,RootFile{1},'.png',NomType,i1_series{1}(ifile),[],j1);
326        %newname=name_generator(filebase_b,i1_series{1}(ifile),j1_series{1}(ifile),'.png',NomType);% makes the new file name
327        if test_level
328            C=levels(C);
329            imwrite(C,newname,'BitDepth',8); % save the new image
330        else
331            imwrite(C,newname,'BitDepth',16); % save the new image
332        end
333    end
334   
335    %% repeat the operation on a sliding series of nbaver*nbfield2 images
336    display('sliding background image will be substracted')
337    if nbfield_slice > nbaver_ima
338        for ifield = step*ceil(nbaver/2)+1:step:nbfield_slice-step*floor(nbaver/2)
339            if checkrun
340                stopstate=get(hseries.RUN,'BusyAction');
341                update_waitbar(hseries.waitbar_frame,WaitbarPos,(ifield+(islice-1)*nbfield_slice)/(nbfield_slice*NbSlice))
342            else
343                stopstate='queue';
344            end
345            if isequal(stopstate,'queue')% enable STOP command
346                Ak(:,:,1:nbaver_ima-step)=Ak(:,:,1+step:nbaver_ima);% shift the current image series by one burst (step)
347                %incorporate next burst in the current image series
348                for iburst=1:step
349                    ifile=indselect(ifield+step*floor(nbaver/2)+iburst-1);
350                    filename=fullfile_uvmat(RootPath{1},SubDir,RootFile{1},FileExt,NomType,i1_series(1,ifile),[],j1_series(1,ifile));
351                    %filename=name_generator(filebase,num_i1(ifile),num_j1(ifile),FileExt,NomType);
352                    Aread=read_image(filename,FileType,MovieObject,i1_series(1,ifile));
353                    Ak(:,:,nbaver_ima-step+iburst)=Aread;
354                end
355                Asort=sort(Ak,3);%sort the new current image series by luminosity
356                B=Asort(:,:,rank);%current background image
357                for iburst=1:step
358                    index=step*floor(nbaver/2)+iburst;
359                    Acor=double(Ak(:,:,index))-double(B);
360                    Acor=(Acor>0).*Acor; % put to 0 the negative elements in Acor
361                    C=uint16(Acor);
362                    ifile=indselect(ifield+iburst-1);
363                    if ~isempty(j1_series{1})
364                        j1=j1_series{1}(ifile);
365                    end
366                    newname=fullfile_uvmat(RootPath{1},Param.OutputSubDir,RootFile{1},FileExtOut,NomTypeOut,i1_series(1,1),[],i_slice,[]);
367                   % newname=fullfile_uvmat(Param.InputTable{1,1},SubdirResult,Param.InputTable{1,3},'.png',NomType,i1_series{1}(ifile),[],j1);
368                    %[newname]=name_generator(filebase_b,num_i1(ifile),num_j1(ifile),'.png',NomType) % makes the new file name
369                    if test_level
370                        C=levels(C);
371                        imwrite(C,newname,'BitDepth',8); % save the new image
372                    else
373                        imwrite(C,newname,'BitDepth',16); % save the new image
374                    end
375                end
376            else
377                return
378            end
379        end
380    end
381   
382    %% substract the background from the last images
383    display('last background image will be substracted')
384    ifield=nbfield_slice-(step*ceil(nbaver/2))+1:nbfield_slice;
385    for ifield=nbfield_slice-(step*floor(nbaver/2))+1:nbfield_slice
386        index=ifield-nbfield_slice+step*(2*floor(nbaver/2)+1);
387        Acor=double(Ak(:,:,index))-double(B);
388        Acor=(Acor>0).*Acor; % put to 0 the negative elements in Acor
389        C=uint16(Acor);
390        ifile=indselect(ifield);
391        if ~isempty(j1_series{1})
392            j1=j1_series{1}(ifile);
393        end
394        newname=fullfile_uvmat(RootPath{1},Param.OutputSubDir,RootFile{1},FileExtOut,NomTypeOut,i1_series(1,ifile),[],j1);
395%         newname=fullfile_uvmat(Param.InputTable{1,1},SubdirResult,Param.InputTable{1,3},'.png',NomType,i1_series{1}(ifile),[],j1);
396        if test_level
397            C=levels(C);
398            imwrite(C,newname,'BitDepth',8); % save the new image
399        else
400            imwrite(C,newname,'BitDepth',16); % save the new image
401        end
402    end
403end
404
405%finish the waitbar
406if checkrun
407    update_waitbar(hseries.waitbar,WaitbarPos,1)
408end
409
410%------------------------------------------------------------------------
411%--read images and convert them to the uint16 format used for PIV
412function A=read_image(FileName,FileType,VideoObject,num)
413%------------------------------------------------------------------------
414%num is the view number needed for an avi movie
415switch FileType
416    case {'video','mmreader'}
417        A=read(VideoObject,num);
418    case 'multimage'
419        A=imread(FileName,num);
420    case 'image'   
421        A=imread(FileName);
422end
423siz=size(A);
424if length(siz)==3;%color images
425    A=sum(double(A),3);% take the sum of color components
426end
427   
428
429function C=levels(A)
430%whos A;
431B=double(A(:,:,1));
432windowsize=round(min(size(B,1),size(B,2))/20);
433windowsize=floor(windowsize/2)*2+1;
434ix=1/2-windowsize/2:-1/2+windowsize/2;%
435%del=np/3;
436%fct=exp(-(ix/del).^2);
437fct2=cos(ix/(windowsize-1)/2*pi/2);
438%Mfiltre=(ones(5,5)/5^2);
439%Mfiltre=fct2';
440Mfiltre=fct2'*fct2;
441Mfiltre=Mfiltre/(sum(sum(Mfiltre)));
442
443C=filter2(Mfiltre,B);
444C(:,1:windowsize)=C(:,windowsize)*ones(1,windowsize);
445C(:,end-windowsize+1:end)=C(:,end-windowsize+1)*ones(1,windowsize);
446C(1:windowsize,:)=ones(windowsize,1)*C(windowsize,:);
447C(end-windowsize+1:end,:)=ones(windowsize,1)*C(end-windowsize,:);
448C=tanh(B./(2*C));
449[n,c]=hist(reshape(C,1,[]),100);
450% figure;plot(c,n);
451
452[m,i]=max(n);
453c_max=c(i);
454[dummy,index]=sort(abs(c-c(i)));
455n=n(index);
456c=c(index);
457i_select = find(cumsum(n)<0.95*sum(n));
458if isempty(i_select)
459    i_select = 1:length(c);
460end
461c_select=c(i_select);
462n_select=n(i_select);
463cmin=min(c_select);
464cmax=max(c_select);
465C=(C-cmin)/(cmax-cmin)*256;
466C=uint8(C);
Note: See TracBrowser for help on using the repository browser.