source: trunk/src/civ_matlab.m @ 444

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

masks and calibration updated to fit with the new conventions on file organisation.
bug corrected in mouse_up (object creation)
bug corrected in civ in mode TESTciv

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