35 #ifndef MOSAIC_REFINEMENT_COMMON_HXX_
36 #define MOSAIC_REFINEMENT_COMMON_HXX_
39 #include <Core/ITKCommon/common.hxx>
40 #include <Core/ITKCommon/grid_common.hxx>
41 #include <Core/ITKCommon/Optimizers/itkImageMosaicVarianceMetric.h>
42 #include <Core/ITKCommon/Optimizers/itkRegularStepGradientDescentOptimizer2.h>
43 #include <Core/ITKCommon/the_aa_bbox.hxx>
44 #include <Core/ITKCommon/ThreadUtils/the_thread_pool.hxx>
60 regularize_displacements(
62 std::vector<vec2d_t> & xy_shift,
63 std::vector<double> & mass,
65 image_t::Pointer & dx,
66 image_t::Pointer & dy,
67 image_t::Pointer & db,
70 const unsigned int & median_radius);
76 template <
class TImage,
class TMask>
79 array2d(
typename TImage::Pointer) & pyramid,
80 std::vector<typename TMask::ConstPointer> & mask,
81 std::vector<base_transform_t::Pointer> & transform,
83 unsigned int iterations_per_level)
85 typedef itk::LinearInterpolateImageFunction<TImage, double> interpolator_t;
87 unsigned int pyramid_levels = pyramid.size();
88 if (pyramid_levels == 0)
return;
90 std::vector<typename TImage::Pointer> & image = pyramid[pyramid_levels - 1];
91 unsigned int num_images = image.size();
92 if (num_images == 0)
return;
94 std::ostringstream oss;
95 oss <<
"iterations per level: " << iterations_per_level << std::endl
96 <<
"transform type: " << transform[0]->GetTransformTypeAsString()
103 typename mosaic_metric_t::Pointer mosaic_metric = mosaic_metric_t::New();
104 mosaic_metric->image_.resize(num_images);
105 mosaic_metric->mask_.resize(num_images);
106 mosaic_metric->transform_.resize(num_images);
107 for (
unsigned int i = 0; i < num_images; i++)
109 mosaic_metric->image_[i] = image[i];
110 mosaic_metric->mask_[i] = mask[i];
111 mosaic_metric->transform_[i] = transform[i];
115 std::vector<bool> param_shared(transform[0]->GetNumberOfParameters(),
false);
116 std::vector<bool> param_active(transform[0]->GetNumberOfParameters(),
true);
119 mosaic_metric->setup_param_map(param_shared, param_active);
120 mosaic_metric->Initialize();
123 typename mosaic_metric_t::params_t parameter_scales =
124 mosaic_metric->GetTransformParameters();
125 parameter_scales.Fill(1.0);
127 for (
unsigned int level = 0;
128 level < pyramid_levels && iterations_per_level > 0;
131 for (
unsigned int i = 0; i < num_images; i++)
133 mosaic_metric->image_[i] = pyramid[level][i];
136 typename mosaic_metric_t::measure_t metric_before =
137 mosaic_metric->GetValue(mosaic_metric->GetTransformParameters());
140 for (
unsigned int k = 0; k < 3; k++)
142 typename mosaic_metric_t::params_t params_before =
143 mosaic_metric->GetTransformParameters();
145 typename mosaic_metric_t::measure_t metric_after =
146 std::numeric_limits<typename mosaic_metric_t::measure_t>::max();
149 optimizer_t::Pointer optimizer = optimizer_t::New();
150 typename optimizer_observer_t<optimizer_t>::Pointer observer =
152 optimizer->AddObserver(itk::IterationEvent(), observer);
153 optimizer->SetMinimize(
true);
154 optimizer->SetNumberOfIterations(iterations_per_level);
155 optimizer->SetMinimumStepLength(1e-12);
156 optimizer->SetMaximumStepLength(1e-5);
157 optimizer->SetGradientMagnitudeTolerance(1e-6);
158 optimizer->SetRelaxationFactor(5e-1);
159 optimizer->SetCostFunction(mosaic_metric);
160 optimizer->SetInitialPosition(params_before);
161 optimizer->SetScales(parameter_scales);
162 optimizer->SetPickUpPaceSteps(5);
163 optimizer->SetBackTracking(
true);
168 oss <<
"\n" << level <<
'.' << k <<
": refining distortion transforms"
171 optimizer->StartOptimization();
173 catch (itk::ExceptionObject & exception)
176 oss <<
"optimizer threw an exception:" << std::endl << exception.what() << std::endl;
179 mosaic_metric->SetTransformParameters(optimizer->GetBestParams());
180 metric_after = optimizer->GetBestValue();
182 typename mosaic_metric_t::params_t params_after =
183 mosaic_metric->GetTransformParameters();
185 oss <<
"before: METRIC = " << metric_before
186 <<
", PARAMS = " << params_before << std::endl
187 <<
"after: METRIC = " << metric_after
188 <<
", PARAMS = " << params_after << std::endl;
191 double improvement = 1.0 - metric_after / metric_before;
192 bool failed_to_improve = (metric_after - metric_before) >= 0.0;
193 bool negligible_improvement = !failed_to_improve && (improvement < 1e-3);
195 if (!failed_to_improve)
197 oss <<
"IMPROVEMENT: " << std::setw(3) <<
static_cast<double>(100.0 * improvement)
201 if (failed_to_improve)
203 oss <<
"NOTE: minimization failed, ignoring registration results..."
207 mosaic_metric->SetTransformParameters(params_before);
210 else if (negligible_improvement)
212 oss <<
"NOTE: improvement is negligible..." << std::endl;
217 metric_before = metric_after;
220 CORE_LOG_MESSAGE(oss.str());
229 template <
typename TImage,
typename TMask>
233 std::vector<vec2d_t> & xy_shift,
234 std::vector<double> & mass,
238 bool tiles_already_warped,
241 const TImage * tile_0,
242 const TMask * mask_0,
243 const base_transform_t * forward_0,
246 const TImage * tile_1,
247 const TMask * mask_1,
251 const unsigned int & neighborhood,
254 const double & min_overlap,
257 const unsigned int & median_radius)
261 unsigned int mesh_cols = gt.cols_ + 1;
262 unsigned int mesh_rows = gt.rows_ + 1;
263 unsigned mesh_size = gt.grid_.mesh_.size();
264 xy_shift.assign(mesh_size, vec2d(0, 0));
267 typename TImage::SpacingType sp = tile_1->GetSpacing();
268 if (sp != tile_0->GetSpacing())
return;
271 typename TImage::SizeType sz;
272 sz[0] = neighborhood;
273 sz[1] = neighborhood;
275 typename TImage::Pointer img[] = {
276 make_image<TImage>(sp, sz),
277 make_image<TImage>(sp, sz)
280 typename TMask::Pointer msk[] = {
281 make_image<TMask>(sp, sz),
282 make_image<TMask>(sp, sz)
287 image_t::Pointer dx = make_image<image_t>(mesh_cols,
292 image_t::Pointer dy = make_image<image_t>(mesh_cols,
297 image_t::Pointer db = make_image<image_t>(mesh_cols,
302 typename TImage::Pointer img_large;
303 typename TMask::Pointer msk_large;
305 if (!tiles_already_warped)
307 typename TImage::SizeType sz_large(sz);
310 img_large = make_image<TImage>(sp, sz_large);
311 msk_large = make_image<TMask>(sp, sz_large);
314 std::ostringstream oss;
315 oss <<
"- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << std::endl;
316 for (
unsigned int i = 0; i < mesh_size; i++)
319 const vertex_t & vertex = gt.grid_.mesh_[i];
323 gt.transform_inv(vertex.uv_, center);
326 image_t::IndexType index;
327 index[0] = i % mesh_cols;
328 index[1] = i / mesh_cols;
329 dx->SetPixel(index, 0);
330 dy->SetPixel(index, 0);
331 db->SetPixel(index, 0);
334 vec2d_t shift(vec2d(0, 0));
335 bool ok = tiles_already_warped ?
337 refine_one_point_fft(shift,
352 msk[1].GetPointer()) :
354 refine_one_point_fft(shift,
371 img_large.GetPointer(),
372 msk_large.GetPointer(),
378 msk[1].GetPointer());
384 oss << i <<
". shift: " << shift << std::endl;
385 dx->SetPixel(index, shift[0]);
386 dy->SetPixel(index, shift[1]);
387 db->SetPixel(index, 1);
391 regularize_displacements(xy_shift, mass, dx, dy, db, median_radius);
392 CORE_LOG_MESSAGE(oss.str());
400 template <
typename TImage,
typename TMask>
406 bool tiles_already_warped,
409 const TImage * tile_0,
410 const TMask * mask_0,
411 const base_transform_t * forward_0,
414 const TImage * tile_1,
415 const TMask * mask_1,
419 const unsigned int & neighborhood_size,
422 const double & min_overlap,
432 const std::list<image_t::IndexType> & index,
435 const std::list<pnt2d_t> & center):
436 tiles_already_warped_(tiles_already_warped),
440 forward_0_(forward_0),
444 forward_1_(forward_1),
446 min_overlap_(min_overlap),
452 index_(index.begin(), index.end()),
453 center_(center.begin(), center.end())
456 sp_ = tile_1->GetSpacing();
457 bool ok = (sp_ == tile_0->GetSpacing());
465 sz_[0] = neighborhood_size;
466 sz_[1] = neighborhood_size;
474 typename TImage::Pointer img[] = {
475 make_image<TImage>(sp_, sz_),
476 make_image<TImage>(sp_, sz_)
479 typename TMask::Pointer msk[] = {
480 make_image<TMask>(sp_, sz_),
481 make_image<TMask>(sp_, sz_)
484 typename TImage::Pointer img_large;
485 typename TMask::Pointer msk_large;
487 if (!tiles_already_warped_)
489 typename TImage::SizeType sz_large(sz_);
492 img_large = make_image<TImage>(sp_, sz_large);
493 msk_large = make_image<TMask>(sp_, sz_large);
496 std::size_t num_nodes = center_.size();
497 for (std::size_t i = 0; i < num_nodes; i++)
500 const image_t::IndexType & index = index_[i];
501 const pnt2d_t & center = center_[i];
504 vec2d_t shift(vec2d(0, 0));
506 bool ok = tiles_already_warped_ ?
509 refine_one_point_fft(shift,
524 msk[1].GetPointer()) :
526 refine_one_point_fft(shift,
543 img_large.GetPointer(),
544 msk_large.GetPointer(),
550 msk[1].GetPointer());
553 dx_->SetPixel(index, shift[0]);
554 dy_->SetPixel(index, shift[1]);
555 db_->SetPixel(index, 1);
562 bool tiles_already_warped_;
565 const TImage * tile_0_;
566 const TMask * mask_0_;
567 const base_transform_t * forward_0_;
570 const TImage * tile_1_;
571 const TMask * mask_1_;
575 typename TImage::SpacingType sp_;
576 typename TImage::SizeType sz_;
579 const double min_overlap_;
582 image_t::Pointer dx_;
583 image_t::Pointer dy_;
586 image_t::Pointer db_;
589 std::vector<image_t::IndexType> index_;
592 std::vector<pnt2d_t> center_;
601 template <
typename TImage,
typename TMask>
603 calc_displacements_mt(
unsigned int num_threads,
607 std::vector<vec2d_t> & xy_shift,
608 std::vector<double> & mass,
612 bool tiles_already_warped,
615 const TImage * tile_0,
616 const TMask * mask_0,
617 const base_transform_t * forward_0,
620 const TImage * tile_1,
621 const TMask * mask_1,
625 const unsigned int & neighborhood_size,
628 const double & min_overlap,
631 const unsigned int & median_radius)
634 if (tile_1->GetSpacing() != tile_0->GetSpacing())
return;
638 unsigned int mesh_cols = gt.cols_ + 1;
639 unsigned int mesh_rows = gt.rows_ + 1;
640 unsigned mesh_size = gt.grid_.mesh_.size();
641 xy_shift.assign(mesh_size, vec2d(0, 0));
645 image_t::Pointer dx = make_image<image_t>(mesh_cols,
650 image_t::Pointer dy = make_image<image_t>(mesh_cols,
655 image_t::Pointer db = make_image<image_t>(mesh_cols,
661 thread_pool.set_idle_sleep_duration(50);
664 std::vector<std::list<image_t::IndexType> > node_index_list(num_threads);
665 std::vector<std::list<pnt2d_t> > node_center_list(num_threads);
667 for (
unsigned int i = 0; i < mesh_size; i++)
670 const vertex_t & vertex = gt.grid_.mesh_[i];
671 const unsigned int which_thread = i % num_threads;
675 gt.transform_inv(vertex.uv_, center);
676 node_center_list[which_thread].push_back(center);
679 image_t::IndexType index;
680 index[0] = i % mesh_cols;
681 index[1] = i / mesh_cols;
682 dx->SetPixel(index, 0);
683 dy->SetPixel(index, 0);
684 db->SetPixel(index, 0);
686 node_index_list[which_thread].push_back(index);
690 for (
unsigned int i = 0; i < num_threads; i++)
711 node_center_list[i]);
713 thread_pool.push_back(t);
717 thread_pool.pre_distribute_work();
723 regularize_displacements(xy_shift, mass, dx, dy, db, median_radius);
742 unsigned int mesh_rows,
743 unsigned int mesh_cols):
748 for (
unsigned int i = 0; i < num_neighbors; i++)
750 dx_[i] = make_image<image_t>(mesh_cols,
755 dy_[i] = make_image<image_t>(mesh_cols,
760 db_[i] = make_image<image_t>(mesh_cols,
771 dx_.resize(r.dx_.size());
772 for (
unsigned int i = 0; i < dx_.size(); i++)
774 dx_[i] = cast<image_t, image_t>(r.dx_[i]);
777 dy_.resize(r.dy_.size());
778 for (
unsigned int i = 0; i < dy_.size(); i++)
780 dy_[i] = cast<image_t, image_t>(r.dy_[i]);
783 db_.resize(r.db_.size());
784 for (
unsigned int i = 0; i < db_.size(); i++)
786 db_[i] = cast<image_t, image_t>(r.db_[i]);
793 std::vector<image_t::Pointer> dx_;
794 std::vector<image_t::Pointer> dy_;
795 std::vector<image_t::Pointer> db_;
801 template <
typename img_ptr_t,
typename msk_ptr_t>
805 typedef typename img_ptr_t::ObjectType::Pointer::ObjectType TImage;
806 typedef typename msk_ptr_t::ObjectType::Pointer::ObjectType TMask;
809 unsigned int thread_stride,
810 std::vector<itk::GridTransform::Pointer> & transform,
811 const std::vector<img_ptr_t> & warped_tile,
812 const std::vector<msk_ptr_t> & warped_mask,
814 const bool & tiles_already_warped,
815 const unsigned int & neighborhood_size,
816 const double & minimum_overlap,
817 const bool & keep_first_tile_fixed,
818 std::vector<intermediate_result_t> & results):
820 thread_offset_(thread_offset),
821 thread_stride_(thread_stride),
822 transform_(transform),
823 warped_tile_(warped_tile),
824 warped_mask_(warped_mask),
825 neighbors_(neighbors),
826 tiles_already_warped_(tiles_already_warped),
827 neighborhood_(neighborhood_size),
828 minimum_overlap_(minimum_overlap),
829 keep_first_tile_fixed_(keep_first_tile_fixed),
838 unsigned int num_tiles = warped_tile_.size();
839 unsigned int start = keep_first_tile_fixed_ ? 1 : 0;
842 typename TImage::SpacingType sp = warped_tile_[start]->GetSpacing();
843 typename TImage::SizeType sz;
844 sz[0] = neighborhood_;
845 sz[1] = neighborhood_;
847 typename TImage::Pointer img[] = {
848 make_image<TImage>(sp, sz),
849 make_image<TImage>(sp, sz)
852 typename TMask::Pointer msk[] = {
853 make_image<TMask>(sp, sz),
854 make_image<TMask>(sp, sz)
857 typename TImage::Pointer img_large;
858 typename TMask::Pointer msk_large;
860 if (!tiles_already_warped_)
862 typename TImage::SizeType sz_large(sz);
865 img_large = make_image<TImage>(sp, sz_large);
866 msk_large = make_image<TMask>(sp, sz_large);
869 std::ostringstream oss;
870 for (
unsigned int tile_index = start; tile_index < num_tiles; tile_index++)
873 const unsigned int num_neighbors = neighbors_[tile_index].size();
874 const TImage * tile = warped_tile_[tile_index];
875 const TMask * mask = warped_mask_[tile_index];
879 const unsigned int mesh_cols = gt.cols_ + 1;
880 const unsigned int mesh_size = gt.grid_.mesh_.size();
885 for (
unsigned int neighbor = 0; neighbor < num_neighbors; neighbor++)
887 WRAP(terminator.terminate_on_request());
890 image_t::Pointer & dx = results.dx_[neighbor];
891 image_t::Pointer & dy = results.dy_[neighbor];
892 image_t::Pointer & db = results.db_[neighbor];
894 const unsigned int neighbor_index = neighbors_[tile_index][neighbor];
895 oss << thread_offset_ <<
" thread, matching "
896 << tile_index <<
":" << neighbor_index << std::endl;
899 const TImage * neighbor_tile = warped_tile_[neighbor_index];
900 const TMask * neighbor_mask = warped_mask_[neighbor_index];
901 const base_transform_t * neighbor_xform = transform_[neighbor_index];
903 for (
unsigned int mesh_index = thread_offset_;
904 mesh_index < mesh_size;
905 mesh_index += thread_stride_)
908 const vertex_t & vertex = gt.grid_.mesh_[mesh_index];
912 gt.transform_inv(vertex.uv_, center);
915 image_t::IndexType index;
916 index[0] = mesh_index % mesh_cols;
917 index[1] = mesh_index / mesh_cols;
918 dx->SetPixel(index, 0);
919 dy->SetPixel(index, 0);
920 db->SetPixel(index, 0);
923 vec2d_t shift(vec2d(0, 0));
924 bool ok = tiles_already_warped_ ?
926 refine_one_point_fft(shift,
943 msk[1].GetPointer()) :
945 refine_one_point_fft(shift,
964 img_large.GetPointer(),
965 msk_large.GetPointer(),
971 msk[1].GetPointer());
977 dx->SetPixel(index, shift[0]);
978 dy->SetPixel(index, shift[1]);
979 db->SetPixel(index, 1);
983 CORE_LOG_MESSAGE(oss.str());
986 unsigned int thread_offset_;
987 unsigned int thread_stride_;
988 std::vector<itk::GridTransform::Pointer> & transform_;
989 const std::vector<img_ptr_t> & warped_tile_;
990 const std::vector<msk_ptr_t> & warped_mask_;
991 const std::vector<the_dynamic_array_t<unsigned int> > & neighbors_;
992 const bool tiles_already_warped_;
993 const unsigned int neighborhood_;
994 const double minimum_overlap_;
995 const bool keep_first_tile_fixed_;
996 std::vector<intermediate_result_t> & results_;
1007 bool keep_first_tile_fixed,
1008 unsigned int median_filter_radius,
1009 std::vector<itk::GridTransform::Pointer> & transform,
1010 std::vector<intermediate_result_t> & results):
1011 tile_index_(tile_index),
1012 keep_first_tile_fixed_(keep_first_tile_fixed),
1013 median_filter_radius_(median_filter_radius),
1014 transform_(transform),
1023 std::ostringstream oss;
1024 oss << tile_index_ <<
" mesh update" << std::endl;
1025 CORE_LOG_MESSAGE(oss.str());
1030 const unsigned int mesh_size = gt.grid_.mesh_.size();
1034 const unsigned int num_neighbors = results.dx_.size();
1036 std::vector<vec2d_t> shift(mesh_size, vec2d(0, 0));
1037 std::vector<double> mass(mesh_size, 0);
1039 for (
unsigned int neighbor = 0; neighbor < num_neighbors; neighbor++)
1041 WRAP(terminator.terminate_on_request());
1044 image_t::Pointer & dx = results.dx_[neighbor];
1045 image_t::Pointer & dy = results.dy_[neighbor];
1046 image_t::Pointer & db = results.db_[neighbor];
1048 std::vector<vec2d_t> neighbor_pull(mesh_size, vec2d(0, 0));
1049 regularize_displacements(neighbor_pull,
1054 median_filter_radius_);
1057 for (
unsigned int i = 0; i < mesh_size; i++)
1059 shift[i] += neighbor_pull[i];
1064 if (!keep_first_tile_fixed_)
1067 for (
unsigned int i = 0; i < mesh_size; i++)
1069 double scale = 1 / (1 + mass[i]);
1074 gt.grid_.update(&(shift[0]));
1075 transform->setup(gt);
1078 const unsigned int tile_index_;
1079 const bool keep_first_tile_fixed_;
1080 const unsigned int median_filter_radius_;
1081 std::vector<itk::GridTransform::Pointer> & transform_;
1082 std::vector<intermediate_result_t> & results_;
1091 template <
typename img_ptr_t,
typename msk_ptr_t>
1093 refine_mosaic(std::vector<itk::GridTransform::Pointer> & transform,
1094 const std::vector<img_ptr_t> & tile,
1095 const std::vector<msk_ptr_t> & mask,
1096 const unsigned int & neighborhood,
1097 const bool & prewarp_tiles =
true,
1098 const double & minimum_overlap = 0.25,
1099 const unsigned int & median_radius = 1,
1100 const unsigned int & num_passes = 1,
1101 const bool & keep_first_tile_fixed =
false)
1104 typedef typename img_ptr_t::ObjectType::Pointer::ObjectType TImage;
1105 typedef typename msk_ptr_t::ObjectType::Pointer::ObjectType TMask;
1108 unsigned int num_tiles = tile.size();
1109 if (num_tiles < 2)
return;
1112 std::vector<pnt2d_t> image_min;
1113 std::vector<pnt2d_t> image_max;
1114 calc_image_bboxes<img_ptr_t>(tile, image_min, image_max);
1117 std::vector<pnt2d_t> mosaic_min;
1118 std::vector<pnt2d_t> mosaic_max;
1119 calc_mosaic_bboxes<pnt2d_t, itk_grid_transform_t::Pointer>(transform,
1126 unsigned int start = keep_first_tile_fixed ? 1 : 0;
1129 std::vector<the_dynamic_array_t<unsigned int> > neighbors(num_tiles);
1130 for (
unsigned int i = start; i < num_tiles; i++)
1133 ibox <<
p3x1_t(mosaic_min[i][0], mosaic_min[i][1], 0)
1134 <<
p3x1_t(mosaic_max[i][0], mosaic_max[i][1], 0);
1136 for (
unsigned int j = 0; j < num_tiles; j++)
1138 if (i == j)
continue;
1141 jbox <<
p3x1_t(mosaic_min[j][0], mosaic_min[j][1], 0)
1142 <<
p3x1_t(mosaic_max[j][0], mosaic_max[j][1], 0);
1144 if (!ibox.intersects(jbox))
continue;
1146 neighbors[i].push_back(j);
1150 std::vector<typename TImage::Pointer> warped_tile(num_tiles);
1151 std::vector<typename TMask::Pointer> warped_mask(num_tiles);
1153 if (keep_first_tile_fixed)
1155 warped_tile[0] = tile[0];
1156 warped_mask[0] =
const_cast<TMask *
>(mask[0].GetPointer());
1159 std::ostringstream oss;
1160 for (
unsigned int pass = 0; pass < num_passes; pass++)
1162 oss <<
"--------------------------- pass " << pass
1163 <<
" ---------------------------" << std::endl;
1168 for (
unsigned int i = start; i < num_tiles; i++)
1170 oss << std::setw(4) << i <<
". warping image tile" << std::endl;
1171 warped_tile[i] = warp<TImage>(tile[i], transform[i].GetPointer());
1173 if (mask[i].GetPointer() != NULL)
1175 oss <<
" warping image tile mask" << std::endl;
1176 warped_mask[i] = warp<TMask>(mask[i], transform[i].GetPointer());
1181 std::vector<std::vector<vec2d_t> > shift(num_tiles);
1182 for (
unsigned int i = start; i < num_tiles; i++)
1185 unsigned int mesh_size = gt.grid_.mesh_.size();
1187 std::vector<std::vector<vec2d_t> > shift_i(neighbors[i].size());
1188 std::vector<double> mass(mesh_size, 0);
1190 for (
unsigned int k = 0; k < neighbors[i].size(); k++)
1192 unsigned int j = neighbors[i][k];
1193 oss <<
"matching " << i <<
":" << j << std::endl;
1195 calc_displacements<TImage, TMask>(shift_i[k],
1204 transform[j].GetPointer(),
1209 transform[i].GetPointer(),
1217 shift[i].assign(mesh_size, vec2d(0, 0));
1219 for (
unsigned int j = 0; j < shift_i.size(); j++)
1221 for (
unsigned int k = 0; k < mesh_size; k++)
1223 shift[i][k] += shift_i[j][k];
1227 if (!keep_first_tile_fixed)
1230 for (
unsigned int k = 0; k < mesh_size; k++)
1232 double scale = 1 / (1 + mass[k]);
1233 shift[i][k] *= scale;
1238 for (
unsigned int i = start; i < num_tiles; i++)
1241 gt.grid_.update(&(shift[i][0]));
1242 transform[i]->setup(gt);
1245 CORE_LOG_MESSAGE(oss.str());
1252 template <
typename img_ptr_t,
typename msk_ptr_t>
1256 typedef typename img_ptr_t::ObjectType::Pointer::ObjectType TImage;
1257 typedef typename msk_ptr_t::ObjectType::Pointer::ObjectType TMask;
1260 const std::vector<itk::GridTransform::Pointer> &
1262 const std::vector<img_ptr_t> & tile,
1263 const std::vector<msk_ptr_t> & mask,
1264 std::vector<typename TImage::Pointer> & warped_tile,
1265 std::vector<typename TMask::Pointer> & warped_mask):
1266 tile_index_(tile_index),
1267 transform_(transform),
1270 warped_tile_(warped_tile),
1271 warped_mask_(warped_mask)
1279 std::ostringstream oss;
1280 oss << setw(4) << tile_index_ <<
". warping image tile" << std::endl;
1281 warped_tile_[tile_index_] =
1282 warp<TImage>(tile_[tile_index_],
1283 transform_[tile_index_].GetPointer());
1285 if (mask_[tile_index_].GetPointer() != NULL)
1287 oss << setw(4) << tile_index_ <<
". warping image tile mask" << std::endl;
1288 warped_mask_[tile_index_] =
1289 warp<TMask>(mask_[tile_index_],
1290 transform_[tile_index_].GetPointer());
1292 CORE_LOG_MESSAGE(oss.str());
1295 unsigned int tile_index_;
1296 const std::vector<itk::GridTransform::Pointer> & transform_;
1297 const std::vector<img_ptr_t> & tile_;
1298 const std::vector<msk_ptr_t> & mask_;
1299 std::vector<typename TImage::Pointer> & warped_tile_;
1300 std::vector<typename TMask::Pointer> & warped_mask_;
1307 template <
typename img_ptr_t,
typename msk_ptr_t>
1311 typedef typename img_ptr_t::ObjectType::Pointer::ObjectType TImage;
1312 typedef typename msk_ptr_t::ObjectType::Pointer::ObjectType TMask;
1315 std::vector<itk::GridTransform::Pointer> & transform,
1316 const std::vector<img_ptr_t> & warped_tile,
1317 const std::vector<msk_ptr_t> & warped_mask,
1319 const bool & tiles_already_warped,
1320 const unsigned int & neighborhood_size,
1321 const double & minimum_overlap,
1322 const unsigned int & median_filter_radius,
1323 const bool & keep_first_tile_fixed,
1324 std::vector<std::vector<vec2d_t> > & shift):
1326 tile_index_(tile_index),
1327 transform_(transform),
1328 warped_tile_(warped_tile),
1329 warped_mask_(warped_mask),
1330 neighbors_(neighbors),
1331 tiles_already_warped_(tiles_already_warped),
1332 neighborhood_(neighborhood_size),
1333 minimum_overlap_(minimum_overlap),
1334 median_radius_(median_filter_radius),
1335 keep_first_tile_fixed_(keep_first_tile_fixed),
1345 unsigned int mesh_size = gt.grid_.mesh_.size();
1346 std::vector<double> mass(mesh_size, 0);
1348 unsigned int num_neighbors = neighbors_[tile_index_].size();
1349 std::vector<std::vector<vec2d_t> > shift_i(num_neighbors);
1351 std::ostringstream oss;
1352 for (
unsigned int k = 0; k < num_neighbors; k++)
1354 unsigned int j = neighbors_[tile_index_][k];
1355 oss <<
"matching " << tile_index_ <<
":" << j << std::endl;
1357 calc_displacements<TImage, TMask>(shift_i[k],
1361 tiles_already_warped_,
1366 transform_[j].GetPointer(),
1369 warped_tile_[tile_index_],
1370 warped_mask_[tile_index_],
1371 transform_[tile_index_].GetPointer(),
1379 shift_[tile_index_].assign(mesh_size, vec2d(0, 0));
1381 for (
unsigned int j = 0; j < num_neighbors; j++)
1383 for (
unsigned int k = 0; k < mesh_size; k++)
1385 shift_[tile_index_][k] += shift_i[j][k];
1389 if (!keep_first_tile_fixed_)
1392 for (
unsigned int k = 0; k < mesh_size; k++)
1394 double scale = 1 / (1 + mass[k]);
1395 shift_[tile_index_][k] *= scale;
1398 CORE_LOG_MESSAGE(oss.str());
1401 unsigned int tile_index_;
1402 std::vector<itk::GridTransform::Pointer> & transform_;
1403 const std::vector<img_ptr_t> & warped_tile_;
1404 const std::vector<msk_ptr_t> & warped_mask_;
1405 const std::vector<the_dynamic_array_t<unsigned int> > & neighbors_;
1406 const bool tiles_already_warped_;
1407 const unsigned int neighborhood_;
1408 const double minimum_overlap_;
1409 const unsigned int median_radius_;
1410 const bool keep_first_tile_fixed_;
1411 std::vector<std::vector<vec2d_t> > & shift_;
1418 template<
typename img_ptr_t,
typename msk_ptr_t>
1420 refine_mosaic_mt(std::vector<itk::GridTransform::Pointer> & transform,
1421 const std::vector<img_ptr_t> & tile,
1422 const std::vector<msk_ptr_t> & mask,
1423 const unsigned int & neighborhood_size,
1424 const bool & prewarp_tiles,
1425 const double & minimum_overlap,
1426 const unsigned int & median_radius,
1427 const unsigned int & num_passes,
1428 const bool & keep_first_tile_fixed,
1429 const double & displacement_threshold,
1430 unsigned int num_threads)
1432 if (num_threads == 1)
1434 refine_mosaic<img_ptr_t, msk_ptr_t>(transform,
1442 keep_first_tile_fixed);
1447 typedef typename img_ptr_t::ObjectType::Pointer::ObjectType TImage;
1448 typedef typename msk_ptr_t::ObjectType::Pointer::ObjectType TMask;
1451 unsigned int num_tiles = tile.size();
1452 if (num_tiles < 2)
return;
1455 std::vector<pnt2d_t> image_min;
1456 std::vector<pnt2d_t> image_max;
1457 calc_image_bboxes<img_ptr_t>(tile, image_min, image_max);
1460 std::vector<pnt2d_t> mosaic_min;
1461 std::vector<pnt2d_t> mosaic_max;
1462 const unsigned int SAMPLE_POINTS_ALONG_IMAGE_EDGES = 16;
1463 calc_mosaic_bboxes<pnt2d_t, itk_grid_transform_t::Pointer>(transform,
1468 SAMPLE_POINTS_ALONG_IMAGE_EDGES);
1475 double threshold = displacement_threshold;
1477 unsigned int start = keep_first_tile_fixed ? 1 : 0;
1480 std::vector<the_dynamic_array_t<unsigned int> > neighbors(num_tiles);
1481 for (
unsigned int i = start; i < num_tiles; i++)
1484 ibox <<
p3x1_t(mosaic_min[i][0], mosaic_min[i][1], 0)
1485 <<
p3x1_t(mosaic_max[i][0], mosaic_max[i][1], 0);
1487 for (
unsigned int j = 0; j < num_tiles; j++)
1489 if (i == j)
continue;
1492 jbox <<
p3x1_t(mosaic_min[j][0], mosaic_min[j][1], 0)
1493 <<
p3x1_t(mosaic_max[j][0], mosaic_max[j][1], 0);
1495 if (!ibox.intersects(jbox))
continue;
1497 neighbors[i].push_back(j);
1501 std::vector<typename TImage::Pointer> warped_tile(num_tiles);
1502 std::vector<typename TMask::Pointer> warped_mask(num_tiles);
1504 double last_average = std::numeric_limits<double>::max();
1508 for (
unsigned int i = 0; i < num_tiles; i++)
1510 warped_tile[i] = tile[i];
1511 warped_mask[i] =
const_cast<TMask *
>(mask[i].GetPointer());
1515 thread_pool.set_idle_sleep_duration(50);
1517 std::ostringstream oss;
1518 for (
unsigned int pass = 0; pass < num_passes; pass++)
1520 double major_percent = 0.15 + 0.8 * ((double)pass/(
double)num_passes);
1521 double next_major = 0.15 + 0.8 * ((double)(pass + 1)/(double)num_passes);
1522 set_major_progress(major_percent);
1524 oss <<
"--------------------------- pass " << pass
1525 <<
" ---------------------------" << std::endl;
1531 std::list<the_transaction_t *> schedule;
1532 for (
unsigned int i = start; i < num_tiles; i++)
1541 schedule.push_back(t);
1544 thread_pool.push_back(schedule);
1545 thread_pool.pre_distribute_work();
1547 thread_pool.start();
1551 set_minor_progress(0.2, next_major);
1555 std::vector<std::vector<vec2d_t> > shift(num_tiles);
1558 unsigned int num_tiles_distributed =
1559 (num_tiles - start) - (num_tiles - start) % num_threads;
1561 unsigned int num_tiles_remaining =
1562 (num_tiles - start) - num_tiles_distributed;
1564 std::list<the_transaction_t *> schedule;
1565 for (
unsigned int i = 0; i < num_tiles_distributed; i++)
1567 unsigned int index = start + i;
1573 tile_transaction_t * t =
new tile_transaction_t(index,
1582 keep_first_tile_fixed,
1584 schedule.push_back(t);
1587 thread_pool.push_back(schedule);
1590 thread_pool.start();
1593 set_minor_progress(0.9, next_major);
1596 for (
unsigned int i = 0; i < num_tiles_remaining; i++)
1598 unsigned int index = start + num_tiles_distributed + i;
1601 unsigned int mesh_size = gt.grid_.mesh_.size();
1603 std::vector<std::vector<vec2d_t> > shift_i(neighbors[index].size());
1604 std::vector<double> mass(mesh_size, 0);
1606 for (
unsigned int k = 0; k < neighbors[index].size(); k++)
1608 unsigned int j = neighbors[index][k];
1609 oss <<
"matching " << index <<
":" << j << std::endl;
1611 calc_displacements_mt<TImage, TMask>(num_threads,
1621 transform[j].GetPointer(),
1626 transform[index].GetPointer(),
1634 shift[index].assign(mesh_size, vec2d(0, 0));
1636 for (
unsigned int j = 0; j < shift_i.size(); j++)
1638 for (
unsigned int k = 0; k < mesh_size; k++)
1640 shift[index][k] += shift_i[j][k];
1644 if (!keep_first_tile_fixed)
1647 for (
unsigned int k = 0; k < mesh_size; k++)
1649 double scale = 1 / (1 + mass[k]);
1650 shift[index][k] *= scale;
1659 for (
unsigned int i = start; i < num_tiles; i++)
1662 gt.grid_.update(&(shift[i][0]));
1663 transform[i]->setup(gt);
1727 double worst = 0.0, avg = 0.0, count = 0.0;
1728 for (
int i = 0; i < shift.size(); i++)
1730 for (
int k = 0; k < shift[i].size(); k++)
1732 if ( std::abs(shift[i][k][0]) > worst )
1733 worst = std::abs(shift[i][k][0]);
1734 if ( std::abs(shift[i][k][1]) > worst )
1735 worst = std::abs(shift[i][k][1]);
1737 avg += std::abs(shift[i][k][0]) + std::abs(shift[i][k][1]);
1742 std::cout << pass <<
" Average Displacement: " << avg
1743 <<
" Max Displacement: " << worst << std::endl;
1748 if ( avg <= threshold )
1750 else if ( avg >= last_average )
1755 CORE_LOG_MESSAGE(oss.str());
1759 #endif // MOSAIC_REFINEMENT_COMMON_HXX_
Definition: v3x1p3x1.hxx:826
Computes mean pixel variance within the overlapping regions of a mosaic.
Definition: itkImageMosaicVarianceMetric.h:69
Definition: mosaic_refinement_common.hxx:1253
Definition: mosaic_refinement_common.hxx:1308
Definition: optimizer_observer.hxx:44
Definition: the_transaction.hxx:55
Definition: mosaic_refinement_common.hxx:401
Definition: the_dynamic_array.hxx:45
Definition: the_terminator.hxx:58
Definition: the_thread_pool.hxx:105
Definition: the_aa_bbox.hxx:81
Definition: common.hxx:619
Definition: the_thread_interface.hxx:57
Definition: mosaic_refinement_common.hxx:1003
Definition: itkDiscontinuousTransform.h:56