YaDICs  V04.14.a
Yet another Digital Image Correlation software: platform dedicated to 2/3D Fluid and Solid kinematics field measurements.
 All Classes Files Functions Variables Pages
Ccorrelation_intercor.h
1 /**********************************************************************
2  * Copyright (C) 2012, The YaDICs Project Developers.
3  * See the COPYRIGHT file at the top-level directory of this distribution ./COPYRIGHT.
4  * See ./COPYING file for copying and redistribution conditions.
5  *
6  * This file is part of YaDICs.
7  * YaDICs is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * YaDICs is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with YaDICs. If not, see <http://www.gnu.org/licenses/>.
19  *
20  * Information about how to use the software are provided at http://yadic.univ-lille1.fr/
21  **********************************************************************/
22 
23 
24 #ifndef CCORRELATION_INTERCOR
25 #define CCORRELATION_INTERCOR
26 
27 
28 #include "Ccorrelation.h"
29 
44 template<typename T, typename Timg>
45 class Ccorrelation_intercor: public Ccorrelation<T,Timg>
46 {
47 
48  public:
49 
50  std::string m_peak_type;
51  T m_meanVal;
52 
54  {// constructor
55 
56  this->class_name = "Correlation : Intercorrelation";
57 
58  }
59 
60 
61  virtual void init(CParameterNetCDF &fp)
62  {// init from parameter file
63 
68  std::string attribute_name = "median_filter";
69  int error = fp.loadAttribute(attribute_name,this->m_medianFilter);
70  if (this->m_verbose){printf("\t\t median filter over following domain -> %i\n",this->m_medianFilter);}
71 
72  attribute_name = "peak";
73  error = fp.loadAttribute(attribute_name,m_peak_type);
74  if (this->m_verbose){printf("\t\t peak approximation method -> %s\n", m_peak_type.c_str());}
75 
76  }
77 
78  virtual void exec(const Cimage<Timg> &oImage, const Cmesh<T,Timg> &oMesh, Cfield<T,Timg> &oField)
79  {// exec
80 
87  #ifdef cimg_use_fftw3
88  pthread_mutex_t fftw_init_mutex;
89  #endif
90 
91  this->_3D = oMesh._3D;
92 
93  //calcul of image mean value to fill unknown region within correlograms.
94  T m_meanVal = oImage.m_curImg[0].mean();
95  CImg<T> current_res(this->m_threadNB,1,1,1,0);
96  CImg<int> p(this->m_threadNB,1,1,1,0);
97 
98  int counter(100);
99 
100  #pragma omp parallel
101  {
102 
103  std::vector<T> offset;
104  int thread = omp_get_thread_num();
105 
106  //initialisation of two sub_images containers and associated Fourier transform.
107  // ! CImg complex = CImgList -> [0] = real part and [1] = imaginary one
108  CImgList<T> correlogram(2, oMesh.m_win[0], oMesh.m_win[1], oMesh.m_win[2], 1, 0);
109  CImgList<T> F(correlogram), G(correlogram); //FFT of img1 & img2
110 
112  CNpeak<T> Peaks(m_peak_type, oMesh.grid_dims(3), oMesh.num_var()); //pointer vector toward m_nbPeak peak_type objects
113  Peaks.m_verbose = this->m_verbose;
114 
115  #ifdef cimg_use_fftw3 //setup FFTw (thread safe by using mutex)
116  correlogram[0].fftw_assign(F[0],&fftw_init_mutex);
117  #endif
118 
119  #pragma omp for schedule(runtime)
120  cimglist_for(oMesh.m_connect, elem)
121  {// for each element
122 
123  p[thread]+=oMesh.m_win[0]*oMesh.m_win[1]*oMesh.m_win[2];
124 
125  if (cropBox(oMesh, oImage, oField, elem, correlogram, offset))
126  {
127 
128  if(this->m_verbose and thread == 0)
129  {this->count(elem,oMesh.m_connect.size(),counter);}// counter of master thread progression
130 
131  correl(correlogram, F, G);//intercorrelation
132 
133  if(oField.m_storeCorrelo)
134  {//stores correlograms
135  oField.m_correlogram.draw_image(offset[0],offset[1],offset[2],0,correlogram[0],1);
136  }
137 
138  Peaks.exec(correlogram[0]);//n first peaks stat - correlogram[0] = real(ifft(F.G*))
139 
140  actu_field(oImage, oMesh, elem, Peaks, oField);//actualizes displacement field
141 
142  residual(oImage, oMesh, elem, offset, oField, current_res[thread]);//computes residues
143 
144  }// if elem is unmasked
145 
146  }// loops on elem
147 
148  #ifdef cimg_use_fftw3
149  correlogram[0].fftw_clear();
150  #endif //cimg_use_fftw3
151 
152  #pragma omp single
153  {
154  oField.m_meanRes.push_back(std::sqrt(current_res.sum())/p.sum()*oImage.m_curImg[0].size()/oImage.m_res*100);
155  std::cout<<this->class_name.c_str()<<" -> residue : "<<oField.m_meanRes.back()<<" \%\n\n";
156 
157  if (this->m_medianFilter)
158  {
159  for(int var=0; var<oMesh.num_var(); var++)
160  {// apply pixel scaling and median filter
161  oField.m_mode[var+2].blur_median(this->m_medianFilter);
162  }
163  }
164  }//barrier
165 
166  if (oImage.m_storeDef or oImage.m_storeRes or oImage.m_storeField)
167  {
168  #pragma omp for schedule(runtime)
169  cimglist_for(oMesh.m_connect, elem)
170  {// for each element
171 
172  if (cropBox(oMesh, oImage, oField, elem, correlogram, offset))
173  {// if elem is unmasked
174 
175  if (oImage.m_storeField){field(oImage, oMesh, elem, offset, oField, current_res[thread]);}
176  if (oImage.m_storeDef){deformField(oImage, oMesh, elem, offset, oField, current_res[thread]);}
177  if (oImage.m_storeRes){residuField(oImage, oMesh, elem, offset, oField, current_res[thread]);}
178 
179  }
180  }
181 
182  }
183 
184  }//parallele
185 
186  }
187 
188  void actu_field(const Cimage<Timg> &oImage, const Cmesh<T,Timg> &oMesh, const int &elem, const CNpeak<T> &Peaks, Cfield<T,Timg> &oField)
189  {// actualizes fields adding current peak positions
190 
195  int x(0), y(0), z(0);
196  oField.m_mode[0].contains((oField.m_mode[0])[elem], x,y,z);
197 
198  cimglist_for(oField.m_mode, L)
199  {//fill output field
200 
201  for (int c=0; c<oMesh.grid_dims(3); ++c)
202  {//for desired number of peak
203 
204  if (L>1)
205  {
206  oField.m_mode(L,x,y,z,c) = (floor(oField.m_mode(L,x,y,z,c)/oImage.m_pix[L-2]) + Peaks.m_Nstat(L,0,0,0,c))*oImage.m_pix[L-2];
207  }
208  else
209  {
210  oField.m_mode(L,x,y,z,c) = Peaks.m_Nstat(L,0,0,0,c);
211  }
212 
213  }
214 
215  }
216 
217  }
218 
219  void residual(const Cimage<Timg> &oImage, const Cmesh<T,Timg> &oMesh, const int &elem, const std::vector<T> &offset, Cfield<T,Timg> &oField, T &res)
220  {//Deformed image corrected using U,V,W per block
221 
222  std::vector<T> U;U.assign(3,0);
223 
224  for (int dim=0; dim<oMesh.num_var(); dim++)
225  {
226  U[dim] = oField.m_mode[dim+2][elem]/oImage.m_pix[dim];
227  }
228 
229  for (int x=0; x<oMesh.m_win[0]; x++)
230  {
231  for (int y=0; y<oMesh.m_win[1]; y++)
232  {
233  for (int z=0; z<oMesh.m_win[2]; z++)
234  {
235 
236  if (oImage.m_curImg[0].contains(oImage.m_curImg(0,offset[0]+x, offset[1]+y, offset[2]+z)))
237  {
238  res += std::pow( (T)oImage.m_curImg(0, offset[0]+x, offset[1]+y, offset[2]+z,0) - (T)oImage.m_curImg[1].linear_atXYZ(offset[0]+x+U[0],offset[1]+y+U[1], offset[2]+z+U[2],0, oImage.m_curImg(0, offset[0]+x, offset[1]+y, offset[2]+z,0)) ,2);
239  }
240 
241  }
242  }
243  }
244 
245  }
246 
247  void deformField(const Cimage<Timg> &oImage, const Cmesh<T,Timg> &oMesh, const int &elem, const std::vector<T> &offset, Cfield<T,Timg> &oField, T &res)
248  {//compute corrected deformed image
249 
250  std::vector<T> U;U.assign(3,0);
251 
252  for (int dim=0; dim<oMesh.num_var(); dim++)
253  {
254  U[dim] = oField.m_mode[dim+2][elem];
255  }
256 
257  for (int x=0; x<oMesh.m_win[0]; x++)
258  {
259  for (int y=0; y<oMesh.m_win[1]; y++)
260  {
261  for (int z=0; z<oMesh.m_win[2]; z++)
262  {
263  if (oImage.m_curImg[0].contains(oImage.m_curImg(0,offset[0]+x, offset[1]+y, offset[2]+z)))
264  {
265  oField.m_def(offset[0]+x, offset[1]+y, offset[2]+z) = oImage.m_curImg[1].linear_atXYZ(offset[0]+x+U[0]/oImage.m_pix[0],offset[1]+y+U[1]/oImage.m_pix[1], offset[2]+z+U[2]/oImage.m_pix[2],0,oImage.m_curImg(0,offset[0]+x, offset[1]+y, offset[2]+z));
266  }
267  }
268  }
269  }
270 
271 
272  }
273 
274  void residuField(const Cimage<Timg> &oImage, const Cmesh<T,Timg> &oMesh, const int &elem, const std::vector<T> &offset, Cfield<T,Timg> &oField, T &res)
275  {//compute the difference between the reference and the corrected deformed image (% of the init residue)
276 
277  std::vector<T> U;U.assign(3,0);
278 
279  for (int dim=0; dim<oMesh.num_var(); dim++)
280  {
281  U[dim] = oField.m_mode[dim+2][elem];
282  }
283 
284  for (int x=0; x<oMesh.m_win[0]; x++)
285  {
286  for (int y=0; y<oMesh.m_win[1]; y++)
287  {
288  for (int z=0; z<oMesh.m_win[2]; z++)
289  {
290  if (oImage.m_curImg[0].contains(oImage.m_curImg(0,offset[0]+x, offset[1]+y, offset[2]+z)))
291  {
292  oField.m_res(offset[0]+x, offset[1]+y, offset[2]+z) = oImage.m_curImg(0,offset[0]+x, offset[1]+y, offset[2]+z) - oImage.m_curImg[1].linear_atXYZ(offset[0]+x+U[0]/oImage.m_pix[0],offset[1]+y+U[1]/oImage.m_pix[1], offset[2]+z+U[2]/oImage.m_pix[2],0,oImage.m_curImg(0, offset[0]+x, offset[1]+y, offset[2]+z));
293  }
294  }
295  }
296  }
297 
298  }
299 
300  void field(const Cimage<Timg> &oImage, const Cmesh<T,Timg> &oMesh, const int &elem, const std::vector<T> &offset, Cfield<T,Timg> &oField, T &res)
301  {//Deformed image corrected using U,V,W per block
302 
303  std::vector<T> U;U.assign(3,0);
304 
305  for (int dim=0; dim<oMesh.num_var(); dim++)
306  {
307  U[dim] = oField.m_mode[dim+2][elem];
308  }
309 
310  for (int x=0; x<oMesh.m_win[0]; x++)
311  {
312  for (int y=0; y<oMesh.m_win[1]; y++)
313  {
314  for (int z=0; z<oMesh.m_win[2]; z++)
315  {
316 
317  if (oImage.m_curImg[0].contains(oImage.m_curImg(0,offset[0]+x, offset[1]+y, offset[2]+z)))
318  {
319  cimglist_for(oField.m_field, var)
320  {
321  oField.m_field(var,offset[0]+x, offset[1]+y, offset[2]+z) = U[var];
322  }
323  }
324  }
325  }
326  }
327 
328  }
329 
330  int cropBox(const Cmesh<T,Timg> &oMesh, const Cimage<Timg> &oImage, const Cfield<T,Timg> &oField, const int &elem, CImgList<T> &box, std::vector<T> &coord0)
331  {//crop 2 sub_image within oImage.m_img[0-1]
332 
337  std::vector<T> coord1;
338  coord0.assign(3,0);
339  coord1.assign(3,0);
340  cimglist_for(box,im){box[im].fill(1);}
341  int msk(0);
342 
343  //Upper left and lower right corners coordonates and rigid displacement of centroid
344  cimglist_for(oMesh.m_node, dim)
345  {
346  coord0[dim] = oMesh.m_node[dim][oMesh.m_connect[elem].front()] - oMesh.m_win[dim]/2;
347  coord1[dim] = coord0[dim] + oMesh.m_win[dim] - 1;
348  }
349 
350  if (!oImage.m_curMask.is_empty())
351  {box[0].draw_image(0,0,0,0,oImage.m_curMask.get_crop(coord0[0],coord0[1],coord0[2],0,coord1[0],coord1[1],coord1[2],0,0));}
352 
353  if (box[0].mean() > 0.5)
354  {//if the box contain at least one unmasked pixel
355 
356  std::vector<int> U;U.assign(3,0);
357  cimglist_for(oMesh.m_node, dim)
358  {U[dim] = floor(oField.m_mode[dim + 2][elem]/oImage.m_pix[dim]);}
359 
360  cimg_forXYZ(box[0], x,y,z)
361  {//if a box is analysed the entire in-bound image is taken into account
362 
363  if (oImage.m_curImg[0].contains(oImage.m_curImg(0,coord0[0]+x,coord0[1]+y,coord0[2]+z,0)))
364  {box(0, x,y,z) = oImage.m_curImg(0, coord0[0]+x,coord0[1]+y,coord0[2]+z);}
365  else
366  {box(0, x,y,z) = this->m_meanVal;}
367 
368  if (oImage.m_curImg[1].contains(oImage.m_curImg(1,coord0[0]+U[0]+x,coord0[1]+U[1]+y,coord0[2]+U[2]+z,0)))
369  {box(1, x,y,z) = oImage.m_curImg(1, coord0[0]+U[0]+x,coord0[1]+U[1]+y,coord0[2]+U[2]+z);}
370  else
371  {box(1, x,y,z) = box(0, x,y,z);}
372 
373  }
374 
375  msk = 1;
376 
377 
378  }
379 
380  return msk;
381 
382  }
383 
384 
385  virtual void correl(CImgList<T> &correlogram, CImgList<T> &F, CImgList<T> &G) = 0;
386 
387 
388  void FFT(CImgList<T> &correlogram, CImgList<T> &F, CImgList<T> &G)
389  {//FFT in place
390 
391  correlogram[0].FFT(F[0],F[1]);
392  correlogram[0].FFT(G[0],G[1]);
393 
394  }
395 
396  void iFFT(CImgList<T> &correlogram)
397  {//ifft
398 
399  correlogram[0].FFT(correlogram[0],correlogram[1],true);
400 
401  }
402 
403  void shift(CImgList<T> &correlogram)
404  {//shift correlogram cadran
405 
406  std::vector<float> offset;
407  offset.assign(4,0);
408 
409  offset[0] = (float)correlogram[0].width()/2;
410  offset[1] = (float)correlogram[0].height()/2;
411  if(this->_3D){offset[2] = (float)correlogram[0].depth()/2;}
412 
413  cimglist_for(correlogram,L)
414  {
415  correlogram[L].shift(offset[0],offset[1],offset[2],offset[3],2);//boundary condition : Fourier expansion
416  }
417 
418  }
419 
420  virtual void interCor(CImgList<T> &correlogram, CImgList<T> &F, CImgList<T> &G)
421  {//inter-correlation
422 
423  cimg_forXYZ(correlogram[0],x,y,z)
424  {
425  correlogram(0,x,y,z) = F(0,x,y,z)*G(0,x,y,z) + F(1,x,y,z)*G(1,x,y,z);
426  correlogram(1,x,y,z) = F(1,x,y,z)*G(0,x,y,z) - F(0,x,y,z)*G(1,x,y,z);
427  }
428 
429  }
430 
431  void mean(CImgList<T> &correlogram)
432  {//substract mean offset
433 
434  T mean0(correlogram[0].mean()), mean1(correlogram[1].mean());
435 
436  correlogram[0]-=mean0;
437  correlogram[1]-=mean1;
438 
439  }
440 
441 };
442 
443 #endif
Definition: CNpeak.h:55
void actu_field(const Cimage< Timg > &oImage, const Cmesh< T, Timg > &oMesh, const int &elem, const CNpeak< T > &Peaks, Cfield< T, Timg > &oField)
Definition: Ccorrelation_intercor.h:188
virtual void exec(const Cimage< Timg > &oImage, const Cmesh< T, Timg > &oMesh, Cfield< T, Timg > &oField)
Definition: Ccorrelation_intercor.h:78
this is the mother class of every correlation classes. m_correl_type refers to the the type of correl...
Definition: Ccorrelation.h:65
CImg< T > m_correlogram
to improve, they shouldn't be here//
Definition: Cfield.h:74
Definition: Cmesh.h:61
Definition: Cfield.h:51
virtual void init(CParameterNetCDF &fp)
Definition: Ccorrelation_intercor.h:61
Definition: Cimage.h:57
int cropBox(const Cmesh< T, Timg > &oMesh, const Cimage< Timg > &oImage, const Cfield< T, Timg > &oField, const int &elem, CImgList< T > &box, std::vector< T > &coord0)
Definition: Ccorrelation_intercor.h:330
this class implement 7 functions:
Definition: Ccorrelation_intercor.h:45