source: trunk/src/civ_matlab.m @ 315

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

many corrections, use of the new GUI civ with mask, grid and the new matlab civ1 and fix
pivlab now included in civ_matlab which contains all matlab subfunctions for civ.

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