4444#include < Teuchos_LAPACK.hpp>
4545#include < Teuchos_SerialDenseMatrix.hpp>
4646
47+ #include < opencv2/core/core.hpp>
48+ #include < opencv2/highgui/highgui.hpp>
49+ #include < opencv2/imgcodecs.hpp>
50+ #include < opencv2/imgproc.hpp>
51+
4752#include < fstream>
4853
4954namespace DICe {
@@ -230,6 +235,216 @@ Post_Processor::initialize_neighborhood(const scalar_t & neighborhood_radius){
230235 DEBUG_MSG (" Post_Processor::initialize_neighborhood(): end" );
231236}
232237
238+ Crack_Locator_Post_Processor::Crack_Locator_Post_Processor (const Teuchos::RCP<Teuchos::ParameterList> & params) :
239+ Post_Processor (post_process_crack_locator){
240+ window_size_ = 25 ;
241+ ref_img_ = Teuchos::null;
242+ // no new fields added since the post processor writes output files instead
243+ DEBUG_MSG (" Enabling post processor Crack_Locator_Post_Processor with no new associated fields:" );
244+ set_params (params);
245+ }
246+
247+ void
248+ Crack_Locator_Post_Processor::set_params (const Teuchos::RCP<Teuchos::ParameterList> & params){
249+ window_size_ = params->get <int_t >(crack_locator_window_size,25 );
250+ DEBUG_MSG (" Crack_Locator_Post_Processor set_params(): using window size " << window_size_);
251+ }
252+
253+ void
254+ Crack_Locator_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img){
255+ DEBUG_MSG (" Crack_Locator_Post_Processor execute() begin" );
256+ assert (ref_img!=Teuchos::null);
257+ assert (def_img!=Teuchos::null);
258+ if (ref_img_==Teuchos::null) ref_img_ = Teuchos::rcp (new DICe::Image (ref_img)); // deep copy the reference image in case it gets modified or swapped later
259+ assert (ref_img_!=Teuchos::null);
260+ // get the image width and height:
261+ const int_t width = ref_img_->width ();
262+ const int_t height = ref_img_->height ();
263+
264+ // create opencv mat images, start with 16 bit then equalize the histogram
265+ cv::Mat ref = cv::Mat (height,width,CV_32FC1,cv::Scalar (0 ));
266+ cv::Mat def = cv::Mat (height,width,CV_32FC1,cv::Scalar (0 ));
267+ cv::Mat map = cv::Mat (height,width,CV_32FC1,cv::Scalar (0 ));
268+ // for(int_t y=0;y<height;++y){
269+ // for(int_t x=0;x<width;++x){
270+ // ref.at<float>(y,x) = 0.0f;
271+ // def.at<float>(y,x) = 0.0f;
272+ // def.at<float>(y,x) = 0.0f;
273+ // }
274+ // }
275+
276+
277+ // ensure only in serial for now TODO enable parallel post processor for this
278+ const int_t num_procs = mesh_->get_comm ()->get_size ();
279+ TEUCHOS_TEST_FOR_EXCEPTION (num_procs!=1 ,std::runtime_error," Plotly_Contour_Post_Processor only works in serial" );
280+
281+ // gather the current coordinates of the subsets with sigma>=0 or all valid points
282+ Teuchos::RCP<MultiField> coords_x = mesh_->get_field (DICe::field_enums::SUBSET_COORDINATES_X_FS);
283+ Teuchos::RCP<MultiField> coords_y = mesh_->get_field (DICe::field_enums::SUBSET_COORDINATES_Y_FS);
284+ Teuchos::RCP<MultiField> disp_x = mesh_->get_field (DICe::field_enums::SUBSET_DISPLACEMENT_X_FS);
285+ Teuchos::RCP<MultiField> disp_y = mesh_->get_field (DICe::field_enums::SUBSET_DISPLACEMENT_Y_FS);
286+ Teuchos::RCP<MultiField> sigma = mesh_->get_field (DICe::field_enums::SIGMA_FS);
287+
288+ // count the number of valid points
289+ int_t num_valid_pts = 0 ;
290+ for (int_t i=0 ;i<local_num_points_;++i)
291+ if (sigma->local_value (i)>=0.0 )
292+ num_valid_pts++;
293+ std::vector<int_t > local_ids (num_valid_pts,0 );
294+
295+ // create neighborhood lists using nanoflann:
296+ DEBUG_MSG (" creating the point cloud using nanoflann" );
297+ point_cloud_ = Teuchos::rcp (new Point_Cloud_2D<scalar_t >());
298+ point_cloud_->pts .resize (num_valid_pts);
299+ int_t current_pt = 0 ;
300+ for (int_t i=0 ;i<local_num_points_;++i){
301+ if (sigma->local_value (i)<0.0 ) continue ;
302+ point_cloud_->pts [current_pt].x = coords_x->local_value (i) + disp_x->local_value (i);
303+ point_cloud_->pts [current_pt].y = coords_y->local_value (i) + disp_y->local_value (i);
304+ local_ids[current_pt++] = i;
305+ }
306+ DEBUG_MSG (" building the kd-tree" );
307+ Teuchos::RCP<kd_tree_2d_t > kd_tree = Teuchos::rcp (new kd_tree_2d_t (2 /* dim*/ , *point_cloud_.get (), nanoflann::KDTreeSingleIndexAdaptorParams (10 /* max leaf */ ) ) );
308+ kd_tree->buildIndex ();
309+ DEBUG_MSG (" kd-tree completed" );
310+
311+ const int_t N = 3 ;
312+ int *IPIV = new int [N+1 ];
313+ int LWORK = N*N;
314+ int INFO = 0 ;
315+ double *WORK = new double [LWORK];
316+ double *GWORK = new double [10 *N];
317+ int *IWORK = new int [LWORK];
318+ // Note, LAPACK does not allow templating on long int or scalar_t...must use int and double
319+ Teuchos::LAPACK<int ,double > lapack;
320+ std::vector<std::pair<size_t ,scalar_t > > ret_matches;
321+ nanoflann::SearchParams params;
322+ params.sorted = true ; // sort by distance in ascending order
323+ const double neigh_rad_sq = window_size_*window_size_;
324+ scalar_t query_pt[2 ];
325+ // initialize value storage vector of vectors
326+ // iterate each pixel and find the closest displacement using least squares
327+ for (int_t y=0 ;y<height;++y){
328+ for (int_t x=0 ;x<width;++x){
329+ query_pt[0 ] = x;
330+ query_pt[1 ] = y;
331+ kd_tree->radiusSearch (&query_pt[0 ],neigh_rad_sq,ret_matches,params);
332+ const int_t num_neigh = ret_matches.size ();
333+ if (num_neigh<=3 ) continue ;
334+ // set up the X_t matrices
335+ Teuchos::SerialDenseMatrix<int_t ,double > X_t (N,num_neigh, true );
336+ Teuchos::SerialDenseMatrix<int_t ,double > X_t_X (N,N,true );
337+ for (int_t i=0 ;i<num_neigh;++i){
338+ X_t (0 ,i) = 1.0 ;
339+ X_t (1 ,i) = point_cloud_->pts [ret_matches[i].first ].x - x;// coords_x->local_value(local_ids[ret_matches[i].first]) - x;
340+ X_t (2 ,i) = point_cloud_->pts [ret_matches[i].first ].y - y;// coords_y->local_value(local_ids[ret_matches[i].first]) - y;
341+ }
342+ // set up X^T*X
343+ for (int_t k=0 ;k<N;++k){
344+ for (int_t m=0 ;m<N;++m){
345+ for (int_t j=0 ;j<num_neigh;++j){
346+ X_t_X (k,m) += X_t (k,j)*X_t (m,j);
347+ }
348+ }
349+ }
350+ // Invert X^T*X
351+ // TODO: remove for performance?
352+ // compute the 1-norm of H:
353+ std::vector<double > colTotals (X_t_X.numCols (),0.0 );
354+ for (int_t i=0 ;i<X_t_X.numCols ();++i){
355+ for (int_t j=0 ;j<X_t_X.numRows ();++j){
356+ colTotals[i]+=std::abs (X_t_X (j,i));
357+ }
358+ }
359+ double anorm = 0.0 ;
360+ for (int_t i=0 ;i<X_t_X.numCols ();++i){
361+ if (colTotals[i] > anorm) anorm = colTotals[i];
362+ }
363+ lapack.GETRF (X_t_X.numRows (),X_t_X.numCols (),X_t_X.values (),X_t_X.numRows (),IPIV,&INFO);
364+ double rcond=0.0 ; // reciporical condition number
365+ lapack.GECON (' 1' ,X_t_X.numRows (),X_t_X.values (),X_t_X.numRows (),anorm,&rcond,GWORK,IWORK,&INFO);
366+ if (rcond < 1.0E-12 ) continue ;
367+ lapack.GETRI (X_t_X.numRows (),X_t_X.values (),X_t_X.numRows (),IPIV,WORK,LWORK,&INFO);
368+
369+ Teuchos::ArrayRCP<double > u (num_neigh,0.0 );
370+ Teuchos::ArrayRCP<double > v (num_neigh,0.0 );
371+ for (int_t j=0 ;j<num_neigh;++j){
372+ u[j] = -1.0 *disp_x->local_value (local_ids[ret_matches[j].first ]);
373+ v[j] = -1.0 *disp_y->local_value (local_ids[ret_matches[j].first ]);
374+ }
375+ // compute X^T*u
376+ Teuchos::ArrayRCP<double > X_t_u (N,0.0 );
377+ Teuchos::ArrayRCP<double > X_t_v (N,0.0 );
378+ for (int_t k=0 ;k<N;++k)
379+ for (int_t j=0 ;j<num_neigh;++j){
380+ X_t_u[k] += X_t (k,j)*u[j];
381+ X_t_v[k] += X_t (k,j)*v[j];
382+ }
383+
384+ // compute the coeffs
385+ Teuchos::ArrayRCP<double > coeffs_u (N,0.0 );
386+ Teuchos::ArrayRCP<double > coeffs_v (N,0.0 );
387+ for (int_t k=0 ;k<N;++k)
388+ for (int_t j=0 ;j<N;++j){
389+ coeffs_u[k] += X_t_X (k,j)*X_t_u[j];
390+ coeffs_v[k] += X_t_X (k,j)*X_t_v[j];
391+ }
392+
393+ const scalar_t x_loc = x + coeffs_u[0 ];
394+ const scalar_t y_loc = y + coeffs_v[0 ];
395+ if (x_loc>=0 &&x_loc<width&&y_loc>=0 &&y_loc<height){
396+ ref.at <float >(y,x) = (*ref_img_)(x,y);
397+ def.at <float >(y,x) = (*def_img)(x,y);
398+ map.at <float >(y,x) = ref_img_->interpolate_keys_fourth (x_loc,y_loc);
399+ }
400+ } // end y loop
401+ } // end x loop
402+
403+ // TODO write the output json file
404+ delete [] WORK;
405+ delete [] GWORK;
406+ delete [] IWORK;
407+ delete [] IPIV;
408+
409+ ref.convertTo (ref,CV_8UC1);
410+ def.convertTo (def,CV_8UC1);
411+ map.convertTo (map,CV_8UC1);
412+ cv::equalizeHist (ref,ref);
413+ cv::equalizeHist (def,def);
414+ cv::equalizeHist (map,map);
415+ std::stringstream filenameR;
416+ filenameR << " ref_" << current_frame_id_ << " .png" ;
417+ cv::imwrite (filenameR.str (),ref);
418+ std::stringstream filenameD;
419+ filenameD << " def_" << current_frame_id_ << " .png" ;
420+ cv::imwrite (filenameD.str (),def);
421+ std::stringstream filenameM;
422+ filenameM << " map_" << current_frame_id_ << " .png" ;
423+ cv::imwrite (filenameM.str (),map);
424+
425+ for (int_t y=0 ;y<height;++y){
426+ for (int_t x=0 ;x<width;++x){
427+ if (def.at <uchar>(y,x)<map.at <uchar>(y,x)){
428+ def.at <uchar>(y,x) = map.at <uchar>(y,x) - def.at <uchar>(y,x);
429+ }else {
430+ def.at <uchar>(y,x) = 0 .0f ;
431+ }
432+ }
433+ }
434+ // cv::absdiff(def,map,def);
435+ std::stringstream filenameDiff;
436+ filenameDiff << " diff_" << current_frame_id_ << " .png" ;
437+ cv::imwrite (filenameDiff.str (),def);
438+
439+ // set a threshold on how far away the nearest subset can be
440+ // do a diff using the displacement value
441+ // threshold the diff
442+ // output a json file with a heatmap?
443+
444+
445+ DEBUG_MSG (" Crack_Locator_Post_Processor execute() end" );
446+ }
447+
233448Plotly_Contour_Post_Processor::Plotly_Contour_Post_Processor (const Teuchos::RCP<Teuchos::ParameterList> & params) :
234449 Post_Processor (post_process_plotly_contour){
235450 // no new fields added since the post processor writes output files instead
@@ -244,7 +459,7 @@ Plotly_Contour_Post_Processor::set_params(const Teuchos::RCP<Teuchos::ParameterL
244459}
245460
246461void
247- Plotly_Contour_Post_Processor::execute (){
462+ Plotly_Contour_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img ){
248463 DEBUG_MSG (" Plotly_Contour_Post_Processor execute() begin" );
249464
250465 // ensure only in serial for now TODO enable parallel post processor for this
@@ -493,7 +708,7 @@ Plotly_Contour_Post_Processor::execute(){
493708 } // end gy loop
494709 } // end gx loop
495710
496- // TODO write the output json file
711+ // write the output json file
497712 delete [] WORK;
498713 delete [] GWORK;
499714 delete [] IWORK;
@@ -658,7 +873,7 @@ VSG_Strain_Post_Processor::pre_execution_tasks(){
658873}
659874
660875void
661- VSG_Strain_Post_Processor::execute (){
876+ VSG_Strain_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img ){
662877 DEBUG_MSG (" VSG_Strain_Post_Processor execute() begin" );
663878 if (!neighborhood_initialized_) pre_execution_tasks ();
664879
@@ -934,7 +1149,7 @@ NLVC_Strain_Post_Processor::compute_kernel(const scalar_t & dx,
9341149
9351150
9361151void
937- NLVC_Strain_Post_Processor::execute (){
1152+ NLVC_Strain_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img ){
9381153 DEBUG_MSG (" NLVC_Strain_Post_Processor execute() begin" );
9391154 if (!neighborhood_initialized_) pre_execution_tasks ();
9401155
@@ -1074,7 +1289,7 @@ Altitude_Post_Processor::Altitude_Post_Processor(const Teuchos::RCP<Teuchos::Par
10741289}
10751290
10761291void
1077- Altitude_Post_Processor::execute (){
1292+ Altitude_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img ){
10781293 DEBUG_MSG (" Altitude_Post_Processor::execute(): begin" );
10791294
10801295// Teuchos::RCP<DICe::MultiField> ground_level_rcp = mesh_->get_field(DICe::field_enums::GROUND_LEVEL_FS);
@@ -1234,7 +1449,7 @@ Uncertainty_Post_Processor::Uncertainty_Post_Processor(const Teuchos::RCP<Teucho
12341449}
12351450
12361451void
1237- Uncertainty_Post_Processor::execute (){
1452+ Uncertainty_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img ){
12381453 DEBUG_MSG (" Uncertainty_Post_Processor::execute(): begin" );
12391454
12401455 Teuchos::RCP<DICe::MultiField> sigma_rcp = mesh_->get_field (DICe::field_enums::SIGMA_FS);
@@ -1586,7 +1801,7 @@ Live_Plot_Post_Processor::pre_execution_tasks(){
15861801}
15871802
15881803void
1589- Live_Plot_Post_Processor::execute (){
1804+ Live_Plot_Post_Processor::execute (Teuchos::RCP<Image> ref_img, Teuchos::RCP<Image> def_img ){
15901805 DEBUG_MSG (" Live_Plot_Post_Processor execute() begin" );
15911806 if (!neighborhood_initialized_) pre_execution_tasks ();
15921807
0 commit comments