Xmipp  v3.23.11-Nereus
iterative_alignment_estimator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: David Strelak (davidstrelak@gmail.com)
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program 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 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program 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 this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
27 
28 namespace Alignment {
29 
30 template<typename T>
31 template<typename U, typename F>
32 void IterativeAlignmentEstimator<T>::updateEstimation(AlignmentEstimation &est,
33  const U &newVals, const F &func) {
34  size_t len = newVals.size();
35  for (size_t i = 0; i < len; ++i) {
36  func(newVals.at(i), est.poses.at(i));
37  }
38 }
39 
40 template<typename T>
41 void IterativeAlignmentEstimator<T>::print(const AlignmentEstimation &e) {
42  for (auto &m : e.poses) {
43  printf("([%f %f], %f) ", MAT_ELEM(m, 0, 2), MAT_ELEM(m, 1, 2), RAD2DEG(atan2(MAT_ELEM(m, 1, 0), MAT_ELEM(m, 0, 0))));
44  }
45  printf("\n");
46 }
47 
48 template<typename T>
49 T *IterativeAlignmentEstimator<T>::applyTransform(const AlignmentEstimation &estimation) {
50  std::vector<float> t;
51  t.reserve(9 * estimation.poses.size());
52  auto tmp = Matrix2D<float>(3, 3);
54  for (size_t j = 0; j < estimation.poses.size(); ++j) {
55  M3x3_INV(tmp, estimation.poses.at(j)) // inverse the transformation
56  for (int i = 0; i < 9; ++i) {
57  t.emplace_back(tmp.mdata[i]);
58  }
59  }
60  return m_transformer.interpolate(t);
61 }
62 
63 template<typename T>
65  const AlignmentEstimation &estimation,
66  const T * __restrict__ orig, T * __restrict__ copy, bool hasSingleOrig) {
67  const size_t n = dims.n();
68  const size_t z = dims.z();
69  const size_t y = dims.y();
70  const size_t x = dims.x();
71 
72  auto futures = std::vector<std::future<void>>();
73 
74  auto workload = [&](int id, size_t signalId){
75  size_t offset = signalId * dims.sizeSingle();
76  auto in = MultidimArray<T>(1, z, y, x, const_cast<T*>(orig + (hasSingleOrig ? 0 : offset))); // removing const, but data should not be changed
77  auto out = MultidimArray<T>(1, z, y, x, copy + offset);
78  in.setXmippOrigin();
79  out.setXmippOrigin();
80  // compensate the movement
81  applyGeometry(xmipp_transformation::LINEAR, out, in, estimation.poses.at(signalId), false, xmipp_transformation::DONT_WRAP);
82  };
83 
84  for (size_t i = 0; i < n; ++i) {
85  futures.emplace_back(pool.push(workload, i));
86  }
87  for (auto &f : futures) {
88  f.get();
89  }
90 }
91 
92 template<typename T>
94  bool rotationFirst) {
95  // note (DS) if any of these steps return 0 (no shift or rotation), additional iterations are useless
96  // as the image won't change
97  auto stepRotation = [&] {
98  m_rot_est.compute(m_transformer.getDest());
99  const auto &cRotEst = m_rot_est;
100  auto r = Matrix2D<float>();
101  updateEstimation(est,
102  cRotEst.getRotations2D(),
103  [&r](float angle, Matrix2D<float> &lhs) {
104  rotation2DMatrix(angle, r);
105  lhs = r * lhs;
106  });
107  applyTransform(est);
108  };
109  auto stepShift = [&] {
110  m_shift_est.computeShift2DOneToN(m_transformer.getDest());
111  updateEstimation(est, m_shift_est.getShifts2D(),
112  [](const Point2D<float> &shift, Matrix2D<float> &lhs) {
113  MAT_ELEM(lhs, 0, 2) += shift.x;
114  MAT_ELEM(lhs, 1, 2) += shift.y;
115  });
116  applyTransform(est);
117  };
118  // get a fresh copy of the images
119  m_transformer.copySrcToDest();
120  for (unsigned i = 0; i < iters; ++i) {
121  if (rotationFirst) {
122  stepRotation();
123  // if we have object implementing both interfaces, we don't need to run next step
124  if ( ! m_sameEstimators) {
125  stepShift();
126  }
127  } else {
128  stepShift();
129  // if we have object implementing both interfaces, we don't need to run next step
130  if ( ! m_sameEstimators) {
131  stepRotation();
132  }
133  }
134 // print(est);
135  }
136  m_meritComputer.compute(m_transformer.getDest());
137  const auto &mc = m_meritComputer;
138  est.figuresOfMerit = mc.getFiguresOfMerit();
139 }
140 
141 template<typename T>
143  const T *ref) {
144  m_meritComputer.loadReference(ref);
145  m_shift_est.load2DReferenceOneToN(ref);
146  if ( ! m_sameEstimators) {
147  m_rot_est.loadReference(ref);
148  }
149 }
150 
151 template<typename T>
153  const T * __restrict__ others, // it would be good if data is normalized, but probably it does not have to be
154  unsigned iters) {
155  m_transformer.setSrc(others);
156 
157  // prepare transformer which is responsible for applying the pose t
158  const size_t n = m_rot_est.getSettings().otherDims.n();
159  // try rotation -> shift
160  auto result_RS = AlignmentEstimation(n);
161  compute(iters, result_RS, true);
162  // try shift-> rotation
163  auto result_SR = AlignmentEstimation(n);
164  compute(iters, result_SR, false);
165 
166  for (size_t i = 0; i < n; ++i) {
167  if (result_RS.figuresOfMerit.at(i) < result_SR.figuresOfMerit.at(i)) {
168  result_RS.figuresOfMerit.at(i) = result_SR.figuresOfMerit.at(i);
169  result_RS.poses.at(i) = result_SR.poses.at(i);
170  }
171  }
172 
173  return result_RS;
174 }
175 
176 template<typename T>
178  if (m_rot_est.getSettings().otherDims != m_shift_est.getDimensions()) {
179  REPORT_ERROR(ERR_LOGIC_ERROR, "Estimators are initialized for different sizes");
180  }
181  if (m_rot_est.getSettings().type != m_shift_est.getAlignType()) {
182  REPORT_ERROR(ERR_LOGIC_ERROR, "Estimators are initialized for different type of alignment");
183  }
184 }
185 
186 // explicit instantiation
189 
190 } /* namespace Alignment */
T y
Definition: point2D.h:53
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
#define SPEED_UP_temps0
Definition: xmipp_macros.h:394
auto push(F &&f, Rest &&... rest) -> std::future< decltype(f(0, rest...))>
Definition: ctpl.h:152
CUDA_HD constexpr size_t z() const
Definition: dimensions.h:69
static double * y
void applyGeometry(int SplineDegree, MultidimArray< std::complex< double > > &V2, const MultidimArray< std::complex< double > > &V1, const Matrix2D< double > &A, bool inv, bool wrap, std::complex< double > outside, MultidimArray< double > *BcoeffsPtr)
doublereal * x
#define i
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
CUDA_HD constexpr size_t x() const
Definition: dimensions.h:51
#define M3x3_INV(Ainv, A)
Definition: matrix2d.h:302
static void sApplyTransform(ctpl::thread_pool &pool, const Dimensions &dims, const AlignmentEstimation &estimation, const T *orig, T *copy, bool hasSingleOrig)
AlignmentEstimation compute(const T *others, unsigned iters=3)
int in
double * f
CUDA_HD constexpr size_t sizeSingle() const
Definition: dimensions.h:100
T x
Definition: point2D.h:52
CUDA_HD constexpr size_t y() const
Definition: dimensions.h:60
double z
CUDA_HD constexpr size_t n() const
Definition: dimensions.h:78
void rotation2DMatrix(T ang, Matrix2D< T > &result, bool homogeneous)
#define j
int m
std::vector< Matrix2D< float > > poses
#define len
#define RAD2DEG(r)
Definition: xmipp_macros.h:320
int * n
Some logical error in the pipeline.
Definition: xmipp_error.h:147