source: trunk/src/civ_matlab.m @ 404

Last change on this file since 404 was 399, checked in by sommeria, 12 years ago

implementation of thin plate interpolation (proj on planes with mode 'filter'), rationalisation of variable formats in civ_matlab

File size: 31.8 KB
Line 
1%'civ_matlab': Matlab version of the PIV programs CivX
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_uvmat(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_matlab(Param,ncfile)
41errormsg='';
42Data.ListGlobalAttribute={'Conventions','Program','CivStage'};
43Data.Conventions='uvmat/civdata';% states the conventions used for the description of field variables and attributes
44Data.Program='civ_matlab';
45Data.CivStage=0;%default
46ListVarCiv1={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_C','Civ1_F'}; %variables to read
47ListVarFix1={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_C','Civ1_F','Civ1_FF'};
48mask='';
49maskname='';%default
50check_civx=0;%default
51check_civ1=0;%default
52check_patch1=0;%default
53
54if ischar(Param)
55    Param=xml2struct(Param); %if Param is the name of an xml file, read this file as a Matlab structure
56end
57
58%% Civ1
59if isfield (Param,'Civ1')
60    check_civ1=1;% test for further use of civ1 results
61    % %% prepare images
62    par_civ1=Param.Civ1;
63    if isfield(par_civ1,'reverse_pair')
64        if par_civ1.reverse_pair
65            if ischar(par_civ1.ImageB)
66                temp=par_civ1.ImageA;
67                par_civ1.ImageA=imread(par_civ1.ImageB);
68            end
69            if ischar(temp)
70                par_civ1.ImageB=imread(temp);
71            end
72        end
73    else
74        if isfield(par_civ1,'ImageA')&&(ischar(par_civ1.ImageA)||strcmp(class(par_civ1.ImageA),'VideoReader')) % case with no image: only the PIV grid is calculated
75            [Field,ParamOut,errormsg] = read_field(par_civ1.ImageA,par_civ1.FileTypeA,[],par_civ1.i1);
76            par_civ1.ImageA=Field.A;%imread(par_civ1.ImageA);%[Field,ParamOut,errormsg] = read_field(ObjectName,FileType,ParamIn,num)
77        end
78        if isfield(par_civ1,'ImageB')&& (ischar(par_civ1.ImageB)||strcmp(class(par_civ1.ImageA),'VideoReader'))
79            [Field,ParamOut,errormsg] = read_field(par_civ1.ImageB,par_civ1.FileTypeB,[],par_civ1.i2);
80            par_civ1.ImageB=Field.A;%=imread(par_civ1.ImageB);
81        end
82    end
83   
84    % caluclate velocity data (y and v in indices, reverse to y component)
85    [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ1);
86   
87    % to try the reverse_pair method, uncomment below
88    %     [xtable1 ytable1 utable1 vtable1 ctable1 F1 result_conv1 errormsg1] = civ (Param.Civ1);
89    %     Param.Civ1.reverse_pair=1;
90    %     [xtable2 ytable2 utable2 vtable2 ctable2 F2 result_conv2 errormsg2] = civ (Param.Civ1);
91    %     xtable=[xtable1; xtable2];
92    %     ytable=[ytable1; ytable2];
93    %     utable=[utable1; -utable2];
94    %     vtable=[vtable1; -vtable2];
95    %     ctable=[ctable1; ctable2];
96    %     F=[F1; F2];
97    %     result_conv=[result_conv1; result_conv2];
98    %     errormsg=[errormsg1; errormsg2];
99    if ~isempty(errormsg)
100        return
101    end
102    list_param=(fieldnames(Param.Civ1))';
103    Civ1_param=list_param;%default
104    for ilist=1:length(list_param)
105        Civ1_param{ilist}=['Civ1_' list_param{ilist}];
106        Data.(['Civ1_' list_param{ilist}])=Param.Civ1.(list_param{ilist});
107    end
108    Data.ListGlobalAttribute=[Data.ListGlobalAttribute Civ1_param];% {'Civ1_Time','Civ1_Dt'}];
109    Data.ListVarName={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_F','Civ1_C'};%  cell array containing the names of the fields to record
110    Data.VarDimName={'nb_vec_1','nb_vec_1','nb_vec_1','nb_vec_1','nb_vec_1','nb_vec_1'};
111    Data.VarAttribute{1}.Role='coord_x';
112    Data.VarAttribute{2}.Role='coord_y';
113    Data.VarAttribute{3}.Role='vector_x';
114    Data.VarAttribute{4}.Role='vector_y';
115    Data.VarAttribute{5}.Role='warnflag';
116    Data.Civ1_X=reshape(xtable,[],1);
117    Data.Civ1_Y=reshape(Param.Civ1.ImageHeight-ytable+1,[],1);
118    Data.Civ1_U=reshape(utable,[],1);
119    Data.Civ1_V=reshape(-vtable,[],1);
120    Data.Civ1_C=reshape(ctable,[],1);
121    Data.Civ1_F=reshape(F,[],1);
122    Data.CivStage=1; 
123else
124    if exist('ncfile','var')
125        CivFile=ncfile;
126    elseif isfield(Param.Patch1,'CivFile')
127        CivFile=Param.Patch1.CivFile;
128    end
129    Data=nc2struct(CivFile,'ListGlobalAttribute','absolut_time_T0'); %look for the constant 'absolut_time_T0' to detect old civx data format
130    if isfield(Data,'Txt')
131        errormsg=Data.Txt;
132        return
133    end
134    if ~isempty(Data.absolut_time_T0')%read civx file
135        check_civx=1;% test for old civx data format
136        [Data,vardetect,ichoice]=nc2struct(CivFile);%read the variables in the netcdf file
137    else
138        Data=nc2struct(CivFile);%read civ1 and fix1 data in the existing netcdf file
139    end
140end
141
142%% Fix1
143if isfield (Param,'Fix1')
144    ListFixParam=fieldnames(Param.Fix1);
145    for ilist=1:length(ListFixParam)
146        ParamName=ListFixParam{ilist};
147        ListName=['Fix1_' ParamName];
148        eval(['Data.ListGlobalAttribute=[Data.ListGlobalAttribute ''' ParamName '''];'])
149        eval(['Data.' ListName '=Param.Fix1.' ParamName ';'])
150    end
151    if check_civx
152        if ~isfield(Data,'fix')
153            Data.ListGlobalAttribute=[Data.ListGlobalAttribute 'fix'];
154            Data.fix=1;
155            Data.ListVarName=[Data.ListVarName {'vec_FixFlag'}];
156            Data.VarDimName=[Data.VarDimName {'nb_vectors'}];
157        end
158        Data.vec_FixFlag=fix(Param.Fix1,Data.vec_F,Data.vec_C,Data.vec_U,Data.vec_V,Data.vec_X,Data.vec_Y);
159    else
160        Data.ListVarName=[Data.ListVarName {'Civ1_FF'}];
161        Data.VarDimName=[Data.VarDimName {'nb_vec_1'}];
162        nbvar=length(Data.ListVarName);
163        Data.VarAttribute{nbvar}.Role='errorflag';   
164        Data.Civ1_FF=fix(Param.Fix1,Data.Civ1_F,Data.Civ1_C,Data.Civ1_U,Data.Civ1_V);
165        Data.CivStage=2;   
166    end
167end   
168%% Patch1
169if isfield (Param,'Patch1')
170    if check_civx
171        errormsg='Civ Matlab input needed for patch';
172        return
173    end
174   
175    Data.ListGlobalAttribute=[Data.ListGlobalAttribute {'Patch1_Rho','Patch1_Threshold','Patch1_SubDomain'}];
176    Data.Patch1_Rho=Param.Patch1.SmoothingParam;
177    Data.Patch1_Threshold=Param.Patch1.MaxDiff;
178    Data.Patch1_SubDomain=Param.Patch1.SubdomainSize;
179    nbvar=length(Data.ListVarName);
180    Data.ListVarName=[Data.ListVarName {'Civ1_U_smooth','Civ1_V_smooth','Civ1_SubRange','Civ1_NbSites','Civ1_Coord_tps','Civ1_U_tps','Civ1_V_tps'}];
181        Data.VarDimName=[Data.VarDimName {'nb_vec_1','nb_vec_1',{'nb_coord','nb_bounds','nb_subdomain_1'},{'nb_subdomain_1'},...
182             {'nb_tps_1','nb_coord','nb_subdomain_1'},{'nb_tps_1','nb_subdomain_1'},{'nb_tps_1','nb_subdomain_1'}}];
183    Data.VarAttribute{nbvar+1}.Role='vector_x';
184    Data.VarAttribute{nbvar+2}.Role='vector_y';
185    Data.VarAttribute{nbvar+5}.Role='coord_tps';
186    Data.VarAttribute{nbvar+6}.Role='vector_x_tps';
187    Data.VarAttribute{nbvar+7}.Role='vector_y_tps';
188    Data.Civ1_U_smooth=zeros(size(Data.Civ1_X));
189    Data.Civ1_V_smooth=zeros(size(Data.Civ1_X));
190    if isfield(Data,'Civ1_FF')
191        ind_good=find(Data.Civ1_FF==0);
192    else
193        ind_good=1:numel(Data.Civ1_X);
194    end
195    [Data.Civ1_SubRange,Data.Civ1_NbSites,Data.Civ1_Coord_tps,Data.Civ1_U_tps,Data.Civ1_V_tps,tild,Ures, Vres,tild,FFres]=...
196            filter_tps([Data.Civ1_X(ind_good) Data.Civ1_Y(ind_good)],Data.Civ1_U(ind_good),Data.Civ1_V(ind_good),[],Data.Patch1_SubDomain,Data.Patch1_Rho,Data.Patch1_Threshold);
197      fill=zeros(3,2,size(Data.Civ1_SubRange,3)); %matrix of zeros to complement the matrix Data.Civ1_Coord_tps (conveninent for file storage)
198      Data.Civ1_Coord_tps=cat(1,Data.Civ1_Coord_tps,fill);
199      Data.Civ1_U_smooth(ind_good)=Ures;
200      Data.Civ1_V_smooth(ind_good)=Vres;
201      Data.Civ1_FF(ind_good)=FFres;
202      Data.CivStage=3;                             
203end   
204
205%% Civ2
206if isfield (Param,'Civ2')
207    par_civ2=Param.Civ2;
208    if ~isfield (Param,'Civ1') || ~strcmp(Param.Civ1.ImageA,par_civ2.ImageA)
209        %read first image if not already done for civ1
210        [Field,ParamOut,errormsg] = read_field(par_civ2.ImageA,par_civ2.FileTypeA,[],par_civ2.i1);
211        par_civ2.ImageA=Field.A;
212        %      par_civ2.ImageA=imread(Param.Civ2.ImageA);
213    else
214        par_civ2.ImageA=par_civ1.ImageA;
215    end
216    if ~isfield (Param,'Civ1') || ~strcmp(Param.Civ1.ImageB,par_civ2.ImageB)
217        %read first image if not already done for civ1
218        [Field,ParamOut,errormsg] = read_field(par_civ2.ImageB,par_civ2.FileTypeB,[],par_civ2.i2);
219        par_civ2.ImageB=Field.A;
220        %      par_civ2.ImageB=imread(Param.Civ2.ImageB);
221    else
222        par_civ2.ImageB=par_civ1.ImageB;
223    end
224    ibx2=ceil(par_civ2.Bx/2);
225    iby2=ceil(par_civ2.By/2);
226    isx2=ibx2+4;% search ara +-4 pixels around the guess
227    isy2=iby2+4;
228    % shift from par_civ2.filename_nc1
229    % shiftx=velocity interpolated at position
230    miniy=max(1+isy2,1+iby2);
231    minix=max(1+isx2,1+ibx2);
232    maxiy=min(size(par_civ2.ImageA,1)-isy2,size(par_civ2.ImageA,1)-iby2);
233    maxix=min(size(par_civ2.ImageA,2)-isx2,size(par_civ2.ImageA,2)-ibx2);
234    [GridX,GridY]=meshgrid(minix:par_civ2.Dx:maxix,miniy:par_civ2.Dy:maxiy);
235    GridX=reshape(GridX,[],1);
236    GridY=reshape(GridY,[],1);
237    Shiftx=zeros(size(GridX));% shift expected from civ1 data
238    Shifty=zeros(size(GridX));
239    nbval=zeros(size(GridX));
240    if par_civ2.CheckDeformation
241        DUDX=zeros(size(GridX));
242        DUDY=zeros(size(GridX));
243        DVDX=zeros(size(GridX));
244        DVDY=zeros(size(GridX));
245    end
246    NbSubDomain=size(Data.Civ1_SubRange,3);
247    % get the guess from patch1
248    for isub=1:NbSubDomain
249        nbvec_sub=Data.Civ1_NbSites(isub);
250        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));
251        epoints = [GridX(ind_sel) GridY(ind_sel)];% coordinates of interpolation sites
252        ctrs=Data.Civ1_Coord_tps(1:nbvec_sub,:,isub) ;%(=initial points) ctrs
253        nbval(ind_sel)=nbval(ind_sel)+1;% records the number of values for eacn interpolation point (in case of subdomain overlap)
254        EM = tps_eval(epoints,ctrs);
255        Shiftx(ind_sel)=Shiftx(ind_sel)+EM*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
256        Shifty(ind_sel)=Shifty(ind_sel)+EM*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
257        if par_civ2.CheckDeformation
258            [EMDX,EMDY] = tps_eval_dxy(epoints,ctrs);%2D matrix of distances between extrapolation points epoints and spline centres (=site points) ctrs
259            DUDX(ind_sel)=DUDX(ind_sel)+EMDX*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
260            DUDY(ind_sel)=DUDY(ind_sel)+EMDY*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
261            DVDX(ind_sel)=DVDX(ind_sel)+EMDX*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
262            DVDY(ind_sel)=DVDY(ind_sel)+EMDY*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
263        end
264    end
265    mask='';
266    if par_civ2.CheckMask&&~isempty(par_civ2.Mask)&& ~strcmp(maskname,par_civ2.Mask)% mask exist, not already read in civ1
267        mask=imread(par_civ2.Mask);
268    end
269    par_civ2.Searchx=2*isx2+1;
270    par_civ2.Searchy=2*isy2+1;
271    par_civ2.Shiftx=Shiftx(nbval>=1)./nbval(nbval>=1);
272    par_civ2.Shifty=Shifty(nbval>=1)./nbval(nbval>=1);
273    par_civ2.Grid=[GridX(nbval>=1)-par_civ2.Shiftx/2 GridY(nbval>=1)-par_civ2.Shifty/2];% grid taken at the extrapolated origin of the displacement vectors   
274    if par_civ2.CheckDeformation
275        par_civ2.DUDX=DUDX./nbval;
276        par_civ2.DUDY=DUDY./nbval;
277        par_civ2.DVDX=DVDX./nbval;
278        par_civ2.DVDY=DVDY./nbval;
279    end
280    % caluclate velocity data (y and v in indices, reverse to y component)
281    [xtable ytable utable vtable ctable F] = civ (par_civ2);
282%     diff_squared=(utable-par_civ2.Shiftx).*(utable-par_civ2.Shiftx)+(vtable+par_civ2.Shifty).*(vtable+par_civ2.Shifty);
283%     F(diff_squared>=4)=4; %flag vectors whose distance to the guess exceeds 2 pixels
284    list_param=(fieldnames(Param.Civ2))';
285    list_remove={'pxcmx','pxcmy','npx','npy','gridflag','maskflag','term_a','term_b','T0'};
286    for ilist=1:length(list_remove)
287        index=strcmp(list_remove{ilist},list_param);
288        if ~isempty(find(index,1))
289            list_param(index)=[];
290        end
291    end
292    for ilist=1:length(list_param)
293        Civ2_param{ilist}=['Civ2_' list_param{ilist}];
294        eval(['Data.Civ2_' list_param{ilist} '=Param.Civ2.' list_param{ilist} ';'])
295    end
296    if isfield(Data,'Civ2_gridname') && strcmp(Data.Civ1_gridname(1:6),'noFile')
297        Data.Civ1_gridname='';
298    end
299    if isfield(Data,'Civ2_maskname') && strcmp(Data.Civ1_maskname(1:6),'noFile')
300        Data.Civ2_maskname='';
301    end
302    Data.ListGlobalAttribute=[Data.ListGlobalAttribute Civ2_param {'Civ2_Time','Civ2_Dt'}];
303%     Data.Civ2_Time=par_civ2.Time;
304%     Data.Civ2_Dt=par_civ2.Dt;
305    nbvar=numel(Data.ListVarName);
306    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
307    Data.VarDimName=[Data.VarDimName {'nb_vec_2','nb_vec_2','nb_vec_2','nb_vec_2','nb_vec_2','nb_vec_2'}];
308    Data.VarAttribute{nbvar+1}.Role='coord_x';
309    Data.VarAttribute{nbvar+2}.Role='coord_y';
310    Data.VarAttribute{nbvar+3}.Role='vector_x';
311    Data.VarAttribute{nbvar+4}.Role='vector_y';
312    Data.VarAttribute{nbvar+5}.Role='warnflag';
313    Data.Civ2_X=reshape(xtable,[],1);
314    Data.Civ2_Y=reshape(size(par_civ2.ImageA,1)-ytable+1,[],1);
315    Data.Civ2_U=reshape(utable,[],1);
316    Data.Civ2_V=reshape(-vtable,[],1);
317    Data.Civ2_C=reshape(ctable,[],1);
318    Data.Civ2_F=reshape(F,[],1);
319    Data.CivStage=Data.CivStage+1;
320end
321
322%% Fix2
323if isfield (Param,'Fix2')
324    ListFixParam=fieldnames(Param.Fix2);
325    for ilist=1:length(ListFixParam)
326        ParamName=ListFixParam{ilist};
327        ListName=['Fix2_' ParamName];
328        eval(['Data.ListGlobalAttribute=[Data.ListGlobalAttribute ''' ParamName '''];'])
329        eval(['Data.' ListName '=Param.Fix2.' ParamName ';'])
330    end
331    if check_civx
332        if ~isfield(Data,'fix2')
333            Data.ListGlobalAttribute=[Data.ListGlobalAttribute 'fix2'];
334            Data.fix2=1;
335            Data.ListVarName=[Data.ListVarName {'vec2_FixFlag'}];
336            Data.VarDimName=[Data.VarDimName {'nb_vectors2'}];
337        end
338        Data.vec_FixFlag=fix(Param.Fix2,Data.vec2_F,Data.vec2_C,Data.vec2_U,Data.vec2_V,Data.vec2_X,Data.vec2_Y);
339    else
340        Data.ListVarName=[Data.ListVarName {'Civ2_FF'}];
341        Data.VarDimName=[Data.VarDimName {'nb_vec_2'}];
342        nbvar=length(Data.ListVarName);
343        Data.VarAttribute{nbvar}.Role='errorflag';   
344        Data.Civ2_FF=fix(Param.Fix2,Data.Civ2_F,Data.Civ2_C,Data.Civ2_U,Data.Civ2_V);
345        Data.CivStage=Data.CivStage+1;   
346    end
347   
348end   
349
350%% Patch2
351if isfield (Param,'Patch2')
352    Data.ListGlobalAttribute=[Data.ListGlobalAttribute {'Patch2_Rho','Patch2_Threshold','Patch2_SubDomain'}];
353    Data.Patch2_Rho=Param.Patch2.SmoothingParam;
354    Data.Patch2_Threshold=Param.Patch2.MaxDiff;
355    Data.Patch2_SubDomain=Param.Patch2.SubdomainSize;
356    nbvar=length(Data.ListVarName);
357    Data.ListVarName=[Data.ListVarName {'Civ2_U_smooth','Civ2_V_smooth','Civ2_SubRange','Civ2_NbSites','Civ2_Coord_tps','Civ2_U_tps','Civ2_V_tps'}];
358    Data.VarDimName=[Data.VarDimName {'nb_vec_2','nb_vec_2',{'nb_coord','nb_bounds','nb_subdomain_2'},{'nb_subdomain_2'},...
359             {'nb_tps_2','nb_coord','nb_subdomain_2'},{'nb_tps_2','nb_subdomain_2'},{'nb_tps_2','nb_subdomain_2'}}];
360
361        Data.VarAttribute{nbvar+1}.Role='vector_x';
362    Data.VarAttribute{nbvar+2}.Role='vector_y';
363    Data.VarAttribute{nbvar+5}.Role='coord_tps';
364    Data.VarAttribute{nbvar+6}.Role='vector_x_tps';
365    Data.VarAttribute{nbvar+7}.Role='vector_y_tps';
366    Data.Civ2_U_smooth=zeros(size(Data.Civ2_X));
367    Data.Civ2_V_smooth=zeros(size(Data.Civ2_X));
368    if isfield(Data,'Civ2_FF')
369        ind_good=find(Data.Civ2_FF==0);
370    else
371        ind_good=1:numel(Data.Civ2_X);
372    end
373    [Data.Civ2_SubRange,Data.Civ2_NbSites,Data.Civ2_Coord_tps,Data.Civ2_U_tps,Data.Civ2_V_tps,tild,Ures, Vres,tild,FFres]=...
374         filter_tps([Data.Civ2_X(ind_good) Data.Civ2_Y(ind_good)],Data.Civ2_U(ind_good),Data.Civ2_V(ind_good),[],Data.Patch2_SubDomain,Data.Patch2_Rho,Data.Patch2_Threshold);
375           fill=zeros(3,2,size(Data.Civ2_SubRange,3)); %matrix of zeros to complement the matrix Data.Civ1_Coord_tps (conveninent for file storage)
376      Data.Civ2_Coord_tps=cat(1,Data.Civ2_Coord_tps,fill);
377    Data.Civ2_U_smooth(ind_good)=Ures;
378    Data.Civ2_V_smooth(ind_good)=Vres;
379    Data.Civ2_FF(ind_good)=FFres;
380    Data.CivStage=Data.CivStage+1;                             
381end 
382
383%% write result in a netcdf file if requested
384if exist('ncfile','var')
385    errormsg=struct2nc(ncfile,Data);
386end
387
388% 'civ': function piv.m adapted from PIVlab http://pivlab.blogspot.com/
389%--------------------------------------------------------------------------
390% function [xtable ytable utable vtable typevector] = civ (image1,image2,ibx,iby step, subpixfinder, mask, roi)
391%
392% OUTPUT:
393% xtable: set of x coordinates
394% ytable: set of y coordiantes
395% utable: set of u displacements (along x)
396% vtable: set of v displacements (along y)
397% ctable: max image correlation for each vector
398% typevector: set of flags, =1 for good, =0 for NaN vectors
399%
400%INPUT:
401% image1:first image (matrix)
402% image2: second image (matrix)
403% ibx2,iby2: half size of the correlation box along x and y, in px (size=(2*iby2+1,2*ibx2+1)
404% isx2,isy2: half size of the search box along x and y, in px (size=(2*isy2+1,2*isx2+1)
405% shiftx, shifty: shift of the search box (in pixel index, yshift reversed)
406% step: mesh of the measurement points (in px)
407% subpixfinder=1 or 2 controls the curve fitting of the image correlation
408% mask: =[] for no mask
409% roi: 4 element vector defining a region of interest: x position, y position, width, height, (in image indices), for the whole image, roi=[];
410function [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ)
411%this funtion performs the DCC PIV analysis. Recent window-deformation
412%methods perform better and will maybe be implemented in the future.
413
414%% prepare grid
415ibx2=ceil(par_civ.Bx/2);
416iby2=ceil(par_civ.By/2);
417isx2=ceil(par_civ.Searchx/2);
418isy2=ceil(par_civ.Searchy/2);
419shiftx=round(par_civ.Shiftx);
420shifty=-round(par_civ.Shifty);% sign minus because image j index increases when y decreases
421if isfield(par_civ,'Grid')
422    if ischar(par_civ.Grid)%read the drid file if the input is a file name
423        par_civ.Grid=dlmread(par_civ.Grid);
424        par_civ.Grid(1,:)=[];%the first line must be removed (heading in the grid file)
425    end
426else% automatic measurement grid
427    ibx2=ceil(par_civ.Bx/2);
428    iby2=ceil(par_civ.By/2);
429    isx2=ceil(par_civ.Searchx/2);
430    isy2=ceil(par_civ.Searchy/2);
431    miniy=max(1+isy2+shifty,1+iby2);
432    minix=max(1+isx2-shiftx,1+ibx2);
433    maxiy=min(par_civ.ImageHeight-isy2+shifty,par_civ.ImageHeight-iby2);
434    maxix=min(par_civ.ImageWidth-isx2-shiftx,par_civ.ImageWidth-ibx2);
435    [GridX,GridY]=meshgrid(minix:par_civ.Dx:maxix,miniy:par_civ.Dy:maxiy);
436    par_civ.Grid(:,1)=reshape(GridX,[],1);
437    par_civ.Grid(:,2)=reshape(GridY,[],1);
438end
439nbvec=size(par_civ.Grid,1);
440if numel(shiftx)==1
441    shiftx=shiftx*ones(nbvec,1);
442    shifty=shifty*ones(nbvec,1);
443end
444%% Default output
445xtable=par_civ.Grid(:,1);
446ytable=par_civ.Grid(:,2);
447utable=zeros(nbvec,1);
448vtable=zeros(nbvec,1);
449ctable=zeros(nbvec,1);
450F=zeros(nbvec,1);
451result_conv=[];
452errormsg='';
453
454%% prepare mask
455if isfield(par_civ,'Mask') && ~isempty(par_civ.Mask)
456    if strcmp(par_civ.Mask,'all')
457        return    % get the grid only, no civ calculation
458    elseif ischar(par_civ.Mask)
459        par_civ.Mask=imread(par_civ.Mask);
460    end
461end
462check_MinIma=isfield(par_civ,'MinIma');% test for image luminosity threshold
463check_MaxIma=isfield(par_civ,'MaxIma') && ~isempty(par_civ.MaxIma);
464
465% %% prepare images
466% if isfield(par_civ,'reverse_pair')
467%     if par_civ.reverse_pair
468%         if ischar(par_civ.ImageB)
469%             temp=par_civ.ImageA;
470%             par_civ.ImageA=imread(par_civ.ImageB);
471%         end
472%         if ischar(temp)
473%             par_civ.ImageB=imread(temp);
474%         end
475%     end
476% else
477%     if ischar(par_civ.ImageA)
478%         par_civ.ImageA=imread(par_civ.ImageA);
479%     end
480%     if ischar(par_civ.ImageB)
481%         par_civ.ImageB=imread(par_civ.ImageB);
482%     end
483% end
484par_civ.ImageA=sum(double(par_civ.ImageA),3);%sum over rgb component for color images
485par_civ.ImageB=sum(double(par_civ.ImageB),3);
486[npy_ima npx_ima]=size(par_civ.ImageA);
487if ~isequal(size(par_civ.ImageB),[npy_ima npx_ima])
488    errormsg='image pair with unequal size';
489    return
490end
491
492%% Apply mask
493    % Convention for mask
494    % mask >200 : velocity calculated
495    %  200 >=mask>150;velocity not calculated, interpolation allowed (bad spots)
496    % 150>=mask >100: velocity not calculated, nor interpolated
497    %  100>=mask> 20: velocity not calculated, impermeable (no flux through mask boundaries) TO IMPLEMENT
498    %  20>=mask: velocity=0
499checkmask=0;
500if isfield(par_civ,'Mask') && ~isempty(par_civ.Mask)
501   checkmask=1;
502   if ~isequal(size(par_civ.Mask),[npy_ima npx_ima])
503        errormsg='mask must be an image with the same size as the images';
504        return
505   end
506  %  check_noflux=(par_civ.Mask<100) ;%TODO: to implement
507    check_undefined=(par_civ.Mask<200 & par_civ.Mask>=100 );
508    par_civ.ImageA(check_undefined)=min(min(par_civ.ImageA));% put image A to zero (i.e. the min image value) in the undefined  area
509    par_civ.ImageB(check_undefined)=min(min(par_civ.ImageB));% put image B to zero (i.e. the min image value) in the undefined  area
510end
511
512%% compute image correlations: MAINLOOP on velocity vectors
513corrmax=0;
514sum_square=1;% default
515mesh=1;% default
516CheckDecimal=isfield(par_civ,'CheckDecimal')&& par_civ.CheckDecimal==1;
517if CheckDecimal
518    mesh=0.2;%mesh in pixels for subpixel image interpolation
519    CheckDeformation=isfield(par_civ,'CheckDeformation')&& par_civ.CheckDeformation==1;
520end
521% vector=[0 0];%default
522for ivec=1:nbvec
523    iref=round(par_civ.Grid(ivec,1)+0.5);% xindex on the image A for the middle of the correlation box
524    jref=round(par_civ.ImageHeight-par_civ.Grid(ivec,2)+0.5);% yindex on the image B for the middle of the correlation box
525    if ~(checkmask && par_civ.Mask(jref,iref)<=20) %velocity not set to zero by the black mask
526        if jref-iby2<1 || jref+iby2>par_civ.ImageHeight|| iref-ibx2<1 || iref+ibx2>par_civ.ImageWidth||...
527              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
528            F(ivec)=3;
529        else
530            image1_crop=par_civ.ImageA(jref-iby2:jref+iby2,iref-ibx2:iref+ibx2);%extract a subimage (correlation box) from image A
531            image2_crop=par_civ.ImageB(jref+shifty(ivec)-isy2:jref+shifty(ivec)+isy2,iref+shiftx(ivec)-isx2:iref+shiftx(ivec)+isx2);%extract a larger subimage (search box) from image B
532            image1_mean=mean(mean(image1_crop));
533            image2_mean=mean(mean(image2_crop));
534            %threshold on image minimum
535            if check_MinIma && (image1_mean < par_civ.MinIma || image2_mean < par_civ.MinIma)
536                F(ivec)=3;
537            end
538            %threshold on image maximum
539            if check_MaxIma && (image1_mean > par_civ.MaxIma || image2_mean > par_civ.MaxIma)
540                F(ivec)=3;
541            end
542        end     
543        if F(ivec)~=3
544            image1_crop=image1_crop-image1_mean;%substract the mean
545            image2_crop=image2_crop-image2_mean;
546            if CheckDecimal
547                xi=(1:mesh:size(image1_crop,2));
548                yi=(1:mesh:size(image1_crop,1))';
549                if CheckDeformation
550                    [XI,YI]=meshgrid(xi-ceil(size(image1_crop,2)/2),yi-ceil(size(image1_crop,1)/2));
551                    XIant=XI-par_civ.DUDX(ivec)*XI-par_civ.DUDY(ivec)*YI+ceil(size(image1_crop,2)/2);
552                    YIant=YI-par_civ.DVDX(ivec)*XI-par_civ.DVDY(ivec)*YI+ceil(size(image1_crop,1)/2);
553                    image1_crop=interp2(image1_crop,XIant,YIant);
554                else
555                    image1_crop=interp2(image1_crop,xi,yi);
556                end
557                xi=(1:mesh:size(image2_crop,2));
558                yi=(1:mesh:size(image2_crop,1))';
559                image2_crop=interp2(image2_crop,xi,yi);
560            end
561            sum_square=sum(sum(image1_crop.*image1_crop));
562            %reference: Oliver Pust, PIV: Direct Cross-Correlation
563            result_conv= conv2(image2_crop,flipdim(flipdim(image1_crop,2),1),'valid');
564            corrmax= max(max(result_conv));
565            result_conv=(result_conv/corrmax)*255; %normalize, peak=always 255
566            %Find the correlation max, at 255
567            [y,x] = find(result_conv==255,1);
568            if ~isempty(y) && ~isempty(x)
569                try
570                    if par_civ.Rho==1
571                        [vector,F(ivec)] = SUBPIXGAUSS (result_conv,x,y);
572                    elseif par_civ.Rho==2
573                        [vector,F(ivec)] = SUBPIX2DGAUSS (result_conv,x,y);
574                    end
575                    utable(ivec)=vector(1)*mesh+shiftx(ivec);
576                    vtable(ivec)=vector(2)*mesh+shifty(ivec);                 
577                    xtable(ivec)=iref+utable(ivec)/2-0.5;% convec flow (velocity taken at the point middle from imgae 1 and 2)
578                    ytable(ivec)=jref+vtable(ivec)/2-0.5;% and position of pixel 1=0.5 (convention for image coordinates=0 at the edge)
579                    iref=round(xtable(ivec));% image index for the middle of the vector
580                    jref=round(ytable(ivec));
581                    if checkmask && par_civ.Mask(jref,iref)<200 && par_civ.Mask(jref,iref)>=100
582                        utable(ivec)=0;
583                        vtable(ivec)=0;
584                        F(ivec)=3;
585                    end
586                    ctable(ivec)=corrmax/sum_square;% correlation value
587                catch ME
588                    F(ivec)=3;
589                end
590            else
591                F(ivec)=3;
592            end
593        end
594    end
595   
596    %Create the vector matrix x, y, u, v
597end
598result_conv=result_conv*corrmax/(255*sum_square);% keep the last correlation matrix for output
599
600%------------------------------------------------------------------------
601% --- Find the maximum of the correlation function after interpolation
602function [vector,F] = SUBPIXGAUSS (result_conv,x,y)
603%------------------------------------------------------------------------
604vector=[0 0]; %default
605F=0;
606[npy,npx]=size(result_conv);
607
608% if (x <= (size(result_conv,1)-1)) && (y <= (size(result_conv,1)-1)) && (x >= 1) && (y >= 1)
609    %the following 8 lines are copyright (c) 1998, Uri Shavit, Roi Gurka, Alex Liberzon, Technion ï¿œ Israel Institute of Technology
610    %http://urapiv.wordpress.com
611    peaky = y;
612    if y <= npy-1 && y >= 1
613        f0 = log(result_conv(y,x));
614        f1 = real(log(result_conv(y-1,x)));
615        f2 = real(log(result_conv(y+1,x)));
616        peaky = peaky+ (f1-f2)/(2*f1-4*f0+2*f2);
617    else
618        F=-2; % warning flag for vector truncated by the limited search box
619    end
620    peakx=x;
621    if x <= npx-1 && x >= 1
622        f0 = log(result_conv(y,x));
623        f1 = real(log(result_conv(y,x-1)));
624        f2 = real(log(result_conv(y,x+1)));
625        peakx = peakx+ (f1-f2)/(2*f1-4*f0+2*f2);
626    else
627        F=-2; % warning flag for vector truncated by the limited search box
628    end
629    vector=[peakx-floor(npx/2)-1 peaky-floor(npy/2)-1];
630
631%------------------------------------------------------------------------
632% --- Find the maximum of the correlation function after interpolation
633function [vector,F] = SUBPIX2DGAUSS (result_conv,x,y)
634%------------------------------------------------------------------------
635vector=[0 0]; %default
636F=-2;
637peaky=y;
638peakx=x;
639[npy,npx]=size(result_conv);
640if (x <= npx-1) && (y <= npy-1) && (x >= 1) && (y >= 1)
641    F=0;
642    for i=-1:1
643        for j=-1:1
644            %following 15 lines based on
645            %H. Nobach ï¿œ M. Honkanen (2005)
646            %Two-dimensional Gaussian regression for sub-pixel displacement
647            %estimation in particle image velocimetry or particle position
648            %estimation in particle tracking velocimetry
649            %Experiments in Fluids (2005) 38: 511ï¿œ515
650            c10(j+2,i+2)=i*log(result_conv(y+j, x+i));
651            c01(j+2,i+2)=j*log(result_conv(y+j, x+i));
652            c11(j+2,i+2)=i*j*log(result_conv(y+j, x+i));
653            c20(j+2,i+2)=(3*i^2-2)*log(result_conv(y+j, x+i));
654            c02(j+2,i+2)=(3*j^2-2)*log(result_conv(y+j, x+i));
655        end
656    end
657    c10=(1/6)*sum(sum(c10));
658    c01=(1/6)*sum(sum(c01));
659    c11=(1/4)*sum(sum(c11));
660    c20=(1/6)*sum(sum(c20));
661    c02=(1/6)*sum(sum(c02));
662    deltax=(c11*c01-2*c10*c02)/(4*c20*c02-c11^2);
663    deltay=(c11*c10-2*c01*c20)/(4*c20*c02-c11^2);
664    if abs(deltax)<1
665        peakx=x+deltax;
666    end
667    if abs(deltay)<1
668        peaky=y+deltay;
669    end
670end
671vector=[peakx-floor(npx/2)-1 peaky-floor(npy/2)-1];
672
673%'RUN_FIX': function for fixing velocity fields:
674%-----------------------------------------------
675% RUN_FIX(filename,field,flagindex,thresh_vecC,thresh_vel,iter,flag_mask,maskname,fileref,fieldref)
676%
677%filename: name of the netcdf file (used as input and output)
678%field: structure specifying the names of the fields to fix (depending on civ1 or civ2)
679    %.vel_type='civ1' or 'civ2';
680    %.nb=name of the dimension common to the field to fix ('nb_vectors' for civ1);
681    %.fixflag=name of fix flag variable ('vec_FixFlag' for civ1)
682%flagindex: flag specifying which values of vec_f are removed:
683        % if flagindex(1)=1: vec_f=-2 vectors are removed
684        % if flagindex(2)=1: vec_f=3 vectors are removed
685        % if flagindex(3)=1: vec_f=2 vectors are removed (if iter=1) or vec_f=4 vectors are removed (if iter=2)
686%iter=1 for civ1 fields and iter=2 for civ2 fields
687%thresh_vecC: threshold in the image correlation vec_C
688%flag_mask: =1 mask used to remove vectors (0 else)
689%maskname: name of the mask image file for fix
690%thresh_vel: threshold on velocity, or on the difference with the reference file fileref if exists
691%inf_sup=1: remove values smaller than threshold thresh_vel, =2, larger than threshold
692%fileref: .nc file name for a reference velocity (='': refrence 0 used)
693%fieldref: 'civ1','filter1'...feld used in fileref
694
695function FF=fix(Param,F,C,U,V,X,Y)
696FF=zeros(size(F));%default
697
698%criterium on warn flags
699FlagName={'CheckFmin2','CheckF2','CheckF3','CheckF4'};
700FlagVal=[-2 2 3 4];
701for iflag=1:numel(FlagName)
702    if isfield(Param,FlagName{iflag}) && Param.(FlagName{iflag})
703        FF=(FF==1| F==FlagVal(iflag));
704    end
705end
706%criterium on correlation values
707if isfield (Param,'MinCorr')
708    FF=FF==1 | C<Param.MinCorr;
709end
710if (isfield(Param,'MinVel')&&~isempty(Param.MinVel))||(isfield (Param,'MaxVel')&&~isempty(Param.MaxVel))
711    Umod= U.*U+V.*V;
712    if isfield (Param,'MinVel')&&~isempty(Param.MinVel)
713        FF=FF==1 | Umod<(Param.MinVel*Param.MinVel);
714    end
715    if isfield (Param,'MaxVel')&&~isempty(Param.MaxVel)
716        FF=FF==1 | Umod>(Param.MaxVel*Param.MaxVel);
717    end
718end
719
720
721
722
723
724
725
Note: See TracBrowser for help on using the repository browser.