Xmipp  v3.23.11-Nereus
single_extrema_finder.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 
26 #include <iostream>
27 #include "single_extrema_finder.h"
28 
29 namespace ExtremaFinder {
30 
31 template<typename T>
32 void SingleExtremaFinder<T>::setDefault() {
33  m_cpu = nullptr;
34 }
35 
36 template<typename T>
37 void SingleExtremaFinder<T>::release() {
38  setDefault();
39 }
40 
41 template<typename T>
42 void SingleExtremaFinder<T>::check() const {
43  if (this->getSettings().hw.size() > 1) {
44  std::cerr << "Search using multiple threads is not yet implemented. Single thread will be used.\n";
45  }
46 }
47 
48 template<typename T>
49 void SingleExtremaFinder<T>::initMax() {
50  return initBasic();
51 }
52 
53 template<typename T>
54 void SingleExtremaFinder<T>::findMax(const T *__restrict__ data) {
55  auto kernel = [&](const T *d) {
56  sFindMax(*m_cpu, this->getSettings().dims, d,
57  this->getPositions().data(),
58  this->getValues().data());
59  };
60  return findBasic(data, kernel);
61 }
62 
63 template<typename T>
64 bool SingleExtremaFinder<T>::canBeReusedMax(const ExtremaFinderSettings &s) const {
65  return true;
66 }
67 
68 template<typename T>
69 void SingleExtremaFinder<T>::initLowest() {
70  return initBasic();
71 }
72 
73 template<typename T>
74 void SingleExtremaFinder<T>::findLowest(const T *__restrict__ data) {
75  auto kernel = [&](const T *d) {
76  sFindLowest(*m_cpu, this->getSettings().dims, d,
77  this->getPositions().data(),
78  this->getValues().data());
79  };
80  return findBasic(data, kernel);
81 }
82 
83 template<typename T>
84 bool SingleExtremaFinder<T>::canBeReusedLowest(const ExtremaFinderSettings &s) const {
85  return true;
86 }
87 
88 template<typename T>
89 void SingleExtremaFinder<T>::initMaxAroundCenter() {
90  return initBasic();
91 }
92 
93 template<typename T>
94 void SingleExtremaFinder<T>::findMaxAroundCenter(const T *__restrict__ data) {
95  auto s = this->getSettings();
96  auto kernel2D = [&](const T *d) {
97  sFindMax2DAroundCenter(*m_cpu, s.dims, d,
98  this->getPositions().data(),
99  this->getValues().data(),
100  s.maxDistFromCenter);
101  };
102  if (s.dims.is2D()) {
103  return findBasic(data, kernel2D);
104  }
105  REPORT_ERROR(ERR_NOT_IMPLEMENTED, "Not implemented");
106 }
107 
108 template<typename T>
109 bool SingleExtremaFinder<T>::canBeReusedMaxAroundCenter(const ExtremaFinderSettings &s) const {
110  return true;
111 }
112 
113 template<typename T>
114 void SingleExtremaFinder<T>::initLowestAroundCenter() {
115  return initBasic();
116 }
117 
118 template<typename T>
119 void SingleExtremaFinder<T>::findLowestAroundCenter(const T *__restrict__ data) {
120  auto s = this->getSettings();
121  auto kernel2D = [&](const T *d) {
122  sFindLowest2DAroundCenter(*m_cpu, s.dims, d,
123  this->getPositions().data(),
124  this->getValues().data(),
125  s.maxDistFromCenter);
126  };
127  if (s.dims.is2D()) {
128  return findBasic(data, kernel2D);
129  }
130  REPORT_ERROR(ERR_NOT_IMPLEMENTED, "Not implemented");
131 }
132 
133 template<typename T>
134 bool SingleExtremaFinder<T>::canBeReusedLowestAroundCenter(const ExtremaFinderSettings &s) const {
135  return true;
136 }
137 
138 
139 template<typename T>
140 void SingleExtremaFinder<T>::initBasic() {
141  release();
142  auto s = this->getSettings();
143  if (0 == s.hw.size()) {
144  REPORT_ERROR(ERR_ARG_INCORRECT, "At least one CPU thread is needed");
145  }
146  try {
147  m_cpu = dynamic_cast<CPU*>(s.hw.at(0));
148  } catch (std::bad_cast&) {
149  REPORT_ERROR(ERR_ARG_INCORRECT, "Instance of CPU expected");
150  }
151 }
152 
153 template<typename T>
154 template<typename KERNEL>
155 void SingleExtremaFinder<T>::findBasic(const T *__restrict__ data, const KERNEL &k) {
156  bool isReady = this->isInitialized();
157  if ( ! isReady) {
158  REPORT_ERROR(ERR_LOGIC_ERROR, "Not ready to execute. Call init() first");
159  }
160  k(data);
161 }
162 
163 template<typename T>
165  const Dimensions &dims,
166  const T *__restrict__ data,
167  float *__restrict__ positions,
168  T *__restrict__ values) {
169  // check input
170  assert(dims.sizeSingle() > 0);
171  assert(dims.n() > 0);
172  assert(nullptr != data);
173  assert((nullptr != positions) || (nullptr != values));
174 }
175 
176 template<typename T>
178  const Dimensions &dims,
179  const T *__restrict__ data,
180  float *__restrict__ positions,
181  T *__restrict__ values) {
182  sFindUniversalChecks(dims, data, positions, values);
183 
184  if (dims.isPadded()) {
185  REPORT_ERROR(ERR_NOT_IMPLEMENTED, "Not implemented");
186  } else {
187  // locate max
188  for (size_t n = 0; n < dims.n(); ++n) {
189  auto start = data + (n * dims.sizeSingle());
190  auto max = std::max_element(start, start + dims.sizeSingle());
191  auto pos = std::distance(start, max);
192  values[n] = *max;
193  positions[n] = pos;
194  }
195  }
196 }
197 
198 template<typename T>
200  const Dimensions &dims,
201  const T *__restrict__ data,
202  float *__restrict__ positions,
203  T *__restrict__ values) {
204  sFindUniversalChecks(dims, data, positions, values);
205 
206  if (dims.isPadded()) {
207  REPORT_ERROR(ERR_NOT_IMPLEMENTED, "Not implemented");
208  } else {
209  // locate minima
210  for (size_t n = 0; n < dims.n(); ++n) {
211  auto start = data + (n * dims.sizeSingle());
212  auto max = std::min_element(start, start + dims.sizeSingle());
213  auto pos = std::distance(start, max);
214  values[n] = *max;
215  positions[n] = pos;
216  }
217  }
218 }
219 
220 template<typename T>
222  const CPU &cpu,
223  const Dimensions &dims,
224  const T *__restrict__ data,
225  float *__restrict__ positions,
226  T *__restrict__ values,
227  size_t maxDist) {
228  sFindUniversal2DAroundCenter(std::greater<T>(),
229  std::numeric_limits<T>::lowest(),
230  cpu, dims, data, positions, values, maxDist);
231 }
232 
233 template<typename T>
235  const CPU &cpu,
236  const Dimensions &dims,
237  const T *__restrict__ data,
238  float *__restrict__ positions,
239  T *__restrict__ values,
240  size_t maxDist) {
241  sFindUniversal2DAroundCenter(std::less<T>(),
243  cpu, dims, data, positions, values, maxDist);
244 }
245 
246 template<typename T>
247 template<typename C>
249  const C &comp,
250  T startVal,
251  const CPU &cpu,
252  const Dimensions &dims,
253  const T *data,
254  float *positions, // can be nullptr
255  T * values, // can be nullptr
256  size_t maxDist) {
257  // check input
258  assert(dims.is2D());
259  assert( ! dims.isPadded());
260  assert(dims.sizeSingle() > 0);
261  assert(dims.n() > 0);
262  assert(nullptr != data);
263  assert((nullptr != positions) || (nullptr != values));
264  assert(0 < maxDist);
265  const size_t xHalf = dims.x() / 2;
266  const size_t yHalf = dims.y() / 2;
267  assert((2 * xHalf) > maxDist);
268  assert((2 * yHalf) > maxDist);
269 
270  const auto min = std::pair<size_t, size_t>(
271  std::max((size_t)0, xHalf - maxDist),
272  std::max((size_t)0, yHalf - maxDist)
273  );
274 
275  const auto max = std::pair<size_t, size_t>(
276  std::min(dims.x() - 1, xHalf + maxDist),
277  std::min(dims.y() - 1, yHalf + maxDist)
278  );
279 
280  const size_t maxDistSq = maxDist * maxDist;
281  for (size_t n = 0; n < dims.n(); ++n) {
282  size_t offsetN = n * dims.xyzPadded();
283  T extrema = startVal;
284  float pos = -1;
285  // iterate through the center
286  for (size_t y = min.second; y <= max.second; ++y) {
287  size_t offsetY = y * dims.x();
288  int logicY = (int)y - yHalf;
289  size_t ySq = logicY * logicY;
290  for (size_t x = min.first; x <= max.first; ++x) {
291  int logicX = (int)x - xHalf;
292  // continue if the Euclidean distance is too far
293  if ((ySq + (logicX * logicX)) > maxDistSq) continue;
294  // get current value and update, if necessary
295  T tmp = data[offsetN + offsetY + x];
296  if (comp(tmp, extrema)) {
297  extrema = tmp;
298  pos = offsetY + x;
299  }
300  }
301  }
302  // store results
303  if (nullptr != positions) {
304  positions[n] = pos;
305  }
306  if (nullptr != values) {
307  values[n] = extrema;
308  }
309  }
310 }
311 
312 // explicit instantiation
313 template class SingleExtremaFinder<float>;
314 template class SingleExtremaFinder<double>;
315 
316 } /* namespace ExtremaFinder */
CUDA_HD constexpr bool is2D() const
Definition: dimensions.h:162
constexpr size_t xyzPadded() const
Definition: dimensions.h:95
void min(Image< double > &op1, const Image< double > &op2)
static void sFindLowest(const CPU &cpu, const Dimensions &dims, const T *data, float *positions, T *values)
Case or algorithm not implemented yet.
Definition: xmipp_error.h:177
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
constexpr bool isPadded() const
Definition: dimensions.h:153
static double * y
static void sFindUniversal2DAroundCenter(const C &comp, T startVal, const CPU &cpu, const Dimensions &dims, const T *data, float *positions, T *values, size_t maxDist)
static void sFindLowest2DAroundCenter(const CPU &cpu, const Dimensions &dims, const T *data, float *positions, T *values, size_t maxDist)
doublereal * x
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
doublereal * d
CUDA_HD constexpr size_t x() const
Definition: dimensions.h:51
Incorrect argument received.
Definition: xmipp_error.h:113
CUDA_HD constexpr size_t sizeSingle() const
Definition: dimensions.h:100
void max(Image< double > &op1, const Image< double > &op2)
CUDA_HD constexpr size_t y() const
Definition: dimensions.h:60
CUDA_HD constexpr size_t n() const
Definition: dimensions.h:78
TYPE distance(struct Point_T *p, struct Point_T *q)
Definition: point.cpp:28
static void sFindMax(const CPU &cpu, const Dimensions &dims, const T *data, float *positions, T *values)
Definition: cpu.h:37
static void sFindMax2DAroundCenter(const CPU &cpu, const Dimensions &dims, const T *data, float *positions, T *values, size_t maxDist)
int * n
Some logical error in the pipeline.
Definition: xmipp_error.h:147