source: trunk/src/civ_matlab.m @ 364

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

civ2, fix2, patch2 introduced under Matlab (no interpolation and rotation done yet)
small corrections in plot_field and read_civdata

File size: 34.9 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%   patch: 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% ncfile: name of a netcdf file to be created for the result (extension .nc)
17%
18%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
19%  Copyright  2011, LEGI / CNRS-UJF-INPG, joel.sommeria@legi.grenoble-inp.fr.
20%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
21%     This is part of the toolbox UVMAT.
22%
23%     UVMAT is free software; you can redistribute it and/or modify
24%     it under the terms of the GNU General Public License as published by
25%     the Free Software Foundation; either version 2 of the License, or
26%     (at your option) any later version.
27%
28%     UVMAT is distributed in the hope that it will be useful,
29%     but WITHOUT ANY WARRANTY; without even the implied warranty of
30%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31%     GNU General Public License (open UVMAT/COPYING.txt) for more details.
32%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
33
34function [Data,errormsg,result_conv]= civ_matlab(Param,ncfile)
35errormsg='';
36Data.ListGlobalAttribute={'Conventions','Program','CivStage'};
37Data.Conventions='uvmat/civdata';% states the conventions used for the description of field variables and attributes
38Data.Program='civ_matlab';
39Data.CivStage=0;%default
40ListVarCiv1={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_C','Civ1_F'}; %variables to read
41ListVarFix1={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_C','Civ1_F','Civ1_FF'};
42mask='';
43maskname='';%default
44check_civx=0;%default
45check_civ1=0;%default
46check_patch1=0;%default
47
48if ischar(Param)
49    Param=xml2struct(Param);
50end
51
52%% Civ1
53if isfield (Param,'Civ1')
54    check_civ1=1;% test for further use of civ1 results
55    % %% prepare images
56    par_civ1=Param.Civ1;
57    if isfield(par_civ1,'reverse_pair')
58        if par_civ1.reverse_pair
59            if ischar(par_civ1.ImageB)
60                temp=par_civ1.ImageA;
61                par_civ1.ImageA=imread(par_civ1.ImageB);
62            end
63            if ischar(temp)
64                par_civ1.ImageB=imread(temp);
65            end
66        end
67    else
68        if ischar(par_civ1.ImageA)
69            par_civ1.ImageA=imread(par_civ1.ImageA);
70        end
71        if ischar(par_civ1.ImageB)
72            par_civ1.ImageB=imread(par_civ1.ImageB);
73        end
74    end
75   
76    % caluclate velocity data (y and v in indices, reverse to y component)
77    [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ1);
78   
79    % to try the reverse_pair method, uncomment below
80    %     [xtable1 ytable1 utable1 vtable1 ctable1 F1 result_conv1 errormsg1] = civ (Param.Civ1);
81    %     Param.Civ1.reverse_pair=1;
82    %     [xtable2 ytable2 utable2 vtable2 ctable2 F2 result_conv2 errormsg2] = civ (Param.Civ1);
83    %     xtable=[xtable1; xtable2];
84    %     ytable=[ytable1; ytable2];
85    %     utable=[utable1; -utable2];
86    %     vtable=[vtable1; -vtable2];
87    %     ctable=[ctable1; ctable2];
88    %     F=[F1; F2];
89    %     result_conv=[result_conv1; result_conv2];
90    %     errormsg=[errormsg1; errormsg2];
91    if ~isempty(errormsg)
92        return
93    end
94    list_param=(fieldnames(Param.Civ1))';
95    Civ1_param=list_param;%default
96    for ilist=1:length(list_param)
97        Civ1_param{ilist}=['Civ1_' list_param{ilist}];
98        Data.(['Civ1_' list_param{ilist}])=Param.Civ1.(list_param{ilist});
99    end
100    Data.ListGlobalAttribute=[Data.ListGlobalAttribute Civ1_param];% {'Civ1_Time','Civ1_Dt'}];
101    Data.ListVarName={'Civ1_X','Civ1_Y','Civ1_U','Civ1_V','Civ1_F','Civ1_C'};%  cell array containing the names of the fields to record
102    Data.VarDimName={'NbVec1','NbVec1','NbVec1','NbVec1','NbVec1','NbVec1'};
103    Data.VarAttribute{1}.Role='coord_x';
104    Data.VarAttribute{2}.Role='coord_y';
105    Data.VarAttribute{3}.Role='vector_x';
106    Data.VarAttribute{4}.Role='vector_y';
107    Data.VarAttribute{5}.Role='warnflag';
108    Data.Civ1_X=reshape(xtable,[],1);
109    Data.Civ1_Y=reshape(Param.Civ1.ImageHeight-ytable+1,[],1);
110    Data.Civ1_U=reshape(utable,[],1);
111    Data.Civ1_V=reshape(-vtable,[],1);
112    Data.Civ1_C=reshape(ctable,[],1);
113    Data.Civ1_F=reshape(F,[],1);
114    Data.CivStage=1; 
115else
116    if exist('ncfile','var')
117        CivFile=ncfile;
118    elseif isfield(Param.Patch1,'CivFile')
119        CivFile=Param.Patch1.CivFile;
120    end
121    Data=nc2struct(CivFile,'ListGlobalAttribute','absolut_time_T0'); %look for the constant 'absolut_time_T0' to detect old civx data format
122    if isfield(Data,'Txt')
123        errormsg=Data.Txt;
124        return
125    end
126    if ~isempty(Data.absolut_time_T0')%read civx file
127        check_civx=1;% test for old civx data format
128        [Data,vardetect,ichoice]=nc2struct(CivFile);%read the variables in the netcdf file
129    else
130        Data=nc2struct(CivFile);%read civ1 and fix1 data in the existing netcdf file
131    end
132end
133
134%% Fix1
135if isfield (Param,'Fix1')
136    ListFixParam=fieldnames(Param.Fix1);
137    for ilist=1:length(ListFixParam)
138        ParamName=ListFixParam{ilist};
139        ListName=['Fix1_' ParamName];
140        eval(['Data.ListGlobalAttribute=[Data.ListGlobalAttribute ''' ParamName '''];'])
141        eval(['Data.' ListName '=Param.Fix1.' ParamName ';'])
142    end
143    if check_civx
144        if ~isfield(Data,'fix')
145            Data.ListGlobalAttribute=[Data.ListGlobalAttribute 'fix'];
146            Data.fix=1;
147            Data.ListVarName=[Data.ListVarName {'vec_FixFlag'}];
148            Data.VarDimName=[Data.VarDimName {'nb_vectors'}];
149        end
150        Data.vec_FixFlag=fix(Param.Fix1,Data.vec_F,Data.vec_C,Data.vec_U,Data.vec_V,Data.vec_X,Data.vec_Y);
151    else
152        Data.ListVarName=[Data.ListVarName {'Civ1_FF'}];
153        Data.VarDimName=[Data.VarDimName {'NbVec1'}];
154        nbvar=length(Data.ListVarName);
155        Data.VarAttribute{nbvar}.Role='errorflag';   
156        Data.Civ1_FF=fix(Param.Fix1,Data.Civ1_F,Data.Civ1_C,Data.Civ1_U,Data.Civ1_V);
157        Data.CivStage=2;   
158    end
159end   
160%% Patch1
161if isfield (Param,'Patch1')
162    if check_civx
163        errormsg='Civ Matlab input needed for patch';
164        return
165    end
166    check_patch1=1;
167    Data.ListGlobalAttribute=[Data.ListGlobalAttribute {'Patch1_Rho','Patch1_Threshold','Patch1_SubDomain'}];
168    Data.Patch1_Rho=Param.Patch1.SmoothingParam;
169    Data.Patch1_Threshold=Param.Patch1.MaxDiff;
170    Data.Patch1_SubDomain=Param.Patch1.SubdomainSize;
171    Data.ListVarName=[Data.ListVarName {'Civ1_U_Diff','Civ1_V_Diff','Civ1_X_SubRange','Civ1_Y_SubRange','Civ1_NbSites','Civ1_X_tps','Civ1_Y_tps','Civ1_U_tps','Civ1_V_tps'}];
172    Data.VarDimName=[Data.VarDimName {'NbVec1','NbVec1',{'NbSubDomain1','Two'},{'NbSubDomain1','Two'},'NbSubDomain1',...
173             {'NbVec1Sub','NbSubDomain1'},{'NbVec1Sub','NbSubDomain1'},{'Nbtps1','NbSubDomain1'},{'Nbtps1','NbSubDomain1'}}];
174    nbvar=length(Data.ListVarName);
175    Data.VarAttribute{nbvar-1}.Role='vector_x';
176    Data.VarAttribute{nbvar}.Role='vector_y';
177    Data.Civ1_U_Diff=zeros(size(Data.Civ1_X));
178    Data.Civ1_V_Diff=zeros(size(Data.Civ1_X));
179    if isfield(Data,'Civ1_FF')
180        ind_good=find(Data.Civ1_FF==0);
181    else
182        ind_good=1:numel(Data.Civ1_X);
183    end
184    [Data.Civ1_X_SubRange,Data.Civ1_Y_SubRange,Data.Civ1_NbSites,FFres,Ures, Vres,Data.Civ1_X_tps,Data.Civ1_Y_tps,Data.Civ1_U_tps,Data.Civ1_V_tps]=...
185                            patch(Data.Civ1_X(ind_good)',Data.Civ1_Y(ind_good)',Data.Civ1_U(ind_good)',Data.Civ1_V(ind_good)',Data.Patch1_Rho,Data.Patch1_Threshold,Data.Patch1_SubDomain);
186      Data.Civ1_U_Diff(ind_good)=Data.Civ1_U(ind_good)-Ures;
187      Data.Civ1_V_Diff(ind_good)=Data.Civ1_V(ind_good)-Vres;
188      Data.Civ1_FF(ind_good)=FFres;
189      Data.CivStage=3;                             
190end   
191
192%% Civ2
193if isfield (Param,'Civ2')
194    par_civ2=Param.Civ2;
195    if ~isfield (Param,'Civ1') || ~strcmp(Param.Civ1.ImageA,par_civ2.ImageA)
196        par_civ2.ImageA=imread(Param.Civ2.ImageA);%read first image if not already done for civ1
197    else
198        par_civ2.ImageA=par_civ1.ImageA;
199    end
200    if ~isfield (Param,'Civ1') || ~strcmp(Param.Civ1.ImageB,par_civ2.ImageB)
201        par_civ2.ImageB=imread(Param.Civ2.ImageB);%read second image if not already done for civ1
202         else
203        par_civ2.ImageB=par_civ1.ImageB;
204    end
205    ibx2=ceil(par_civ2.Bx/2);
206    iby2=ceil(par_civ2.By/2);
207    isx2=ibx2+2;
208    isy2=iby2+2;
209    % shift from par_civ2.filename_nc1
210    % shiftx=velocity interpolated at position
211    miniy=max(1+isy2,1+iby2);
212    minix=max(1+isx2,1+ibx2);
213    maxiy=min(size(par_civ2.ImageA,1)-isy2,size(par_civ2.ImageA,1)-iby2);
214    maxix=min(size(par_civ2.ImageA,2)-isx2,size(par_civ2.ImageA,2)-ibx2);
215    [GridX,GridY]=meshgrid(minix:par_civ2.Dx:maxix,miniy:par_civ2.Dy:maxiy);
216    GridX=reshape(GridX,[],1);
217    GridY=reshape(GridY,[],1);
218    Shiftx=zeros(size(GridX));% shift expected from civ1 data
219    Shifty=zeros(size(GridX));
220    nbval=zeros(size(GridX));
221    if par_civ2.CheckDeformation
222        DUDX=zeros(size(GridX));
223        DUDY=zeros(size(GridX));
224        DVDX=zeros(size(GridX));
225        DVDY=zeros(size(GridX));
226    end
227    [NbSubDomain,xx]=size(Data.Civ1_X_SubRange);
228    % get the guess from patch1
229    for isub=1:NbSubDomain
230        nbvec_sub=Data.Civ1_NbSites(isub);
231        ind_sel=find(GridX>=Data.Civ1_X_SubRange(isub,1) & GridX<=Data.Civ1_X_SubRange(isub,2) & GridY>=Data.Civ1_Y_SubRange(isub,1) & GridY<=Data.Civ1_Y_SubRange(isub,2));
232        epoints = [GridX(ind_sel) GridY(ind_sel)];% coordinates of interpolation sites
233        ctrs=[Data.Civ1_X_tps(1:nbvec_sub,isub) Data.Civ1_Y_tps(1:nbvec_sub,isub)];%(=initial points) ctrs
234        nbval(ind_sel)=nbval(ind_sel)+1;% records the number of values for eacn interpolation point (in case of subdomain overlap)
235        EM = tps_eval(epoints,ctrs);
236        Shiftx(ind_sel)=Shiftx(ind_sel)+EM*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
237        Shifty(ind_sel)=Shifty(ind_sel)+EM*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
238        if par_civ2.CheckDeformation
239            [EMDX,EMDY] = tps_eval_dxy(epoints,ctrs);%2D matrix of distances between extrapolation points epoints and spline centres (=site points) ctrs
240            DUDX(ind_sel)=DUDX(ind_sel)+EMDX*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
241            DUDY(ind_sel)=DUDY(ind_sel)+EMDY*Data.Civ1_U_tps(1:nbvec_sub+3,isub);
242            DVDX(ind_sel)=DVDX(ind_sel)+EMDX*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
243            DVDY(ind_sel)=DVDY(ind_sel)+EMDY*Data.Civ1_V_tps(1:nbvec_sub+3,isub);
244        end
245    end
246    mask='';
247    if par_civ2.CheckMask&&~isempty(par_civ2.maskname)&& ~strcmp(maskname,par_civ2.maskname)% mask exist, not already read in civ1
248        mask=imread(par_civ2.maskname);
249    end
250    par_civ2.Searchx=2*isx2+1;
251    par_civ2.Searchy=2*isy2+1;
252    par_civ2.Shiftx=Shiftx./nbval;
253    par_civ2.Shifty=Shifty./nbval;
254    par_civ2.Grid=[GridX GridY];   
255    if par_civ2.CheckDeformation
256        DUDX=DUDX./nbval;
257        DUDY=DUDY./nbval;
258        DVDX=DVDX./nbval;
259        DVDY=DVDY./nbval;
260    end
261    % caluclate velocity data (y and v in indices, reverse to y component)
262    [xtable ytable utable vtable ctable F] = civ (par_civ2);
263    list_param=(fieldnames(Param.Civ2))';
264    list_remove={'pxcmx','pxcmy','npx','npy','gridflag','maskflag','term_a','term_b','T0'};
265    for ilist=1:length(list_remove)
266        index=strcmp(list_remove{ilist},list_param);
267        if ~isempty(find(index,1))
268            list_param(index)=[];
269        end
270    end
271    for ilist=1:length(list_param)
272        Civ2_param{ilist}=['Civ2_' list_param{ilist}];
273        eval(['Data.Civ2_' list_param{ilist} '=Param.Civ2.' list_param{ilist} ';'])
274    end
275    if isfield(Data,'Civ2_gridname') && strcmp(Data.Civ1_gridname(1:6),'noFile')
276        Data.Civ1_gridname='';
277    end
278    if isfield(Data,'Civ2_maskname') && strcmp(Data.Civ1_maskname(1:6),'noFile')
279        Data.Civ2_maskname='';
280    end
281    Data.ListGlobalAttribute=[Data.ListGlobalAttribute Civ2_param {'Civ2_Time','Civ2_Dt'}];
282    Data.Civ2_Time=str2double(par_civ2.Time);
283    Data.Civ2_Dt=str2double(par_civ2.Dt);
284    nbvar=numel(Data.ListVarName);
285    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
286    Data.VarDimName=[Data.VarDimName {'NbVec2','NbVec2','NbVec2','NbVec2','NbVec2','NbVec2'}];
287    Data.VarAttribute{nbvar+1}.Role='coord_x';
288    Data.VarAttribute{nbvar+2}.Role='coord_y';
289    Data.VarAttribute{nbvar+3}.Role='vector_x';
290    Data.VarAttribute{nbvar+4}.Role='vector_y';
291    Data.VarAttribute{nbvar+5}.Role='warnflag';
292    Data.Civ2_X=reshape(xtable,[],1);
293    Data.Civ2_Y=reshape(size(par_civ2.ImageA,1)-ytable+1,[],1);
294    Data.Civ2_U=reshape(utable,[],1);
295    Data.Civ2_V=reshape(-vtable,[],1);
296    Data.Civ2_C=reshape(ctable,[],1);
297    Data.Civ2_F=reshape(F,[],1);
298    Data.CivStage=Data.CivStage+1;
299end
300
301%% Fix2
302if isfield (Param,'Fix2')
303    ListFixParam=fieldnames(Param.Fix2);
304    for ilist=1:length(ListFixParam)
305        ParamName=ListFixParam{ilist};
306        ListName=['Fix2_' ParamName];
307        eval(['Data.ListGlobalAttribute=[Data.ListGlobalAttribute ''' ParamName '''];'])
308        eval(['Data.' ListName '=Param.Fix2.' ParamName ';'])
309    end
310    if check_civx
311        if ~isfield(Data,'fix2')
312            Data.ListGlobalAttribute=[Data.ListGlobalAttribute 'fix2'];
313            Data.fix2=1;
314            Data.ListVarName=[Data.ListVarName {'vec2_FixFlag'}];
315            Data.VarDimName=[Data.VarDimName {'nb_vectors2'}];
316        end
317        Data.vec_FixFlag=fix(Param.Fix2,Data.vec2_F,Data.vec2_C,Data.vec2_U,Data.vec2_V,Data.vec2_X,Data.vec2_Y);
318    else
319        Data.ListVarName=[Data.ListVarName {'Civ2_FF'}];
320        Data.VarDimName=[Data.VarDimName {'nbvec2'}];
321        nbvar=length(Data.ListVarName);
322        Data.VarAttribute{nbvar}.Role='errorflag';   
323        Data.Civ2_FF=fix(Param.Fix2,Data.Civ2_F,Data.Civ2_C,Data.Civ2_U,Data.Civ2_V);
324        Data.CivStage=Data.CivStage+1;   
325    end
326   
327end   
328
329%% Patch2
330if isfield (Param,'Patch2')
331    Data.ListGlobalAttribute=[Data.ListGlobalAttribute {'Patch2_Rho','Patch2_Threshold','Patch2_SubDomain'}];
332    Data.Patch2_Rho=Param.Patch2.SmoothingParam;
333    Data.Patch2_Threshold=Param.Patch2.MaxDiff;
334    Data.Patch2_SubDomain=Param.Patch2.SubdomainSize;
335    Data.ListVarName=[Data.ListVarName {'Civ2_U_Diff','Civ2_V_Diff','Civ2_X_SubRange','Civ2_Y_SubRange','Civ2_NbSites','Civ2_X_tps','Civ2_Y_tps','Civ2_U_tps','Civ2_V_tps'}];
336    Data.VarDimName=[Data.VarDimName {'NbVec2','NbVec2',{'NbSubDomain2','Two'},{'NbSubDomain2','Two'},'NbSubDomain2',...
337             {'NbVec2Sub','NbSubDomain2'},{'NbVec2Sub','NbSubDomain2'},{'Nbtps2','NbSubDomain2'},{'Nbtps2','NbSubDomain2'}}];
338    nbvar=length(Data.ListVarName);
339    Data.VarAttribute{nbvar-1}.Role='vector_x';
340    Data.VarAttribute{nbvar}.Role='vector_y';
341    Data.Civ2_U_Diff=zeros(size(Data.Civ2_X));
342    Data.Civ2_V_Diff=zeros(size(Data.Civ2_X));
343    if isfield(Data,'Civ2_FF')
344        ind_good=find(Data.Civ2_FF==0);
345    else
346        ind_good=1:numel(Data.Civ2_X);
347    end
348    [Data.Civ2_X_SubRange,Data.Civ2_Y_SubRange,Data.Civ2_NbSites,FFres,Ures, Vres,Data.Civ2_X_tps,Data.Civ2_Y_tps,Data.Civ2_U_tps,Data.Civ2_V_tps]=...
349                            patch(Data.Civ2_X(ind_good)',Data.Civ2_Y(ind_good)',Data.Civ2_U(ind_good)',Data.Civ2_V(ind_good)',Data.Patch2_Rho,Data.Patch2_Threshold,Data.Patch2_SubDomain);
350      Data.Civ2_U_Diff(ind_good)=Data.Civ2_U(ind_good)-Ures;
351      Data.Civ2_V_Diff(ind_good)=Data.Civ2_V(ind_good)-Vres;
352      Data.Civ2_FF(ind_good)=FFres;
353      Data.CivStage=Data.CivStage+1;                             
354end 
355
356%% write result in a netcdf file if requested
357if exist('ncfile','var')
358    errormsg=struct2nc(ncfile,Data);
359end
360
361% 'civ': function piv.m adapted from PIVlab http://pivlab.blogspot.com/
362%--------------------------------------------------------------------------
363% function [xtable ytable utable vtable typevector] = civ (image1,image2,ibx,iby step, subpixfinder, mask, roi)
364%
365% OUTPUT:
366% xtable: set of x coordinates
367% ytable: set of y coordiantes
368% utable: set of u displacements (along x)
369% vtable: set of v displacements (along y)
370% ctable: max image correlation for each vector
371% typevector: set of flags, =1 for good, =0 for NaN vectors
372%
373%INPUT:
374% image1:first image (matrix)
375% image2: second image (matrix)
376% ibx2,iby2: half size of the correlation box along x and y, in px (size=(2*iby2+1,2*ibx2+1)
377% isx2,isy2: half size of the search box along x and y, in px (size=(2*isy2+1,2*isx2+1)
378% shiftx, shifty: shift of the search box (in pixel index, yshift reversed)
379% step: mesh of the measurement points (in px)
380% subpixfinder=1 or 2 controls the curve fitting of the image correlation
381% mask: =[] for no mask
382% roi: 4 element vector defining a region of interest: x position, y position, width, height, (in image indices), for the whole image, roi=[];
383function [xtable ytable utable vtable ctable F result_conv errormsg] = civ (par_civ)
384%this funtion performs the DCC PIV analysis. Recent window-deformation
385%methods perform better and will maybe be implemented in the future.
386
387%% prepare grid
388ibx2=ceil(par_civ.Bx/2);
389iby2=ceil(par_civ.By/2);
390isx2=ceil(par_civ.Searchx/2);
391isy2=ceil(par_civ.Searchy/2);
392shiftx=par_civ.Shiftx;
393shifty=-par_civ.Shifty;% sign minus because image j index increases when y decreases
394if isfield(par_civ,'Grid')
395    if ischar(par_civ.Grid)%read the drid file if the input is a file name
396        par_civ.Grid=dlmread(par_civ.Grid);
397        par_civ.Grid(1,:)=[];%the first line must be removed (heading in the grid file)
398    end
399else% automatic measurement grid
400    ibx2=ceil(par_civ.Bx/2);
401    iby2=ceil(par_civ.By/2);
402    isx2=ceil(par_civ.Searchx/2);
403    isy2=ceil(par_civ.Searchy/2);
404    miniy=max(1+isy2+shifty,1+iby2);
405    minix=max(1+isx2-shiftx,1+ibx2);
406    maxiy=min(par_civ.ImageHeight-isy2+shifty,par_civ.ImageHeight-iby2);
407    maxix=min(par_civ.ImageWidth-isx2-shiftx,par_civ.ImageWidth-ibx2);
408    [GridX,GridY]=meshgrid(minix:par_civ.Dx:maxix,miniy:par_civ.Dy:maxiy);
409    par_civ.Grid(:,1)=reshape(GridX,[],1);
410    par_civ.Grid(:,2)=reshape(GridY,[],1);
411end
412nbvec=size(par_civ.Grid,1);
413if numel(shiftx)==1
414    shiftx=round(shiftx)*ones(nbvec,1);
415    shifty=round(shifty)*ones(nbvec,1);
416end
417%% Default output
418xtable=par_civ.Grid(:,1);
419ytable=par_civ.Grid(:,2);
420utable=zeros(nbvec,1);
421vtable=zeros(nbvec,1);
422ctable=zeros(nbvec,1);
423F=zeros(nbvec,1);
424result_conv=[];
425errormsg='';
426
427%% prepare mask
428if isfield(par_civ,'Mask') && ~isempty(par_civ.Mask)
429    if strcmp(par_civ.Mask,'all')
430        return    % get the grid only, no civ calculation
431    elseif ischar(par_civ.Mask)
432        par_civ.Mask=imread(par_civ.Mask);
433    end
434end
435check_MinIma=isfield(par_civ,'MinIma');% test for image luminosity threshold
436check_MaxIma=isfield(par_civ,'MaxIma') && ~isempty(par_civ.MaxIma);
437
438% %% prepare images
439% if isfield(par_civ,'reverse_pair')
440%     if par_civ.reverse_pair
441%         if ischar(par_civ.ImageB)
442%             temp=par_civ.ImageA;
443%             par_civ.ImageA=imread(par_civ.ImageB);
444%         end
445%         if ischar(temp)
446%             par_civ.ImageB=imread(temp);
447%         end
448%     end
449% else
450%     if ischar(par_civ.ImageA)
451%         par_civ.ImageA=imread(par_civ.ImageA);
452%     end
453%     if ischar(par_civ.ImageB)
454%         par_civ.ImageB=imread(par_civ.ImageB);
455%     end
456% end
457
458[npy_ima npx_ima]=size(par_civ.ImageA);
459if ~isequal(size(par_civ.ImageB),[npy_ima npx_ima])
460    errormsg='image pair with unequal size';
461    return
462end
463par_civ.ImageA=double(par_civ.ImageA);
464par_civ.ImageB=double(par_civ.ImageB);
465
466
467%% Apply mask
468    % Convention for mask
469    % mask >200 : velocity calculated
470    %  200 >=mask>150;velocity not calculated, interpolation allowed (bad spots)
471    % 150>=mask >100: velocity not calculated, nor interpolated
472    %  100>=mask> 20: velocity not calculated, impermeable (no flux through mask boundaries) TO IMPLEMENT
473    %  20>=mask: velocity=0
474checkmask=0;
475if isfield(par_civ,'Mask') && ~isempty(par_civ.Mask)
476   checkmask=1;
477   if ~isequal(size(par_civ.Mask),[npy_ima npx_ima])
478        errormsg='mask must be an image with the same size as the images';
479        return
480   end
481  %  check_noflux=(par_civ.Mask<100) ;%TODO: to implement
482    check_undefined=(par_civ.Mask<200 & par_civ.Mask>=100 );
483    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
484    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
485end
486
487%% compute image correlations: MAINLOOP on velocity vectors
488corrmax=0;
489sum_square=1;% default
490% vector=[0 0];%default
491for ivec=1:nbvec
492    iref=par_civ.Grid(ivec,1);% xindex on the image A for the middle of the correlation box
493    jref=par_civ.Grid(ivec,2);% yindex on the image B for the middle of the correlation box
494    %     xtable(ivec)=iref;
495    %     ytable(ivec)=jref;%default
496    if ~(checkmask && par_civ.Mask(jref,iref)<=20) %velocity not set to zero by the black mask
497        if jref-iby2<1 || jref+iby2>par_civ.ImageHeight|| iref-ibx2<1 || iref+ibx2>par_civ.ImageWidth||...
498              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
499            F(ivec)=3;
500        else
501            image1_crop=par_civ.ImageA(jref-iby2:jref+iby2,iref-ibx2:iref+ibx2);%extract a subimage (correlation box) from image A
502            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
503            image1_mean=mean(mean(image1_crop));
504            image2_mean=mean(mean(image2_crop));
505            %threshold on image minimum
506            if check_MinIma && (image1_mean < par_civ.MinIma || image2_mean < par_civ.MinIma)
507                F(ivec)=3;
508            end
509            %threshold on image maximum
510            if check_MaxIma && (image1_mean > par_civ.MaxIma || image2_mean > par_civ.MaxIma)
511                F(ivec)=3;
512            end
513        end
514       
515        if F(ivec)~=3
516            image1_crop=image1_crop-image1_mean;%substract the mean
517            image2_crop=image2_crop-image2_mean;
518            sum_square=sum(sum(image1_crop.*image1_crop));
519            %reference: Oliver Pust, PIV: Direct Cross-Correlation
520            result_conv= conv2(image2_crop,flipdim(flipdim(image1_crop,2),1),'valid');
521            corrmax= max(max(result_conv));
522            result_conv=(result_conv/corrmax)*255; %normalize, peak=always 255
523            %Find the correlation max, at 255
524            [y,x] = find(result_conv==255,1);
525            if ~isempty(y) && ~isempty(x)
526                try
527                    if par_civ.Rho==1
528                        [vector,F(ivec)] = SUBPIXGAUSS (result_conv,x,y);
529                    elseif par_civ.Rho==2
530                        [vector,F(ivec)] = SUBPIX2DGAUSS (result_conv,x,y);
531                    end
532                    utable(ivec)=vector(1)+shiftx(ivec);
533                    vtable(ivec)=vector(2)+shifty(ivec);
534                    xtable(ivec)=iref+utable(ivec)/2;% convec flow (velocity taken at the point middle from imgae1 and 2)
535                    ytable(ivec)=jref+vtable(ivec)/2;
536                    iref=round(xtable(ivec));% image index for the middle of the vector
537                    jref=round(ytable(ivec));
538                    if checkmask && par_civ.Mask(jref,iref)<200 && par_civ.Mask(jref,iref)>=100
539                        utable(ivec)=0;
540                        vtable(ivec)=0;
541                        F(ivec)=3;
542                    end
543                    ctable(ivec)=corrmax/sum_square;% correlation value
544                catch ME
545                    F(ivec)=3;
546                end
547            else
548                F(ivec)=3;
549            end
550        end
551    end
552   
553    %Create the vector matrix x, y, u, v
554end
555result_conv=result_conv*corrmax/(255*sum_square);% keep the last correlation matrix for output
556
557%------------------------------------------------------------------------
558% --- Find the maximum of the correlation function after interpolation
559function [vector,F] = SUBPIXGAUSS (result_conv,x,y)
560%------------------------------------------------------------------------
561vector=[0 0]; %default
562F=0;
563[npy,npx]=size(result_conv);
564
565% if (x <= (size(result_conv,1)-1)) && (y <= (size(result_conv,1)-1)) && (x >= 1) && (y >= 1)
566    %the following 8 lines are copyright (c) 1998, Uri Shavit, Roi Gurka, Alex Liberzon, Technion ï¿œ Israel Institute of Technology
567    %http://urapiv.wordpress.com
568    peaky = y;
569    if y <= npy-1 && y >= 1
570        f0 = log(result_conv(y,x));
571        f1 = real(log(result_conv(y-1,x)));
572        f2 = real(log(result_conv(y+1,x)));
573        peaky = peaky+ (f1-f2)/(2*f1-4*f0+2*f2);
574    else
575        F=-2; % warning flag for vector truncated by the limited search box
576    end
577    peakx=x;
578    if x <= npx-1 && x >= 1
579        f0 = log(result_conv(y,x));
580        f1 = real(log(result_conv(y,x-1)));
581        f2 = real(log(result_conv(y,x+1)));
582        peakx = peakx+ (f1-f2)/(2*f1-4*f0+2*f2);
583    else
584        F=-2; % warning flag for vector truncated by the limited search box
585    end
586    vector=[peakx-floor(npx/2)-1 peaky-floor(npy/2)-1];
587
588%------------------------------------------------------------------------
589% --- Find the maximum of the correlation function after interpolation
590function [vector,F] = SUBPIX2DGAUSS (result_conv,x,y)
591%------------------------------------------------------------------------
592vector=[0 0]; %default
593F=-2;
594peaky=y;
595peakx=x;
596[npy,npx]=size(result_conv);
597if (x <= npx-1) && (y <= npy-1) && (x >= 1) && (y >= 1)
598    F=0;
599    for i=-1:1
600        for j=-1:1
601            %following 15 lines based on
602            %H. Nobach ï¿œ M. Honkanen (2005)
603            %Two-dimensional Gaussian regression for sub-pixel displacement
604            %estimation in particle image velocimetry or particle position
605            %estimation in particle tracking velocimetry
606            %Experiments in Fluids (2005) 38: 511ï¿œ515
607            c10(j+2,i+2)=i*log(result_conv(y+j, x+i));
608            c01(j+2,i+2)=j*log(result_conv(y+j, x+i));
609            c11(j+2,i+2)=i*j*log(result_conv(y+j, x+i));
610            c20(j+2,i+2)=(3*i^2-2)*log(result_conv(y+j, x+i));
611            c02(j+2,i+2)=(3*j^2-2)*log(result_conv(y+j, x+i));
612        end
613    end
614    c10=(1/6)*sum(sum(c10));
615    c01=(1/6)*sum(sum(c01));
616    c11=(1/4)*sum(sum(c11));
617    c20=(1/6)*sum(sum(c20));
618    c02=(1/6)*sum(sum(c02));
619    deltax=(c11*c01-2*c10*c02)/(4*c20*c02-c11^2);
620    deltay=(c11*c10-2*c01*c20)/(4*c20*c02-c11^2);
621    if abs(deltax)<1
622        peakx=x+deltax;
623    end
624    if abs(deltay)<1
625        peaky=y+deltay;
626    end
627end
628vector=[peakx-floor(npx/2)-1 peaky-floor(npy/2)-1];
629
630%'RUN_FIX': function for fixing velocity fields:
631%-----------------------------------------------
632% RUN_FIX(filename,field,flagindex,thresh_vecC,thresh_vel,iter,flag_mask,maskname,fileref,fieldref)
633%
634%filename: name of the netcdf file (used as input and output)
635%field: structure specifying the names of the fields to fix (depending on civ1 or civ2)
636    %.vel_type='civ1' or 'civ2';
637    %.nb=name of the dimension common to the field to fix ('nb_vectors' for civ1);
638    %.fixflag=name of fix flag variable ('vec_FixFlag' for civ1)
639%flagindex: flag specifying which values of vec_f are removed:
640        % if flagindex(1)=1: vec_f=-2 vectors are removed
641        % if flagindex(2)=1: vec_f=3 vectors are removed
642        % if flagindex(3)=1: vec_f=2 vectors are removed (if iter=1) or vec_f=4 vectors are removed (if iter=2)
643%iter=1 for civ1 fields and iter=2 for civ2 fields
644%thresh_vecC: threshold in the image correlation vec_C
645%flag_mask: =1 mask used to remove vectors (0 else)
646%maskname: name of the mask image file for fix
647%thresh_vel: threshold on velocity, or on the difference with the reference file fileref if exists
648%inf_sup=1: remove values smaller than threshold thresh_vel, =2, larger than threshold
649%fileref: .nc file name for a reference velocity (='': refrence 0 used)
650%fieldref: 'civ1','filter1'...feld used in fileref
651
652function FF=fix(Param,F,C,U,V,X,Y)
653FF=zeros(size(F));%default
654
655%criterium on warn flags
656FlagName={'CheckFmin2','CheckF2','CheckF3','CheckF4'};
657FlagVal=[-2 2 3 4];
658for iflag=1:numel(FlagName)
659    if isfield(Param,FlagName{iflag}) && Param.(FlagName{iflag})
660        FF=(FF==1| F==FlagVal(iflag));
661    end
662end
663%criterium on correlation values
664if isfield (Param,'MinCorr')
665    FF=FF==1 | C<Param.MinCorr;
666end
667if (isfield(Param,'MinVel')&&~isempty(Param.MinVel))||(isfield (Param,'MaxVel')&&~isempty(Param.MaxVel))
668    Umod= U.*U+V.*V;
669    if isfield (Param,'MinVel')&&~isempty(Param.MinVel)
670        FF=FF==1 | Umod<(Param.MinVel*Param.MinVel);
671    end
672    if isfield (Param,'MaxVel')&&~isempty(Param.MaxVel)
673        FF=FF==1 | Umod>(Param.MaxVel*Param.MaxVel);
674    end
675end
676
677
678
679%------------------------------------------------------------------------
680% patch function
681% OUTPUT:
682% SubRangx,SubRangy(NbSubdomain,2): range (min, max) of the coordiantes x and y respectively, for each subdomain
683% nbpoints(NbSubdomain): number of source points for each subdomain
684% FF: false flags
685% U_smooth, V_smooth: filtered velocity components at the positions of the initial data
686% X_tps,Y_tps,U_tps,V_tps: positions and weight of the tps for each subdomain
687%
688% INPUT:
689% X, Y: set of coordinates of the initial data
690% U,V: set of velocity components of the initial data
691% Rho: smoothing parameter
692% Threshold: max diff accepted between smoothed and initial data
693% Subdomain: estimated number of data points in each subdomain
694
695function [SubRangx,SubRangy,nbpoints,FF,U_smooth,V_smooth,X_tps,Y_tps,U_tps,V_tps] =patch(X,Y,U,V,Rho,Threshold,SubDomain)
696%subdomain decomposition
697warning off
698U=reshape(U,[],1);
699V=reshape(V,[],1);
700X=reshape(X,[],1);
701Y=reshape(Y,[],1);
702nbvec=numel(X);
703NbSubDomain=ceil(nbvec/SubDomain);
704MinX=min(X);
705MinY=min(Y);
706MaxX=max(X);
707MaxY=max(Y);
708RangX=MaxX-MinX;
709RangY=MaxY-MinY;
710AspectRatio=RangY/RangX;
711NbSubDomainX=max(floor(sqrt(NbSubDomain/AspectRatio)),1);
712NbSubDomainY=max(floor(sqrt(NbSubDomain*AspectRatio)),1);
713NbSubDomain=NbSubDomainX*NbSubDomainY;
714SizX=RangX/NbSubDomainX;%width of subdomains
715SizY=RangY/NbSubDomainY;%height of subdomains
716CentreX=linspace(MinX+SizX/2,MaxX-SizX/2,NbSubDomainX);
717CentreY=linspace(MinY+SizY/2,MaxY-SizY/2,NbSubDomainY);
718[CentreX,CentreY]=meshgrid(CentreX,CentreY);
719CentreY=reshape(CentreY,1,[]);% Y positions of subdomain centres
720CentreX=reshape(CentreX,1,[]);% X positions of subdomain centres
721rho=SizX*SizY*Rho/1000000;%optimum rho increase as the area of the subdomain (division by 10^6 to reach good values with the default GUI input)
722U_tps_sub=zeros(length(X),NbSubDomain);%default spline
723V_tps_sub=zeros(length(X),NbSubDomain);%default spline
724U_smooth=zeros(length(X),1);
725V_smooth=zeros(length(X),1);
726
727nb_select=zeros(length(X),1);
728FF=zeros(length(X),1);
729check_empty=zeros(1,NbSubDomain);
730SubRangx=zeros(NbSubDomain,2);%initialise the positions of subdomains
731SubRangy=zeros(NbSubDomain,2);
732for isub=1:NbSubDomain
733    SubRangx(isub,:)=[CentreX(isub)-0.55*SizX CentreX(isub)+0.55*SizX];
734    SubRangy(isub,:)=[CentreY(isub)-0.55*SizY CentreY(isub)+0.55*SizY];
735    ind_sel_previous=[];
736    ind_sel=0;
737    while numel(ind_sel)>numel(ind_sel_previous) %increase the subdomain during four iterations at most
738        ind_sel_previous=ind_sel;
739        ind_sel=find(X>=SubRangx(isub,1) & X<=SubRangx(isub,2) & Y>=SubRangy(isub,1) & Y<=SubRangy(isub,2));
740        % if no vector in the subdomain, skip the subdomain
741        if isempty(ind_sel)
742            check_empty(isub)=1;   
743            U_tps(1,isub)=0;%define U_tps and V_tps by default
744            V_tps(1,isub)=0;
745            break
746            % if too few selected vectors, increase the subrange for next iteration
747        elseif numel(ind_sel)<SubDomain/4 && ~isequal( ind_sel,ind_sel_previous);
748            SubRangx(isub,1)=SubRangx(isub,1)-SizX/4;
749            SubRangx(isub,2)=SubRangx(isub,2)+SizX/4;
750            SubRangy(isub,1)=SubRangy(isub,1)-SizY/4;
751            SubRangy(isub,2)=SubRangy(isub,2)+SizY/4;
752        else
753           
754            [U_smooth_sub,U_tps_sub]=tps_coeff([X(ind_sel) Y(ind_sel)],U(ind_sel),rho);
755            [V_smooth_sub,V_tps_sub]=tps_coeff([X(ind_sel) Y(ind_sel)],V(ind_sel),rho);
756            UDiff=U_smooth_sub-U(ind_sel);
757            VDiff=V_smooth_sub-V(ind_sel);
758            NormDiff=UDiff.*UDiff+VDiff.*VDiff;
759            FF(ind_sel)=20*(NormDiff>Threshold);%put FF value to 20 to identify the criterium of elimmination
760            ind_ind_sel=find(FF(ind_sel)==0); % select the indices of ind_sel corresponding to the remaining vectors
761            % no value exceeds threshold, the result is recorded
762            if isequal(numel(ind_ind_sel),numel(ind_sel))
763                U_smooth(ind_sel)=U_smooth(ind_sel)+U_smooth_sub;
764                V_smooth(ind_sel)=V_smooth(ind_sel)+V_smooth_sub;
765                nbpoints(isub)=numel(ind_sel);
766                X_tps(1:nbpoints(isub),isub)=X(ind_sel);
767                Y_tps(1:nbpoints(isub),isub)=Y(ind_sel);
768                U_tps(1:nbpoints(isub)+3,isub)=U_tps_sub;
769                V_tps(1:nbpoints(isub)+3,isub)=V_tps_sub;         
770                nb_select(ind_sel)=nb_select(ind_sel)+1;
771                 display('good')
772                break
773                % too few selected vectors, increase the subrange for next iteration
774            elseif numel(ind_ind_sel)<SubDomain/4 && ~isequal( ind_sel,ind_sel_previous);
775                SubRangx(isub,1)=SubRangx(isub,1)-SizX/4;
776                SubRangx(isub,2)=SubRangx(isub,2)+SizX/4;
777                SubRangy(isub,1)=SubRangy(isub,1)-SizY/4;
778                SubRangy(isub,2)=SubRangy(isub,2)+SizY/4;
779%                 display('fewsmooth')
780                % interpolation-smoothing is done again with the selected vectors
781            else
782                [U_smooth_sub,U_tps_sub]=tps_coeff([X(ind_sel(ind_ind_sel)) Y(ind_sel(ind_ind_sel))],U(ind_sel(ind_ind_sel)),rho);
783                [V_smooth_sub,V_tps_sub]=tps_coeff([X(ind_sel(ind_ind_sel)) Y(ind_sel(ind_ind_sel))],V(ind_sel(ind_ind_sel)),rho);
784                U_smooth(ind_sel(ind_ind_sel))=U_smooth(ind_sel(ind_ind_sel))+U_smooth_sub;
785                V_smooth(ind_sel(ind_ind_sel))=V_smooth(ind_sel(ind_ind_sel))+V_smooth_sub;
786                nbpoints(isub)=numel(ind_ind_sel);
787                X_tps(1:nbpoints(isub),isub)=X(ind_sel(ind_ind_sel));
788                Y_tps(1:nbpoints(isub),isub)=Y(ind_sel(ind_ind_sel));
789                U_tps(1:nbpoints(isub)+3,isub)=U_tps_sub;
790                V_tps(1:nbpoints(isub)+3,isub)=V_tps_sub;
791                nb_select(ind_sel(ind_ind_sel))=nb_select(ind_sel(ind_ind_sel))+1;
792                display('good2')
793                break
794            end
795        end
796    end
797end
798ind_empty=find(check_empty);
799%remove empty subdomains
800if ~isempty(ind_empty)
801    SubRangx(ind_empty,:)=[];
802    SubRangy(ind_empty,:)=[];
803    X_tps(:,ind_empty)=[];
804    Y_tps(:,ind_empty)=[];
805    U_tps(:,ind_empty)=[];
806    V_tps(:,ind_empty)=[];
807end
808nb_select(nb_select==0)=1;%ones(size(find(nb_select==0)));
809U_smooth=U_smooth./nb_select;
810V_smooth=V_smooth./nb_select;
811
812
813
814
815
Note: See TracBrowser for help on using the repository browser.