source: trunk/src/series/civ_series.m @ 758

Last change on this file since 758 was 758, checked in by sommeria, 10 years ago

checking of file input improved do deal with holes in files series

File size: 49.8 KB
Line 
1%'civ_series': PIV function activated by the general GUI series
2% --- call the sub-functions:
3%   civ: PIV function itself
4%   fix: removes false vectors after detection by various criteria
5%   filter_tps: make interpolation-smoothing
6%------------------------------------------------------------------------
7% function [Data,errormsg,result_conv]= civ_series(Param,ncfile)
8%
9%OUTPUT
10% Data=structure containing the PIV results and information on the processing parameters
11% errormsg=error message char string, default=''
12% resul_conv: image inter-correlation function for the last grid point (used for tests)
13%
14%INPUT:
15% Param: input images and processing parameters
16%     .Civ1: for civ1
17%     .Fix1:
18%     .Patch1:
19%     .Civ2: for civ2
20%     .Fix2:
21%     .Patch2:
22% ncfile: name of a netcdf file to be created for the result (extension .nc)
23%
24%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
25%  Copyright  2011, LEGI / CNRS-UJF-INPG, joel.sommeria@legi.grenoble-inp.fr.
26%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
27%     This is part of the toolbox UVMAT.
28%
29%     UVMAT is free software; you can redistribute it and/or modify
30%     it under the terms of the GNU General Public License as published by
31%     the Free Software Foundation; either version 2 of the License, or
32%     (at your option) any later version.
33%
34%     UVMAT is distributed in the hope that it will be useful,
35%     but WITHOUT ANY WARRANTY; without even the implied warranty of
36%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37%     GNU General Public License (open UVMAT/COPYING.txt) for more details.
38%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
39
40function [Data,errormsg,result_conv]= civ_series(Param)
41errormsg='';
42path_series=fileparts(which('series'));
43addpath(fullfile(path_series,'series'))
44%% set the input elements needed on the GUI series when the action is selected in the menu ActionName or InputTable refreshed
45if isstruct(Param) && isequal(Param.Action.RUN,0)% function activated from the GUI series but not RUN
46    Data=civ_input(Param);% introduce the civ parameters using the GUI civ_input
47    if isempty(Data)
48        Data=Param;% if  civ_input has been cancelled, keep previous parameters
49    end
50    Data.Program=mfilename;%gives the name of the current function
51    Data.AllowInputSort='off';% allow alphabetic sorting of the list of input file SubDir (options 'off'/'on', 'off' by default)
52    Data.WholeIndexRange='off';% prescribes the file index ranges from min to max (options 'off'/'on', 'off' by default)
53    if strcmp(Data.ActionInput.PairIndices.ListPairMode,'pair j1-j2')
54        Data.Desable_j_index='on';% hide the j index in series (set by the pair choice in civ_input)
55    end
56    Data.NbSlice='off'; %nbre of slices ('off' by default)
57    Data.VelType='off';% menu for selecting the velocity type (options 'off'/'one'/'two',  'off' by default)
58    Data.FieldName='off';% menu for selecting the field (s) in the input file(options 'off'/'one'/'two', 'off' by default)
59    Data.FieldTransform = 'off';%can use a transform function
60    Data.ProjObject='off';%can use projection object(option 'off'/'on',
61    Data.Mask='off';%can use mask option   (option 'off'/'on', 'off' by default)
62    Data.OutputDirExt='.civ';%set the output dir extension
63    Data.OutputSubDirMode='last'; %select the last subDir in the input table as root of the output subdir name (option 'all'/'first'/'last', 'all' by default)
64    Data.OutputFileMode='NbInput_i';% one output file expected per value of i index (used for waitbar)
65        % check the existence of the first file in the series: suppressed
66%     first_j=[];
67%     if isfield(Param.IndexRange,'first_j'); first_j=Param.IndexRange.first_j; end
68%     last_j=[];
69%     if isfield(Param.IndexRange,'last_j'); last_j=Param.IndexRange.last_j; end
70%     PairString='';
71%     if isfield(Param.IndexRange,'PairString'); PairString=Param.IndexRange.PairString; end
72    return
73end
74
75%% read input parameters from an xml file if input is a file name (batch mode)
76checkrun=1;
77if ischar(Param)
78    Param=xml2struct(Param);% read Param as input file (batch case)
79    checkrun=0;
80end
81if ~isfield(Param,'ActionInput')
82     disp_uvmat('ERROR','no parameter set for PIV',checkrun)
83        return
84end
85hseries=findobj(allchild(0),'Tag','series');
86RUNHandle=findobj(hseries,'Tag','RUN');%handle of RUN button in GUI series
87WaitbarHandle=findobj(hseries,'Tag','Waitbar');%handle of waitbar in GUI series
88
89%% input files and indexing
90% NbField=1;
91MaxIndex_i=Param.IndexRange.MaxIndex_i;
92MinIndex_i=Param.IndexRange.MinIndex_i;
93MaxIndex_j=1;MinIndex_j=1;
94if isfield(Param.IndexRange,'MaxIndex_j')&& isfield(Param.IndexRange,'MinIndex_j')
95    MaxIndex_j=Param.IndexRange.MaxIndex_j;
96    MinIndex_j=Param.IndexRange.MinIndex_j;
97end
98if isfield(Param,'InputTable')
99    [tild,i_series,tild,j_series]=get_file_series(Param);
100    % iview_nc=0;% series index (iview) for an input nc file (for civ2 or patch2)
101    iview_A=0;% series index (iview) for the first image series
102    iview_B=0;% series index (iview) for the second image series (only non zero for option 'shift' comparing two image series )
103    if Param.ActionInput.CheckCiv1
104        iview_A=1;% usual PIV, the image series is on the first line of the table
105    elseif Param.ActionInput.CheckCiv2 % civ2 is performed without Civ1, a netcdf file series is needed in the first table line
106        iview_A=2;% the second line is used for the input images of Civ2
107    end
108    if strcmp(Param.ActionInput.ListCompareMode,'shift')
109        iview_B=iview_A+1; % the second image series is on the next line of the tinput table
110    end
111    if iview_A~=0
112        RootPath_A=Param.InputTable{iview_A,1};
113        RootFile_A=Param.InputTable{iview_A,3};
114        SubDir_A=Param.InputTable{iview_A,2};
115        NomType_A=Param.InputTable{iview_A,4};
116        FileExt_A=Param.InputTable{iview_A,5};
117        if iview_B==0
118            iview_B=iview_A;% the second image series is the same as the first
119        end
120        RootPath_B=Param.InputTable{iview_B,1};
121        RootFile_B=Param.InputTable{iview_B,3};
122        SubDir_B=Param.InputTable{iview_B,2};
123        NomType_B=Param.InputTable{iview_B,4};
124        FileExt_B=Param.InputTable{iview_B,5};
125    end
126   
127    PairCiv2='';
128    switch Param.ActionInput.ListCompareMode
129        case 'PIV'
130            PairCiv1=Param.ActionInput.PairIndices.ListPairCiv1;
131            if isfield(Param.ActionInput.PairIndices,'ListPairCiv2')
132                PairCiv2=Param.ActionInput.PairIndices.ListPairCiv2;
133            end
134            [i1_series_Civ1,i2_series_Civ1,j1_series_Civ1,j2_series_Civ1,check_bounds,NomTypeNc]=...
135                find_pair_indices(PairCiv1,i_series{1},j_series{1},MinIndex_i,MaxIndex_i,MinIndex_j,MaxIndex_j);
136            if ~isempty(PairCiv2)
137                [i1_series_Civ2,i2_series_Civ2,j1_series_Civ2,j2_series_Civ2,check_bounds_Civ2]=...
138                    find_pair_indices(PairCiv2,i_series{1},j_series{1},MinIndex_i,MaxIndex_i,MinIndex_j,MaxIndex_j);
139                check_bounds=check_bounds | check_bounds_Civ2;
140            end
141            i1_series_Civ1=i1_series_Civ1(~check_bounds);
142            i2_series_Civ1=i2_series_Civ1(~check_bounds);
143            j1_series_Civ1=j1_series_Civ1(~check_bounds);
144            j2_series_Civ1=j2_series_Civ1(~check_bounds);
145        case 'displacement'
146            i1_series_Civ1=Param.ActionInput.OriginIndex*ones(size(i_series{1}));
147            i2_series_Civ1=i_series{1};i2_series_Civ2=i_series{1};
148            j1_series_Civ1=ones(size(i_series{1}));% first j index is 1
149            if isempty(j_series{1})
150                j2_series_Civ1=ones(size(i_series{1}));
151            else
152                j2_series_Civ1=j_series{1};
153            end
154            i1_series_Civ2=i1_series_Civ1;
155            j1_series_Civ2=j1_series_Civ1;
156            j2_series_Civ2=j2_series_Civ1;
157            NomTypeNc=NomType;
158        case 'shift'
159            i1_series_Civ1=i_series{1};i1_series_Civ2=i_series{1};
160            i2_series_Civ1=i_series{1};i2_series_Civ2=i_series{1};
161            if isempty(j_series{1})
162                j1_series_Civ1=ones(size(i_series{1}));
163                j2_series_Civ1=ones(size(i_series{1}));
164            else
165                j1_series_Civ1=j_series{1};
166                j2_series_Civ1=j_series{1};
167            end
168            j1_series_Civ2=j1_series_Civ1;
169            j2_series_Civ2=j2_series_Civ1;
170            NomTypeNc=NomType_A;
171    end
172    if isempty(j_series{1})
173        FrameIndex_A_Civ1=i1_series_Civ1;
174        FrameIndex_B_Civ1=i2_series_Civ1;
175    else
176        FrameIndex_A_Civ1=j1_series_Civ1;
177        FrameIndex_B_Civ1=j2_series_Civ1;
178    end
179    if ~isempty(PairCiv2)
180        i1_series_Civ2=i1_series_Civ2(~check_bounds);
181        i2_series_Civ2=i2_series_Civ2(~check_bounds);
182        j1_series_Civ2=j1_series_Civ2(~check_bounds);
183        j2_series_Civ2=j2_series_Civ2(~check_bounds);
184        if isempty(j_series{1})
185            FrameIndex_A_Civ2=i1_series_Civ2;
186            FrameIndex_B_Civ2=i2_series_Civ2;
187        else
188            FrameIndex_A_Civ2=j1_series_Civ2;
189            FrameIndex_B_Civ2=j2_series_Civ2;
190        end
191    end
192    if isempty(i1_series_Civ1)||(~isempty(PairCiv2) && isempty(i1_series_Civ2))
193        disp_uvmat('ERROR','no image pair fo civ in the input file index range',checkrun)
194        return
195    end
196end
197
198%% check the first image pair
199try
200    if Param.ActionInput.CheckCiv1% Civ1 is performed
201        ImageName_A=fullfile_uvmat(RootPath_A,SubDir_A,RootFile_A,FileExt_A,NomType_A,i1_series_Civ1(1),[],j1_series_Civ1(1));
202        if ~exist(ImageName_A,'file')
203            disp_uvmat('ERROR',['first input image ' ImageName_A ' does not exist'],checkrun)
204            return
205        end
206        [FileType_A,FileInfo_A,VideoObject_A]=get_file_type(ImageName_A);
207        [par_civ1.ImageA,VideoObject_A] = read_image(ImageName_A,FileType_A,VideoObject_A,FrameIndex_A_Civ1(1));
208        ImageName_B=fullfile_uvmat(RootPath_B,SubDir_B,RootFile_B,FileExt_B,NomType_B,i2_series_Civ1(1),[],j2_series_Civ1(1));
209        if ~exist(ImageName_B,'file')
210            disp_uvmat('ERROR',['first input image ' ImageName_B ' does not exist'],checkrun)
211            return
212        end
213        [FileType_B,FileInfo_B,VideoObject_B]=get_file_type(ImageName_B);
214        [par_civ1.ImageB,VideoObject_B] = read_image(ImageName_B,FileType_B,VideoObject_B,FrameIndex_B_Civ1(1));
215        NbField=numel(i1_series_Civ1);
216    elseif Param.ActionInput.CheckCiv2 % Civ2 is performed without Civ1
217        ImageName_A=fullfile_uvmat(RootPath_A,SubDir_A,RootFile_A,FileExt_A,NomType_A,i1_series_Civ2(1),[],j1_series_Civ2(1));
218        if ~exist(ImageName_A,'file')
219            disp_uvmat('ERROR',['first input image ' ImageName_A ' does not exist'],checkrun)
220            return
221        end
222        [FileType_A,FileInfo_A,VideoObject_A]=get_file_type(ImageName_A);
223        [par_civ1.ImageA,VideoObject_A] = read_image(ImageName_A,FileType_A,VideoObject_A,FrameIndex_A_Civ2(1));
224        ImageName_B=fullfile_uvmat(RootPath_B,SubDir_B,RootFile_B,FileExt_B,NomType_B,i2_series_Civ2(1),[],j2_series_Civ2(1));
225        if ~exist(ImageName_B,'file')
226            disp_uvmat('ERROR',['first input image ' ImageName_B ' does not exist'],checkrun)
227            return
228        end
229        [FileType_B,FileInfo_B,VideoObject_B]=get_file_type(ImageName_B);
230        [par_civ1.ImageB,VideoObject_B] = read_image(ImageName_B,FileType_B,VideoObject_B,FrameIndex_B_Civ2(1));
231        NbField=numel(i1_series_Civ2);
232    end
233catch ME
234    if ~isempty(ME.message)
235        disp_uvmat('ERROR', ['error reading input image: ' ME.message],checkrun)
236        return
237    end
238end
239
240
241%% Output directory
242OutputDir=[Param.OutputSubDir Param.OutputDirExt];
243
244Data.ListGlobalAttribute={'Conventions','Program','CivStage'};
245Data.Conventions='uvmat/civdata';% states the conventions used for the description of field variables and attributes
246Data.Program='civ_series';
247Data.CivStage=0;%default
248% ListVarCiv1={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_C','Civ1_F'}; %variables to read
249% ListVarFix1={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_C','Civ1_F','Civ1_FF'};
250% mask='';
251maskname='';%default
252check_civx=0;%default
253% check_civ1=0;%default
254% check_patch1=0;%default
255
256%% get timing from the ImaDoc file or input video
257XmlFileName=find_imadoc(RootPath_A,SubDir_A,RootFile_A,FileExt_A);
258time=[];
259if ~isempty(XmlFileName)
260    XmlData=imadoc2struct(XmlFileName);
261        if isfield(XmlData,'Time')
262            time=XmlData.Time;
263            TimeSource='xml';
264        end
265        if isfield(XmlData,'Camera')
266            if isfield(XmlData.Camera,'NbSlice')&& ~isempty(XmlData.Camera.NbSlice)
267                NbSlice_calib{iview}=XmlData.Camera.NbSlice;% Nbre of slices for Zindex in phys transform
268                if ~isequal(NbSlice_calib{iview},NbSlice_calib{1})
269                    msgbox_uvmat('WARNING','inconsistent number of Z indices for the two field series');
270                end
271            end
272            if isfield(XmlData.Camera,'TimeUnit')&& ~isempty(XmlData.Camera.TimeUnit)
273                TimeUnit=XmlData.Camera.TimeUnit;
274            end
275        end
276end
277if isempty(time) && ~isempty(find(strcmp(FileType_A,{'mmreader','video'})))% case of video input
278    time=zeros(FileInfo_A.NumberOfFrames+1,2);
279    time(:,2)=(0:1/FileInfo_A.FrameRate:(FileInfo_A.NumberOfFrames)/FileInfo_A.FrameRate)';
280    TimeSource='video';
281    ColorType='truecolor';
282end
283if isempty(time)% time = index i +0.001 index j by default
284    time=(MinIndex_i:MaxIndex_i)'*ones(1,MaxIndex_j-MinIndex_j+1);
285    time=time+0.001*ones(MaxIndex_i-MinIndex_i+1,1)*(MinIndex_j:MaxIndex_j);
286    time=[zeros(1,MaxIndex_j-MinIndex_j+1);time];% insert a first line of zeros
287    time=[zeros(MaxIndex_i-MinIndex_i+2,1) time];% insert a first column of zeros
288end
289   
290if length(FileInfo_A) >1 %case of image with multiple frames
291    nbfield=length(FileInfo_A);
292    nbfield_j=1;
293end
294
295%%%%% MAIN LOOP %%%%%%
296for ifield=1:NbField
297    update_waitbar(WaitbarHandle,ifield/NbField)
298    if ~isempty(RUNHandle) && ~strcmp(get(RUNHandle,'BusyAction'),'queue')
299        disp('program stopped by user')
300        break
301    end
302    if strcmp(Param.ActionInput.ListCompareMode,'PIV')
303        ncfile=fullfile_uvmat(RootPath_A,OutputDir,RootFile_A,'.nc',NomTypeNc,i1_series_Civ1(ifield),i2_series_Civ1(ifield),...
304            j1_series_Civ1(ifield),j2_series_Civ1(ifield));
305    else
306        ncfile=fullfile_uvmat(RootPath_A,OutputDir,RootFile_A,'.nc',NomTypeNc,i2_series_Civ1(ifield),[],...
307            j1_series_Civ1(ifield),j2_series_Civ1(ifield));
308    end
309
310    %% Civ1
311    % if Civ1 computation is requested
312    if isfield (Param.ActionInput,'Civ1')
313        par_civ1=Param.ActionInput.Civ1;
314        try
315            ImageName_A=fullfile_uvmat(RootPath_A,SubDir_A,RootFile_A,FileExt_A,NomType_A,i1_series_Civ1(ifield),[],j1_series_Civ1(ifield));
316            [par_civ1.ImageA,VideoObject_A] = read_image(ImageName_A,FileType_A,VideoObject_A,FrameIndex_A_Civ1(ifield));
317            ImageName_B=fullfile_uvmat(RootPath_B,SubDir_B,RootFile_B,FileExt_B,NomType_B,i2_series_Civ1(ifield),[],j2_series_Civ1(ifield));
318            [par_civ1.ImageB,VideoObject_B] = read_image(ImageName_B,FileType_B,VideoObject_B,FrameIndex_B_Civ1(ifield));
319        catch ME
320            if ~isempty(ME.message)
321                disp_uvmat('ERROR', ['error reading input image: ' ME.message],checkrun)
322                return
323            end
324        end
325        par_civ1.ImageWidth=FileInfo_A.Width;
326        par_civ1.ImageHeight=FileInfo_A.Height;
327        list_param=(fieldnames(Param.ActionInput.Civ1))';
328        Civ1_param=regexprep(list_param,'^.+','Civ1_$0');% insert 'Civ1_' before  each string in list_param
329        Civ1_param=[{'Civ1_ImageA','Civ1_ImageB','Civ1_Time','Civ1_Dt'} Civ1_param]; %insert the names of the two input images
330        %indicate the values of all the global attributes in the output data
331        Data.Civ1_ImageA=ImageName_A;
332        Data.Civ1_ImageB=ImageName_B;
333        i1=i1_series_Civ1(ifield);
334        i2=i1;
335        if ~isempty(i2_series_Civ1)
336            i2=i2_series_Civ1(ifield);
337        end
338        j1=1;
339        if ~isempty(j1_series_Civ1)
340            j1=j1_series_Civ1(ifield);
341        end
342        j2=j1;
343        if ~isempty(j2_series_Civ1)
344            j2=j2_series_Civ1(ifield);
345        end
346        Data.Civ1_Time=(time(i2+1,j2+1)+time(i1+1,j1+1))/2;
347        Data.Civ1_Dt=time(i2+1,j2+1)-time(i1+1,j1+1);
348        for ilist=1:length(list_param)
349            Data.(Civ1_param{4+ilist})=Param.ActionInput.Civ1.(list_param{ilist});
350        end
351        Data.ListGlobalAttribute=[Data.ListGlobalAttribute Civ1_param];
352        Data.CivStage=1;
353       
354        % set the list of variables
355        Data.ListVarName={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_F','Civ1_C'};%  cell array containing the names of the fields to record
356        Data.VarDimName={'nb_vec_1','nb_vec_1','nb_vec_1','nb_vec_1','nb_vec_1','nb_vec_1'};
357        Data.VarAttribute{1}.Role='coord_x';
358        Data.VarAttribute{2}.Role='coord_y';
359        Data.VarAttribute{3}.Role='vector_x';
360        Data.VarAttribute{4}.Role='vector_y';
361        Data.VarAttribute{5}.Role='warnflag';
362       
363        if strcmp(Param.ActionInput.ListCompareMode, 'PIV volume')
364            Data.ListVarName=[Data.ListVarName 'Civ1_Z'];
365            Data.Civ1_X=[];Data.Civ1_Y=[];Data.Civ1_Z=[];
366            Data.Civ1_U=[];Data.Civ1_V=[];Data.Civ1_C=[];Data.Civ1_F=[];
367            for ivol=1:NbSlice
368                % caluclate velocity data (y and v in indices, reverse to y component)
369                [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ1);
370                if ~isempty(errormsg)
371                     disp_uvmat('ERROR',errormsg,checkrun)
372                    return
373                end
374                Data.Civ1_X=[Data.Civ1_X reshape(xtable,[],1)];
375                Data.Civ1_Y=[Data.Civ1_Y reshape(Param.Civ1.ImageHeight-ytable+1,[],1)];
376                Data.Civ1_Z=[Data.Civ1_Z ivol*ones(numel(xtable),1)];% z=image index in image coordinates
377                Data.Civ1_U=[Data.Civ1_U reshape(utable,[],1)];
378                Data.Civ1_V=[Data.Civ1_V reshape(-vtable,[],1)];
379                Data.Civ1_C=[Data.Civ1_C reshape(ctable,[],1)];
380                Data.Civ1_F=[Data.Civ1_C reshape(F,[],1)];
381            end
382        else %usual PIV
383            % caluclate velocity data (y and v in indices, reverse to y component)
384            [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ1);
385            if ~isempty(errormsg)
386                disp_uvmat('ERROR',errormsg,checkrun)
387                return
388            end
389            Data.Civ1_X=reshape(xtable,[],1);
390            Data.Civ1_Y=reshape(par_civ1.ImageHeight-ytable+1,[],1);
391            Data.Civ1_U=reshape(utable,[],1);
392            Data.Civ1_V=reshape(-vtable,[],1);
393            Data.Civ1_C=reshape(ctable,[],1);
394            Data.Civ1_F=reshape(F,[],1);
395        end
396    else% we use existing Civ1 data
397        if exist('ncfile','var')
398            CivFile=ncfile;
399        elseif isfield(Param.Patch1,'CivFile')
400            CivFile=Param.Patch1.CivFile;
401        end
402        Data=nc2struct(CivFile,'ListGlobalAttribute','absolut_time_T0'); %look for the constant 'absolut_time_T0' to detect old civx data format
403        if isfield(Data,'Txt')
404            errormsg=Data.Txt;
405            disp_uvmat('ERROR',errormsg,checkrun)
406            return
407        end
408        if ~isempty(Data.absolut_time_T0')%read civx file
409            check_civx=1;% test for old civx data format
410            [Data,vardetect,ichoice]=nc2struct(CivFile);%read the variables in the netcdf file
411        else
412            Data=nc2struct(CivFile);%read civ1 and fix1 data in the existing netcdf file
413        end
414    end
415   
416    %% Fix1
417    if isfield (Param.ActionInput,'Fix1')
418        ListFixParam=fieldnames(Param.ActionInput.Fix1);
419        for ilist=1:length(ListFixParam)
420            ParamName=ListFixParam{ilist};
421            ListName=['Fix1_' ParamName];
422            eval(['Data.ListGlobalAttribute=[Data.ListGlobalAttribute ''' ParamName '''];'])
423            eval(['Data.' ListName '=Param.ActionInput.Fix1.' ParamName ';'])
424        end
425        if check_civx
426            if ~isfield(Data,'fix')
427                Data.ListGlobalAttribute=[Data.ListGlobalAttribute 'fix'];
428                Data.fix=1;
429                Data.ListVarName=[Data.ListVarName {'vec_FixFlag'}];
430                Data.VarDimName=[Data.VarDimName {'nb_vectors'}];
431            end
432            Data.vec_FixFlag=fix(Param.ActionInput.Fix1,Data.vec_F,Data.vec_C,Data.vec_U,Data.vec_V,Data.vec_X,Data.vec_Y);
433        else
434            Data.ListVarName=[Data.ListVarName {'Civ1_FF'}];
435            Data.VarDimName=[Data.VarDimName {'nb_vec_1'}];
436            nbvar=length(Data.ListVarName);
437            Data.VarAttribute{nbvar}.Role='errorflag';
438            Data.Civ1_FF=fix(Param.ActionInput.Fix1,Data.Civ1_F,Data.Civ1_C,Data.Civ1_U,Data.Civ1_V);
439            Data.CivStage=2;
440        end
441    end
442    %% Patch1
443    if isfield (Param.ActionInput,'Patch1')
444        if check_civx
445            errormsg='Civ Matlab input needed for patch';
446            disp_uvmat('ERROR',errormsg,checkrun)
447            return
448        end
449       
450        Data.ListGlobalAttribute=[Data.ListGlobalAttribute {'Patch1_Rho','Patch1_Threshold','Patch1_SubDomain'}];
451        Data.Patch1_FieldSmooth=Param.ActionInput.Patch1.FieldSmooth;
452        Data.Patch1_MaxDiff=Param.ActionInput.Patch1.MaxDiff;
453        Data.Patch1_SubDomainSize=Param.ActionInput.Patch1.SubDomainSize;
454        nbvar=length(Data.ListVarName);
455        Data.ListVarName=[Data.ListVarName {'Civ1_U_smooth','Civ1_V_smooth','Civ1_SubRange','Civ1_NbCentres','Civ1_Coord_tps','Civ1_U_tps','Civ1_V_tps'}];
456        Data.VarDimName=[Data.VarDimName {'nb_vec_1','nb_vec_1',{'nb_coord','nb_bounds','nb_subdomain_1'},'nb_subdomain_1',...
457            {'nb_tps_1','nb_coord','nb_subdomain_1'},{'nb_tps_1','nb_subdomain_1'},{'nb_tps_1','nb_subdomain_1'}}];
458        Data.VarAttribute{nbvar+1}.Role='vector_x';
459        Data.VarAttribute{nbvar+2}.Role='vector_y';
460        Data.VarAttribute{nbvar+5}.Role='coord_tps';
461        Data.VarAttribute{nbvar+6}.Role='vector_x';
462        Data.VarAttribute{nbvar+7}.Role='vector_y';
463        Data.Civ1_U_smooth=zeros(size(Data.Civ1_X));
464        Data.Civ1_V_smooth=zeros(size(Data.Civ1_X));
465        if isfield(Data,'Civ1_FF')
466            ind_good=find(Data.Civ1_FF==0);
467        else
468            ind_good=1:numel(Data.Civ1_X);
469        end
470        [Data.Civ1_SubRange,Data.Civ1_NbCentres,Data.Civ1_Coord_tps,Data.Civ1_U_tps,Data.Civ1_V_tps,tild,Ures, Vres,tild,FFres]=...
471            filter_tps([Data.Civ1_X(ind_good) Data.Civ1_Y(ind_good)],Data.Civ1_U(ind_good),Data.Civ1_V(ind_good),[],Data.Patch1_SubDomainSize,Data.Patch1_FieldSmooth,Data.Patch1_MaxDiff);
472        Data.Civ1_U_smooth(ind_good)=Ures;
473        Data.Civ1_V_smooth(ind_good)=Vres;
474        Data.Civ1_FF(ind_good)=FFres;
475        Data.CivStage=3;
476    end
477   
478    %% Civ2
479    if isfield (Param.ActionInput,'Civ2')
480        par_civ2=Param.ActionInput.Civ2;
481        par_civ2.ImageA=[];
482        par_civ2.ImageB=[];
483        %         if ~isfield(Param.Civ1,'ImageA')
484        ImageName_A_Civ2=fullfile_uvmat(RootPath_A,SubDir_A,RootFile_A,FileExt_A,NomType_A,i1_series_Civ2(ifield),[],j1_series_Civ2(ifield));
485
486        if strcmp(ImageName_A_Civ2,ImageName_A) && isequal(FrameIndex_A_Civ1(ifield),FrameIndex_A_Civ2(ifield))
487            par_civ2.ImageA=par_civ1.ImageA;
488        else
489            [par_civ2.ImageA,VideoObject_A] = read_image(ImageName_A,FileType_A,VideoObject_A,FrameIndex_A_Civ2(ifield));
490        end
491        ImageName_B_Civ2=fullfile_uvmat(RootPath_B,SubDir_B,RootFile_B,FileExt_B,NomType_B,i2_series_Civ2(ifield),[],j2_series_Civ2(ifield));
492        if strcmp(ImageName_B_Civ2,ImageName_B) && isequal(FrameIndex_B_Civ1(ifield),FrameIndex_B_Civ2)
493            par_civ2.ImageB=par_civ1.ImageB;
494        else
495            [par_civ2.ImageB,VideoObject_B] = read_image(ImageName_B,FileType_B,VideoObject_B,FrameIndex_B_Civ2(ifield));
496        end     
497       
498        ncfile=fullfile_uvmat(RootPath_A,OutputDir,RootFile_A,'.nc',NomTypeNc,i1_series_Civ2(ifield),i2_series_Civ2(ifield),...
499            j1_series_Civ2(ifield),j2_series_Civ2(ifield));
500        par_civ2.ImageWidth=FileInfo_A.Width;
501        par_civ2.ImageHeight=FileInfo_A.Height;
502       
503        if isfield(par_civ2,'Grid')% grid points set as input file
504            if ischar(par_civ2.Grid)%read the grid file if the input is a file name
505                par_civ2.Grid=dlmread(par_civ2.Grid);
506                par_civ2.Grid(1,:)=[];%the first line must be removed (heading in the grid file)
507            end
508        else% automatic grid
509            minix=floor(par_civ2.Dx/2)-0.5;
510            maxix=minix+par_civ2.Dx*floor((par_civ2.ImageWidth-1)/par_civ2.Dx);
511            miniy=floor(par_civ2.Dy/2)-0.5;
512            maxiy=minix+par_civ2.Dy*floor((par_civ2.ImageHeight-1)/par_civ2.Dy);
513            [GridX,GridY]=meshgrid(minix:par_civ2.Dx:maxix,miniy:par_civ2.Dy:maxiy);
514            par_civ2.Grid(:,1)=reshape(GridX,[],1);
515            par_civ2.Grid(:,2)=reshape(GridY,[],1);
516        end
517        Shiftx=zeros(size(par_civ2.Grid,1),1);% shift expected from civ1 data
518        Shifty=zeros(size(par_civ2.Grid,1),1);
519        nbval=zeros(size(par_civ2.Grid,1),1);
520        if par_civ2.CheckDeformation
521            DUDX=zeros(size(par_civ2.Grid,1),1);
522            DUDY=zeros(size(par_civ2.Grid,1),1);
523            DVDX=zeros(size(par_civ2.Grid,1),1);
524            DVDY=zeros(size(par_civ2.Grid,1),1);
525        end
526        NbSubDomain=size(Data.Civ1_SubRange,3);
527        % get the guess from patch1
528        for isub=1:NbSubDomain
529            nbvec_sub=Data.Civ1_NbCentres(isub);
530            ind_sel=find(GridX>=Data.Civ1_SubRange(1,1,isub) & GridX<=Data.Civ1_SubRange(1,2,isub) & GridY>=Data.Civ1_SubRange(2,1,isub) & GridY<=Data.Civ1_SubRange(2,2,isub));
531            epoints = [GridX(ind_sel) GridY(ind_sel)];% coordinates of interpolation sites
532            ctrs=Data.Civ1_Coord_tps(1:nbvec_sub,:,isub) ;%(=initial points) ctrs
533            nbval(ind_sel)=nbval(ind_sel)+1;% records the number of values for eacn interpolation point (in case of subdomain overlap)
534            EM = tps_eval(epoints,ctrs);
535            Shiftx(ind_sel)=Shiftx(ind_sel)+EM*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
536            Shifty(ind_sel)=Shifty(ind_sel)+EM*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
537            if par_civ2.CheckDeformation
538                [EMDX,EMDY] = tps_eval_dxy(epoints,ctrs);%2D matrix of distances between extrapolation points epoints and spline centres (=site points) ctrs
539                DUDX(ind_sel)=DUDX(ind_sel)+EMDX*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
540                DUDY(ind_sel)=DUDY(ind_sel)+EMDY*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
541                DVDX(ind_sel)=DVDX(ind_sel)+EMDX*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
542                DVDY(ind_sel)=DVDY(ind_sel)+EMDY*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
543            end
544        end
545        mask='';
546        if par_civ2.CheckMask&&~isempty(par_civ2.Mask)&& ~strcmp(maskname,par_civ2.Mask)% mask exist, not already read in civ1
547            mask=imread(par_civ2.Mask);
548        end
549        ibx2=ceil(par_civ2.CorrBoxSize(1)/2);
550        iby2=ceil(par_civ2.CorrBoxSize(2)/2);
551        par_civ2.SearchBoxSize(1)=2*ibx2+9;% search ara +-4 pixels around the guess
552        par_civ2.SearchBoxSize(2)=2*iby2+9;
553        par_civ2.SearchBoxShift=[Shiftx(nbval>=1)./nbval(nbval>=1) Shifty(nbval>=1)./nbval(nbval>=1)];
554        par_civ2.Grid=[GridX(nbval>=1)-par_civ2.SearchBoxShift(:,1)/2 GridY(nbval>=1)-par_civ2.SearchBoxShift(:,2)/2];% grid taken at the extrapolated origin of the displacement vectors
555        if par_civ2.CheckDeformation
556            par_civ2.DUDX=DUDX./nbval;
557            par_civ2.DUDY=DUDY./nbval;
558            par_civ2.DVDX=DVDX./nbval;
559            par_civ2.DVDY=DVDY./nbval;
560        end
561        % caluclate velocity data (y and v in indices, reverse to y component)
562        [xtable ytable utable vtable ctable F] = civ (par_civ2);
563
564        list_param=(fieldnames(Param.ActionInput.Civ2))';
565        Civ2_param=regexprep(list_param,'^.+','Civ2_$0');% insert 'Civ2_' before  each string in list_param
566        Civ2_param=[{'Civ2_ImageA','Civ2_ImageB','Civ2_Time','Civ2_Dt'} Civ2_param]; %insert the names of the two input images
567        %indicate the values of all the global attributes in the output data
568        Data.Civ2_ImageA=ImageName_A;
569        Data.Civ2_ImageB=ImageName_B;
570        i1=i1_series_Civ2(ifield);
571        i2=i1;
572        if ~isempty(i2_series_Civ2)
573            i2=i2_series_Civ2(ifield);
574        end
575        j1=1;
576        if ~isempty(j1_series_Civ2)
577            j1=j1_series_Civ2(ifield);
578        end
579        j2=j1;
580        if ~isempty(j2_series_Civ1)
581            j2=j2_series_Civ2(ifield);
582        end
583        Data.Civ2_Time=(time(i2+1,j2+1)+time(i1+1,j1+1))/2;
584        Data.Civ2_Dt=time(i2+1,j2+1)-time(i1+1,j1+1);
585%         Data.Civ2_Time=1;
586%         Data.Civ2_Dt=1;
587        for ilist=1:length(list_param)
588            Data.(Civ2_param{4+ilist})=Param.ActionInput.Civ2.(list_param{ilist});
589        end
590        Data.ListGlobalAttribute=[Data.ListGlobalAttribute Civ2_param];
591       
592        nbvar=numel(Data.ListVarName);
593        Data.ListVarName=[Data.ListVarName {'Civ2_X','Civ2_Y','Civ2_U','Civ2_V','Civ2_F','Civ2_C'}];%  cell array containing the names of the fields to record
594        Data.VarDimName=[Data.VarDimName {'nb_vec_2','nb_vec_2','nb_vec_2','nb_vec_2','nb_vec_2','nb_vec_2'}];
595        Data.VarAttribute{nbvar+1}.Role='coord_x';
596        Data.VarAttribute{nbvar+2}.Role='coord_y';
597        Data.VarAttribute{nbvar+3}.Role='vector_x';
598        Data.VarAttribute{nbvar+4}.Role='vector_y';
599        Data.VarAttribute{nbvar+5}.Role='warnflag';
600        Data.Civ2_X=reshape(xtable,[],1);
601        Data.Civ2_Y=reshape(size(par_civ2.ImageA,1)-ytable+1,[],1);
602        Data.Civ2_U=reshape(utable,[],1);
603        Data.Civ2_V=reshape(-vtable,[],1);
604        Data.Civ2_C=reshape(ctable,[],1);
605        Data.Civ2_F=reshape(F,[],1);
606        Data.CivStage=Data.CivStage+1;
607    end
608   
609    %% Fix2
610    if isfield (Param.ActionInput,'Fix2')
611        ListFixParam=fieldnames(Param.ActionInput.Fix2);
612        for ilist=1:length(ListFixParam)
613            ParamName=ListFixParam{ilist};
614            ListName=['Fix2_' ParamName];
615            eval(['Data.ListGlobalAttribute=[Data.ListGlobalAttribute ''' ParamName '''];'])
616            eval(['Data.' ListName '=Param.ActionInput.Fix2.' ParamName ';'])
617        end
618        if check_civx
619            if ~isfield(Data,'fix2')
620                Data.ListGlobalAttribute=[Data.ListGlobalAttribute 'fix2'];
621                Data.fix2=1;
622                Data.ListVarName=[Data.ListVarName {'vec2_FixFlag'}];
623                Data.VarDimName=[Data.VarDimName {'nb_vectors2'}];
624            end
625            Data.vec_FixFlag=fix(Param.Fix2,Data.vec2_F,Data.vec2_C,Data.vec2_U,Data.vec2_V,Data.vec2_X,Data.vec2_Y);
626        else
627            Data.ListVarName=[Data.ListVarName {'Civ2_FF'}];
628            Data.VarDimName=[Data.VarDimName {'nb_vec_2'}];
629            nbvar=length(Data.ListVarName);
630            Data.VarAttribute{nbvar}.Role='errorflag';
631            Data.Civ2_FF=fix(Param.ActionInput.Fix2,Data.Civ2_F,Data.Civ2_C,Data.Civ2_U,Data.Civ2_V);
632            Data.CivStage=Data.CivStage+1;
633        end
634       
635    end
636   
637    %% Patch2
638    if isfield (Param.ActionInput,'Patch2')
639        Data.ListGlobalAttribute=[Data.ListGlobalAttribute {'Patch2_Rho','Patch2_Threshold','Patch2_SubDomain'}];
640        Data.Patch2_FieldSmooth=Param.ActionInput.Patch2.FieldSmooth;
641        Data.Patch2_MaxDiff=Param.ActionInput.Patch2.MaxDiff;
642        Data.Patch2_SubDomainSize=Param.ActionInput.Patch2.SubDomainSize;
643        nbvar=length(Data.ListVarName);
644        Data.ListVarName=[Data.ListVarName {'Civ2_U_smooth','Civ2_V_smooth','Civ2_SubRange','Civ2_NbCentres','Civ2_Coord_tps','Civ2_U_tps','Civ2_V_tps'}];
645        Data.VarDimName=[Data.VarDimName {'nb_vec_2','nb_vec_2',{'nb_coord','nb_bounds','nb_subdomain_2'},{'nb_subdomain_2'},...
646            {'nb_tps_2','nb_coord','nb_subdomain_2'},{'nb_tps_2','nb_subdomain_2'},{'nb_tps_2','nb_subdomain_2'}}];
647       
648        Data.VarAttribute{nbvar+1}.Role='vector_x';
649        Data.VarAttribute{nbvar+2}.Role='vector_y';
650        Data.VarAttribute{nbvar+5}.Role='coord_tps';
651        Data.VarAttribute{nbvar+6}.Role='vector_x';
652        Data.VarAttribute{nbvar+7}.Role='vector_y';
653        Data.Civ2_U_smooth=zeros(size(Data.Civ2_X));
654        Data.Civ2_V_smooth=zeros(size(Data.Civ2_X));
655        if isfield(Data,'Civ2_FF')
656            ind_good=find(Data.Civ2_FF==0);
657        else
658            ind_good=1:numel(Data.Civ2_X);
659        end
660        [Data.Civ2_SubRange,Data.Civ2_NbCentres,Data.Civ2_Coord_tps,Data.Civ2_U_tps,Data.Civ2_V_tps,tild,Ures, Vres,tild,FFres]=...
661            filter_tps([Data.Civ2_X(ind_good) Data.Civ2_Y(ind_good)],Data.Civ2_U(ind_good),Data.Civ2_V(ind_good),[],Data.Patch2_SubDomainSize,Data.Patch2_FieldSmooth,Data.Patch2_MaxDiff);
662        Data.Civ2_U_smooth(ind_good)=Ures;
663        Data.Civ2_V_smooth(ind_good)=Vres;
664        Data.Civ2_FF(ind_good)=FFres;
665        Data.CivStage=Data.CivStage+1;
666    end
667   
668    %% write result in a netcdf file if requested
669    if exist('ncfile','var')
670        errormsg=struct2nc(ncfile,Data);
671        if isempty(errormsg)
672            disp([ncfile ' written'])
673        else
674            disp(errormsg)
675        end
676    end
677end
678
679% 'civ': function piv.m adapted from PIVlab http://pivlab.blogspot.com/
680%--------------------------------------------------------------------------
681% function [xtable ytable utable vtable typevector] = civ (image1,image2,ibx,iby step, subpixfinder, mask, roi)
682%
683% OUTPUT:
684% xtable: set of x coordinates
685% ytable: set of y coordiantes
686% utable: set of u displacements (along x)
687% vtable: set of v displacements (along y)
688% ctable: max image correlation for each vector
689% typevector: set of flags, =1 for good, =0 for NaN vectors
690%
691%INPUT:
692% par_civ: structure of input parameters, with fields:
693%  .CorrBoxSize
694%  .SearchBoxSize
695%  .SearchBoxShift
696%  .ImageHeight
697%  .ImageWidth
698%  .Dx, Dy
699%  .Grid
700%  .Mask
701%  .MinIma
702%  .MaxIma
703%  .image1:first image (matrix)
704% image2: second image (matrix)
705% ibx2,iby2: half size of the correlation box along x and y, in px (size=(2*iby2+1,2*ibx2+1)
706% isx2,isy2: half size of the search box along x and y, in px (size=(2*isy2+1,2*isx2+1)
707% shiftx, shifty: shift of the search box (in pixel index, yshift reversed)
708% step: mesh of the measurement points (in px)
709% subpixfinder=1 or 2 controls the curve fitting of the image correlation
710% mask: =[] for no mask
711% roi: 4 element vector defining a region of interest: x position, y position, width, height, (in image indices), for the whole image, roi=[];
712function [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ)
713%this funtion performs the DCC PIV analysis. Recent window-deformation
714%methods perform better and will maybe be implemented in the future.
715
716%% prepare measurement grid
717if isfield(par_civ,'Grid')% grid points set as input
718    if ischar(par_civ.Grid)%read the drid file if the input is a file name
719        par_civ.Grid=dlmread(par_civ.Grid);
720        par_civ.Grid(1,:)=[];%the first line must be removed (heading in the grid file)
721    end
722else% automatic grid
723    minix=floor(par_civ.Dx/2)-0.5;
724    maxix=minix+par_civ.Dx*floor((par_civ.ImageWidth-1)/par_civ.Dx);
725    miniy=floor(par_civ.Dy/2)-0.5;
726    maxiy=minix+par_civ.Dy*floor((par_civ.ImageHeight-1)/par_civ.Dy);
727    [GridX,GridY]=meshgrid(minix:par_civ.Dx:maxix,miniy:par_civ.Dy:maxiy);
728    par_civ.Grid(:,1)=reshape(GridX,[],1);
729    par_civ.Grid(:,2)=reshape(GridY,[],1);
730end
731nbvec=size(par_civ.Grid,1);
732
733%% prepare correlation and search boxes
734ibx2=ceil(par_civ.CorrBoxSize(1)/2);
735iby2=ceil(par_civ.CorrBoxSize(2)/2);
736isx2=ceil(par_civ.SearchBoxSize(1)/2);
737isy2=ceil(par_civ.SearchBoxSize(2)/2);
738shiftx=round(par_civ.SearchBoxShift(:,1));
739shifty=-round(par_civ.SearchBoxShift(:,2));% sign minus because image j index increases when y decreases
740if numel(shiftx)==1% case of a unique shift for the whole field( civ1)
741    shiftx=shiftx*ones(nbvec,1);
742    shifty=shifty*ones(nbvec,1);
743end
744
745%% Default output
746xtable=par_civ.Grid(:,1);
747ytable=par_civ.Grid(:,2);
748utable=zeros(nbvec,1);
749vtable=zeros(nbvec,1);
750ctable=zeros(nbvec,1);
751F=zeros(nbvec,1);
752result_conv=[];
753errormsg='';
754
755%% prepare mask
756if isfield(par_civ,'Mask') && ~isempty(par_civ.Mask)
757    if strcmp(par_civ.Mask,'all')
758        return    % get the grid only, no civ calculation
759    elseif ischar(par_civ.Mask)
760        par_civ.Mask=imread(par_civ.Mask);
761    end
762end
763check_MinIma=isfield(par_civ,'MinIma');% test for image luminosity threshold
764check_MaxIma=isfield(par_civ,'MaxIma') && ~isempty(par_civ.MaxIma);
765
766% %% prepare images
767% if isfield(par_civ,'reverse_pair')
768%     if par_civ.reverse_pair
769%         if ischar(par_civ.ImageB)
770%             temp=par_civ.ImageA;
771%             par_civ.ImageA=imread(par_civ.ImageB);
772%         end
773%         if ischar(temp)
774%             par_civ.ImageB=imread(temp);
775%         end
776%     end
777% else
778%     if ischar(par_civ.ImageA)
779%         par_civ.ImageA=imread(par_civ.ImageA);
780%     end
781%     if ischar(par_civ.ImageB)
782%         par_civ.ImageB=imread(par_civ.ImageB);
783%     end
784% end
785par_civ.ImageA=sum(double(par_civ.ImageA),3);%sum over rgb component for color images
786par_civ.ImageB=sum(double(par_civ.ImageB),3);
787[npy_ima npx_ima]=size(par_civ.ImageA);
788if ~isequal(size(par_civ.ImageB),[npy_ima npx_ima])
789    errormsg='image pair with unequal size';
790    return
791end
792
793%% Apply mask
794    % Convention for mask IDEAS TO IMPLEMENT ?
795    % mask >200 : velocity calculated
796    %  200 >=mask>150;velocity not calculated, interpolation allowed (bad spots)
797    % 150>=mask >100: velocity not calculated, nor interpolated
798    %  100>=mask> 20: velocity not calculated, impermeable (no flux through mask boundaries)
799    %  20>=mask: velocity=0
800checkmask=0;
801MinA=min(min(par_civ.ImageA));
802MinB=min(min(par_civ.ImageB));
803if isfield(par_civ,'Mask') && ~isempty(par_civ.Mask)
804   checkmask=1;
805   if ~isequal(size(par_civ.Mask),[npy_ima npx_ima])
806        errormsg='mask must be an image with the same size as the images';
807        return
808   end
809  %  check_noflux=(par_civ.Mask<100) ;%TODO: to implement
810    check_undefined=(par_civ.Mask<200 & par_civ.Mask>=20 );
811    par_civ.ImageA(check_undefined)=MinA;% put image A to zero (i.e. the min image value) in the undefined  area
812    par_civ.ImageB(check_undefined)=MinB;% put image B to zero (i.e. the min image value) in the undefined  area
813end
814
815%% compute image correlations: MAINLOOP on velocity vectors
816corrmax=0;
817sum_square=1;% default
818mesh=1;% default
819CheckDecimal=isfield(par_civ,'CheckDecimal')&& par_civ.CheckDecimal==1;
820if CheckDecimal
821    mesh=0.2;%mesh in pixels for subpixel image interpolation
822    CheckDeformation=isfield(par_civ,'CheckDeformation')&& par_civ.CheckDeformation==1;
823end
824% vector=[0 0];%default
825for ivec=1:nbvec
826    iref=round(par_civ.Grid(ivec,1)+0.5);% xindex on the image A for the middle of the correlation box
827    jref=round(par_civ.ImageHeight-par_civ.Grid(ivec,2)+0.5);% yindex on the image B for the middle of the correlation box
828    %if ~(checkmask && par_civ.Mask(jref,iref)<=20) %velocity not set to zero by the black mask
829    %         if jref-iby2<1 || jref+iby2>par_civ.ImageHeight|| iref-ibx2<1 || iref+ibx2>par_civ.ImageWidth||...
830    %               jref+shifty(ivec)-isy2<1||jref+shifty(ivec)+isy2>par_civ.ImageHeight|| iref+shiftx(ivec)-isx2<1 || iref+shiftx(ivec)+isx2>par_civ.ImageWidth  % we are outside the image
831    %             F(ivec)=3;
832    %         else
833    F(ivec)=0;
834    subrange1_x=iref-ibx2:iref+ibx2;% x indices defining the first subimage
835    subrange1_y=jref-iby2:jref+iby2;% y indices defining the first subimage
836    subrange2_x=iref+shiftx(ivec)-isx2:iref+shiftx(ivec)+isx2;%x indices defining the second subimage
837    subrange2_y=jref+shifty(ivec)-isy2:jref+shifty(ivec)+isy2;%y indices defining the second subimage
838    image1_crop=MinA*ones(numel(subrange1_y),numel(subrange1_x));% default value=min of image A
839    image2_crop=MinA*ones(numel(subrange2_y),numel(subrange2_x));% default value=min of image A
840    check1_x=subrange1_x>=1 & subrange1_x<=par_civ.ImageWidth;% check which points in the subimage 1 are contained in the initial image 1
841    check1_y=subrange1_y>=1 & subrange1_y<=par_civ.ImageHeight;
842    check2_x=subrange2_x>=1 & subrange2_x<=par_civ.ImageWidth;% check which points in the subimage 2 are contained in the initial image 2
843    check2_y=subrange2_y>=1 & subrange2_y<=par_civ.ImageHeight;
844   
845    image1_crop(check1_y,check1_x)=par_civ.ImageA(subrange1_y(check1_y),subrange1_x(check1_x));%extract a subimage (correlation box) from image A
846    image2_crop(check2_y,check2_x)=par_civ.ImageB(subrange2_y(check2_y),subrange2_x(check2_x));%extract a larger subimage (search box) from image B
847    image1_mean=mean(mean(image1_crop));
848    image2_mean=mean(mean(image2_crop));
849    %threshold on image minimum
850    if check_MinIma && (image1_mean < par_civ.MinIma || image2_mean < par_civ.MinIma)
851        F(ivec)=3;
852    end
853    %threshold on image maximum
854    if check_MaxIma && (image1_mean > par_civ.MaxIma || image2_mean > par_civ.MaxIma)
855        F(ivec)=3;
856    end
857    %         end
858    if F(ivec)~=3
859        image1_crop=image1_crop-image1_mean;%substract the mean
860        image2_crop=image2_crop-image2_mean;
861        if CheckDecimal
862            xi=(1:mesh:size(image1_crop,2));
863            yi=(1:mesh:size(image1_crop,1))';
864            if CheckDeformation
865                [XI,YI]=meshgrid(xi-ceil(size(image1_crop,2)/2),yi-ceil(size(image1_crop,1)/2));
866                XIant=XI-par_civ.DUDX(ivec)*XI-par_civ.DUDY(ivec)*YI+ceil(size(image1_crop,2)/2);
867                YIant=YI-par_civ.DVDX(ivec)*XI-par_civ.DVDY(ivec)*YI+ceil(size(image1_crop,1)/2);
868                image1_crop=interp2(image1_crop,XIant,YIant);
869            else
870                image1_crop=interp2(image1_crop,xi,yi);
871            end
872            xi=(1:mesh:size(image2_crop,2));
873            yi=(1:mesh:size(image2_crop,1))';
874            image2_crop=interp2(image2_crop,xi,yi);
875        end
876        sum_square=sum(sum(image1_crop.*image1_crop));
877        %reference: Oliver Pust, PIV: Direct Cross-Correlation
878        result_conv= conv2(image2_crop,flipdim(flipdim(image1_crop,2),1),'valid');
879        corrmax= max(max(result_conv));
880        result_conv=(result_conv/corrmax)*255; %normalize, peak=always 255
881        %Find the correlation max, at 255
882        [y,x] = find(result_conv==255,1);
883        if ~isempty(y) && ~isempty(x)
884            try
885                if par_civ.CorrSmooth==1
886                    [vector,F(ivec)] = SUBPIXGAUSS (result_conv,x,y);
887                elseif par_civ.CorrSmooth==2
888                    [vector,F(ivec)] = SUBPIX2DGAUSS (result_conv,x,y);
889                end
890                utable(ivec)=vector(1)*mesh+shiftx(ivec);
891                vtable(ivec)=vector(2)*mesh+shifty(ivec);
892                xtable(ivec)=iref+utable(ivec)/2-0.5;% convec flow (velocity taken at the point middle from imgae 1 and 2)
893                ytable(ivec)=jref+vtable(ivec)/2-0.5;% and position of pixel 1=0.5 (convention for image coordinates=0 at the edge)
894                iref=round(xtable(ivec));% image index for the middle of the vector
895                jref=round(ytable(ivec));
896                if checkmask && par_civ.Mask(jref,iref)<200 && par_civ.Mask(jref,iref)>=100
897                    utable(ivec)=0;
898                    vtable(ivec)=0;
899                    F(ivec)=3;
900                end
901                ctable(ivec)=corrmax/sum_square;% correlation value
902            catch ME
903                F(ivec)=3;
904            end
905        else
906            F(ivec)=3;
907        end
908    end
909end
910result_conv=result_conv*corrmax/(255*sum_square);% keep the last correlation matrix for output
911
912%------------------------------------------------------------------------
913% --- Find the maximum of the correlation function after interpolation
914function [vector,F] = SUBPIXGAUSS (result_conv,x,y)
915%------------------------------------------------------------------------
916vector=[0 0]; %default
917F=0;
918[npy,npx]=size(result_conv);
919result_conv(result_conv<1)=1; %set to 1 correlation values smaller than 1 (to avoid divergence in the log)
920%the following 8 lines are copyright (c) 1998, Uri Shavit, Roi Gurka, Alex Liberzon, Technion ᅵ Israel Institute of Technology
921%http://urapiv.wordpress.com
922peaky = y;
923if y <= npy-1 && y >= 1
924    f0 = log(result_conv(y,x));
925    f1 = log(result_conv(y-1,x));
926    f2 = log(result_conv(y+1,x));
927    peaky = peaky+ (f1-f2)/(2*f1-4*f0+2*f2);
928else
929    F=-2; % warning flag for vector truncated by the limited search box
930end
931peakx=x;
932if x <= npx-1 && x >= 1
933    f0 = log(result_conv(y,x));
934    f1 = log(result_conv(y,x-1));
935    f2 = log(result_conv(y,x+1));
936    peakx = peakx+ (f1-f2)/(2*f1-4*f0+2*f2);
937else
938    F=-2; % warning flag for vector truncated by the limited search box
939end
940vector=[peakx-floor(npx/2)-1 peaky-floor(npy/2)-1];
941
942%------------------------------------------------------------------------
943% --- Find the maximum of the correlation function after interpolation
944function [vector,F] = SUBPIX2DGAUSS (result_conv,x,y)
945%------------------------------------------------------------------------
946vector=[0 0]; %default
947F=-2;
948peaky=y;
949peakx=x;
950result_conv(result_conv<1)=1; %set to 1 correlation values smaller than 1 (to avoid divergence in the log)
951[npy,npx]=size(result_conv);
952if (x <= npx-1) && (y <= npy-1) && (x >= 1) && (y >= 1)
953    F=0;
954    for i=-1:1
955        for j=-1:1
956            %following 15 lines based on
957            %H. Nobach ï¿œ M. Honkanen (2005)
958            %Two-dimensional Gaussian regression for sub-pixel displacement
959            %estimation in particle image velocimetry or particle position
960            %estimation in particle tracking velocimetry
961            %Experiments in Fluids (2005) 38: 511ï¿œ515
962            c10(j+2,i+2)=i*log(result_conv(y+j, x+i));
963            c01(j+2,i+2)=j*log(result_conv(y+j, x+i));
964            c11(j+2,i+2)=i*j*log(result_conv(y+j, x+i));
965            c20(j+2,i+2)=(3*i^2-2)*log(result_conv(y+j, x+i));
966            c02(j+2,i+2)=(3*j^2-2)*log(result_conv(y+j, x+i));
967        end
968    end
969    c10=(1/6)*sum(sum(c10));
970    c01=(1/6)*sum(sum(c01));
971    c11=(1/4)*sum(sum(c11));
972    c20=(1/6)*sum(sum(c20));
973    c02=(1/6)*sum(sum(c02));
974    deltax=(c11*c01-2*c10*c02)/(4*c20*c02-c11^2);
975    deltay=(c11*c10-2*c01*c20)/(4*c20*c02-c11^2);
976    if abs(deltax)<1
977        peakx=x+deltax;
978    end
979    if abs(deltay)<1
980        peaky=y+deltay;
981    end
982end
983vector=[peakx-floor(npx/2)-1 peaky-floor(npy/2)-1];
984
985%'RUN_FIX': function for fixing velocity fields:
986%-----------------------------------------------
987% RUN_FIX(filename,field,flagindex,thresh_vecC,thresh_vel,iter,flag_mask,maskname,fileref,fieldref)
988%
989%filename: name of the netcdf file (used as input and output)
990%field: structure specifying the names of the fields to fix (depending on civ1 or civ2)
991    %.vel_type='civ1' or 'civ2';
992    %.nb=name of the dimension common to the field to fix ('nb_vectors' for civ1);
993    %.fixflag=name of fix flag variable ('vec_FixFlag' for civ1)
994%flagindex: flag specifying which values of vec_f are removed:
995        % if flagindex(1)=1: vec_f=-2 vectors are removed
996        % if flagindex(2)=1: vec_f=3 vectors are removed
997        % if flagindex(3)=1: vec_f=2 vectors are removed (if iter=1) or vec_f=4 vectors are removed (if iter=2)
998%iter=1 for civ1 fields and iter=2 for civ2 fields
999%thresh_vecC: threshold in the image correlation vec_C
1000%flag_mask: =1 mask used to remove vectors (0 else)
1001%maskname: name of the mask image file for fix
1002%thresh_vel: threshold on velocity, or on the difference with the reference file fileref if exists
1003%inf_sup=1: remove values smaller than threshold thresh_vel, =2, larger than threshold
1004%fileref: .nc file name for a reference velocity (='': refrence 0 used)
1005%fieldref: 'civ1','filter1'...feld used in fileref
1006
1007function FF=fix(Param,F,C,U,V,X,Y)
1008FF=zeros(size(F));%default
1009
1010%criterium on warn flags
1011FlagName={'CheckFmin2','CheckF2','CheckF3','CheckF4'};
1012FlagVal=[-2 2 3 4];
1013for iflag=1:numel(FlagName)
1014    if isfield(Param,FlagName{iflag}) && Param.(FlagName{iflag})
1015        FF=(FF==1| F==FlagVal(iflag));
1016    end
1017end
1018%criterium on correlation values
1019if isfield (Param,'MinCorr')
1020    FF=FF==1 | C<Param.MinCorr;
1021end
1022if (isfield(Param,'MinVel')&&~isempty(Param.MinVel))||(isfield (Param,'MaxVel')&&~isempty(Param.MaxVel))
1023    Umod= U.*U+V.*V;
1024    if isfield (Param,'MinVel')&&~isempty(Param.MinVel)
1025        FF=FF==1 | Umod<(Param.MinVel*Param.MinVel);
1026    end
1027    if isfield (Param,'MaxVel')&&~isempty(Param.MaxVel)
1028        FF=FF==1 | Umod>(Param.MaxVel*Param.MaxVel);
1029    end
1030end
1031
1032
1033%------------------------------------------------------------------------
1034% --- determine the list of index pairs of processing file
1035function [i1_series,i2_series,j1_series,j2_series,check_bounds,NomTypeNc]=...
1036    find_pair_indices(str_civ,i_series,j_series,MinIndex_i,MaxIndex_i,MinIndex_j,MaxIndex_j)
1037%------------------------------------------------------------------------
1038i1_series=i_series;% set of first image indexes
1039i2_series=i_series;
1040j1_series=ones(size(i_series));% set of first image numbers
1041j2_series=ones(size(i_series));
1042r=regexp(str_civ,'^\D(?<ind>[i|j])=( -| )(?<num1>\d+)\|(?<num2>\d+)','names');
1043if ~isempty(r)
1044    mode=['D' r.ind];
1045    ind1=str2num(r.num1);
1046    ind2=str2num(r.num2);
1047else
1048    mode='j1-j2';
1049    r=regexp(str_civ,'^j= (?<num1>[a-z])-(?<num2>[a-z])','names');
1050    if ~isempty(r)
1051        NomTypeNc='_1ab';
1052    else
1053        r=regexp(str_civ,'^j= (?<num1>[A-Z])-(?<num2>[A-Z])','names');
1054        if ~isempty(r)
1055            NomTypeNc='_1AB';
1056        else
1057            r=regexp(str_civ,'^j= (?<num1>\d+)-(?<num2>\d+)','names');
1058            if ~isempty(r)
1059                NomTypeNc='_1_1-2';
1060            end           
1061        end
1062    end
1063    if isempty(r)
1064        display('wrong pair mode input option')
1065    else
1066    ind1=stra2num(r.num1);
1067    ind2=stra2num(r.num2);
1068    end
1069end
1070if strcmp (mode,'Di')
1071    i1_series=i_series-ind1;% set of first image numbers
1072    i2_series=i_series+ind2;
1073     check_bounds=i1_series<MinIndex_i | i2_series>MaxIndex_i;
1074    if isempty(j_series)
1075        NomTypeNc='_1-2';
1076    else
1077        j1_series=j_series;
1078        j2_series=j_series;
1079        NomTypeNc='_1-2_1';
1080    end
1081elseif strcmp (mode,'Dj')
1082    j1_series=j_series-ind1;
1083    j2_series=j_series+ind2;
1084    check_bounds=j1_series<MinIndex_j | j2_series>MaxIndex_j;
1085    NomTypeNc='_1_1-2';
1086else  %bursts
1087    i1_series=i_series(1,:);% do not sweep the j index
1088    i2_series=i_series(1,:);
1089    j1_series=ind1*ones(1,size(i_series,2));% j index is fixed by pair choice
1090    j2_series=ind2*ones(1,size(i_series,2));
1091    check_bounds=zeros(size(i1_series));% no limitations due to min-max indices
1092end
1093
1094
1095
1096
Note: See TracBrowser for help on using the repository browser.