SMIL  1.0.4
DMorphoLabel.hpp
1 /*
2  * Copyright (c) 2011-2016, Matthieu FAESSEL and ARMINES
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Matthieu FAESSEL, or ARMINES nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef _D_MORPHO_LABEL_HPP
31 #define _D_MORPHO_LABEL_HPP
32 
33 #include "Base/include/private/DImageArith.hpp"
34 #include "Core/include/DImage.h"
35 #include "DMorphImageOperations.hpp"
36 #include "Base/include/private/DBlobMeasures.hpp"
37 
38 #include <set>
39 #include <map>
40 #include <functional>
41 
42 namespace smil
43 {
65 #ifndef SWIG
66 
67  /*
68  * ###### # # # # #### ##### #### ##### ####
69  * # # # ## # # # # # # # # #
70  * ##### # # # # # # # # # # # ####
71  * # # # # # # # # # # ##### #
72  * # # # # ## # # # # # # # # #
73  * # #### # # #### # #### # # ####
74  */
75  /* @devdoc */
77  template <class T1, class T2, class compOperatorT = std::equal_to<T1>>
78  class labelFunctGeneric : public MorphImageFunctionBase<T1, T2>
79  {
80  public:
81  typedef MorphImageFunctionBase<T1, T2> parentClass;
82  typedef typename parentClass::imageInType imageInType;
83  typedef typename parentClass::imageOutType imageOutType;
84 
85  size_t getLabelNbr()
86  {
87  return real_labels;
88  }
89 
90  virtual RES_T initialize(const imageInType &imIn, imageOutType &imOut,
91  const StrElt &se)
92  {
93  parentClass::initialize(imIn, imOut, se);
94  fill(imOut, T2(0));
95  labels = 0;
96  real_labels = 0;
97  max_value_label = ImDtTypes<T2>::max();
98  return RES_OK;
99  }
100 
101  virtual RES_T processImage(const imageInType &imIn,
102  imageOutType & /*imOut*/, const StrElt & /*se*/)
103  {
104  this->pixelsIn = imIn.getPixels();
105 
106  size_t nbPixels = imIn.getPixelCount();
107  for (size_t i = 0; i < nbPixels; i++) {
108  if (this->pixelsOut[i] == T2(0)) {
109  vector<int> dum;
110  processPixel(i, dum);
111  }
112  }
113  return RES_OK;
114  }
115 
116  virtual void processPixel(size_t pointOffset,
117  SMIL_UNUSED vector<int> &dOffsets)
118  {
119  T1 pVal = this->pixelsIn[pointOffset];
120 
121  if (pVal == T1(0) || this->pixelsOut[pointOffset] != T2(0))
122  return;
123 
124  queue<size_t> propagation;
125 
126  ++real_labels;
127  ++labels;
128  if (labels == max_value_label)
129  labels = 1;
130  this->pixelsOut[pointOffset] = (T2) labels;
131  propagation.push(pointOffset);
132 
133  size_t pixPerLine = this->imSize[0];
134  size_t pixPerSlice = this->imSize[0] * this->imSize[1];
135 
136  while (!propagation.empty()) {
137  off_t x, y, z, n_x, n_y, n_z;
138 
139  bool oddLine = false;
140  size_t curOffset, nbOffset;
141 
142  curOffset = propagation.front();
143  pVal = this->pixelsIn[curOffset];
144 
145  z = curOffset / (pixPerSlice);
146  y = (curOffset - z * pixPerSlice) / pixPerLine;
147  x = curOffset - y * pixPerLine - z * pixPerSlice;
148 
149  oddLine = this->oddSe && (y % 2);
150 
151  for (UINT i = 0; i < this->sePointNbr; ++i) {
152  IntPoint p = this->sePoints[i];
153 
154  n_z = z + p.z;
155  if (n_z < 0 || n_z >= off_t(this->imSize[2]))
156  continue;
157  n_y = y + p.y;
158  if (n_y < 0 || n_y >= off_t(this->imSize[1]))
159  continue;
160  n_x = x + p.x;
161  if (oddLine && ((n_y + 1) % 2) != 0)
162  n_x++;
163  if (n_x < 0 || n_x >= off_t(this->imSize[0]))
164  continue;
165 
166  // if (!this->imageIn->areCoordsInImage(n_x, n_y, n_z))
167  // continue;
168 
169  nbOffset = n_x + n_y * pixPerLine + n_z * pixPerSlice;
170  if (nbOffset != curOffset && this->pixelsOut[nbOffset] != labels &&
171  compareFunc(this->pixelsIn[nbOffset], pVal)) {
172  this->pixelsOut[nbOffset] = T2(labels);
173  propagation.push(nbOffset);
174  }
175  }
176  propagation.pop();
177  }
178  }
179 
180  compOperatorT compareFunc;
181 
182  protected:
183  T2 labels;
184  size_t real_labels;
185  T2 max_value_label;
186  };
187 
188  template <class T1, class T2, class compOperatorT = std::equal_to<T1>>
189  class labelFunctFast : public MorphImageFunctionBase<T1, T2>
190  {
191  public:
192  typedef MorphImageFunctionBase<T1, T2> parentClass;
193  typedef typename parentClass::imageInType imageInType;
194  typedef typename parentClass::imageOutType imageOutType;
195  typedef typename imageInType::lineType lineInType;
196  typedef typename imageInType::sliceType sliceInType;
197  typedef typename imageOutType::lineType lineOutType;
198  typedef typename imageOutType::sliceType sliceOutType;
199 
200  size_t getLabelNbr()
201  {
202  return labels_real;
203  }
204 
205  virtual RES_T initialize(const imageInType &imIn, imageOutType &imOut,
206  const StrElt &se)
207  {
208  parentClass::initialize(imIn, imOut, se);
209  fill(imOut, T2(0));
210  labels = T2(0);
211  labels_real = 0;
212  max_value_label = ImDtTypes<T2>::max();
213  return RES_OK;
214  }
215 
216  virtual RES_T processImage(const imageInType &imIn, imageOutType &imOut,
217  const StrElt & /*se*/)
218  {
219  Image<T1> tmp(imIn);
220  Image<T1> tmp2(imIn);
221  ASSERT(clone(imIn, tmp) == RES_OK);
222  if (this->imSize[2] == 1) {
223  ASSERT(erode(tmp, tmp2, SquSE()) == RES_OK);
224  } else {
225  ASSERT(erode(tmp, tmp2, CubeSE()) == RES_OK);
226  }
227  ASSERT(sub(tmp, tmp2, tmp) == RES_OK);
228 
229  lineInType pixelsTmp = tmp.getPixels();
230 
231  // Adding the first point of each line to tmp.
232 #ifdef USE_OPEN_MP
233 #pragma omp parallel
234 #endif // USE_OPEN_MP
235  {
236 #ifdef USE_OPEN_MP
237 #pragma omp for
238 #endif // USE_OPEN_MP
239  for (size_t i = 0; i < this->imSize[2] * this->imSize[1]; ++i) {
240  pixelsTmp[i * this->imSize[0]] = this->pixelsIn[i * this->imSize[0]];
241  }
242  }
243 
244  queue<size_t> propagation;
245  int x, y, z, n_x, n_y, n_z;
246  IntPoint p;
247 
248  T2 current_label = labels;
249  bool is_not_a_gap = false;
250  bool process_labeling = false;
251  bool oddLine = 0;
252 
253  // First PASS to label the boundaries. //
254  for (size_t i = 0;
255  i < this->imSize[2] * this->imSize[1] * this->imSize[0]; ++i) {
256  if (i % (this->imSize[0]) == 0) {
257  is_not_a_gap = false;
258  }
259  if (pixelsTmp[i] != T1(0)) {
260  if (this->pixelsOut[i] == T2(0)) {
261  if (!is_not_a_gap) {
262  ++labels;
263  ++labels_real;
264  if (labels == max_value_label)
265  labels = 1;
266  current_label = (T2) labels;
267  }
268  this->pixelsOut[i] = current_label;
269  process_labeling = true;
270  } else {
271  current_label = this->pixelsOut[i];
272  }
273 
274  is_not_a_gap = true;
275  }
276  if (this->pixelsIn[i] == T1(0)) {
277  is_not_a_gap = false;
278  }
279 
280  if (process_labeling) {
281  propagation.push(i);
282 
283  while (!propagation.empty()) {
284  z = propagation.front() / (this->imSize[1] * this->imSize[0]);
285  y = (propagation.front() - z * this->imSize[1] * this->imSize[0]) /
286  this->imSize[0];
287  x = propagation.front() - y * this->imSize[0] -
288  z * this->imSize[1] * this->imSize[0];
289 
290  oddLine = this->oddSe && (y % 2);
291  size_t nbOffset;
292 
293  for (UINT i = 0; i < this->sePointNbr; ++i) {
294  p = this->sePoints[i];
295  n_x = x + p.x;
296  n_y = y + p.y;
297  n_x += (oddLine && ((n_y + 1) % 2) != 0);
298  n_z = z + p.z;
299  nbOffset = n_x + (n_y) * this->imSize[0] +
300  (n_z) * this->imSize[1] * this->imSize[0];
301  if (n_x >= 0 && n_x < (int) this->imSize[0] && n_y >= 0 &&
302  n_y < (int) this->imSize[1] && n_z >= 0 &&
303  n_z < (int) this->imSize[2] &&
304  compareFunc(this->pixelsIn[nbOffset],
305  pixelsTmp[propagation.front()]) &&
306  this->pixelsOut[nbOffset] != current_label) {
307  this->pixelsOut[nbOffset] = current_label;
308  propagation.push(nbOffset);
309  }
310  }
311 
312  propagation.pop();
313  }
314  process_labeling = false;
315  }
316  }
317  // Propagate labels inside the borders //
318 
319  size_t nSlices = imIn.getDepth();
320  size_t nLines = imIn.getHeight();
321  size_t nPixels = imIn.getWidth();
322  size_t l, v;
323  T1 previous_value;
324  T2 previous_label;
325 
326  sliceInType srcLines = imIn.getLines();
327  sliceOutType desLines = imOut.getLines();
328  lineInType lineIn;
329  lineOutType lineOut;
330 
331  for (size_t s = 0; s < nSlices; ++s) {
332 #ifdef USE_OPEN_MP
333 #pragma omp parallel private(lineIn, lineOut, l, v, previous_value, \
334  previous_label)
335 #endif // USE_OPEN_MP
336  {
337 #ifdef USE_OPEN_MP
338 #pragma omp for
339 #endif // USE_OPEN_MP
340  for (l = 0; l < nLines; ++l) {
341  lineIn = srcLines[l + s * nSlices];
342  lineOut = desLines[l + s * nSlices];
343  previous_value = lineIn[0];
344  previous_label = lineOut[0];
345  for (v = 1; v < nPixels; ++v) {
346  if (compareFunc(lineIn[v], previous_value)) {
347  lineOut[v] = previous_label;
348  } else {
349  previous_value = lineIn[v];
350  previous_label = lineOut[v];
351  }
352  }
353  }
354  }
355  }
356  return RES_OK;
357  }
358 
359  compOperatorT compareFunc;
360 
361  protected:
362  T2 labels;
363  size_t labels_real;
364  T2 max_value_label;
365  };
366 
367  template <class T>
368  struct lambdaEqualOperator {
369  inline bool operator()(T &a, T &b)
370  {
371  bool retVal = a > b ? (a - b) <= lambda : (b - a) <= lambda;
372  return retVal;
373  }
374  T lambda;
375  };
376 
377 #endif // SWIG
378 
379  template <class T1, class T2>
380  size_t labelWithoutFunctor(const Image<T1> &imIn, Image<T2> &imOut,
381  const StrElt &se = DEFAULT_SE)
382  {
383  // Checks
384  ASSERT_ALLOCATED(&imIn, &imOut);
385  ASSERT_SAME_SIZE(&imIn, &imOut);
386 
387  // Typedefs
388  typedef Image<T1> inT;
389  typedef Image<T2> outT;
390  typedef typename inT::lineType inLineT;
391  typedef typename outT::lineType outLineT;
392 
393  // Initialisation.
394  StrElt cpSe = se.noCenter();
395  fill(imOut, T2(0));
396 
397  // Processing vars.
398  size_t lblNbr = 0;
399  size_t lblNbr_real = 0;
400  size_t size[3];
401  imIn.getSize(size);
402  UINT sePtsNumber = cpSe.points.size();
403  if (sePtsNumber == 0)
404  return 0;
405  queue<size_t> propagation;
406  size_t o, nb_o;
407  size_t x, x0, y, y0, z, z0;
408  bool oddLine;
409  // Image related.
410  inLineT inP = imIn.getPixels();
411  outLineT outP = imOut.getPixels();
412 
413  for (size_t s = 0; s < size[2]; ++s) {
414  for (size_t l = 0; l < size[1]; ++l) {
415  for (size_t p = 0; p < size[0]; ++p) {
416  o = p + l * size[0] + s * size[0] * size[1];
417  if (inP[o] != T1(0) && outP[o] == T2(0)) {
418  ++lblNbr_real;
419  ++lblNbr;
420  if (lblNbr == (size_t)(ImDtTypes<T2>::max() - 1))
421  lblNbr = 1;
422 
423  outP[o] = T2(lblNbr);
424  propagation.push(o);
425  do {
426  o = propagation.front();
427  propagation.pop();
428 
429  x0 = o % size[0];
430  y0 = (o % (size[1] * size[0])) / size[0];
431  z0 = o / (size[0] * size[1]);
432  oddLine = cpSe.odd && y0 % 2;
433  for (UINT pSE = 0; pSE < sePtsNumber; ++pSE) {
434  x = x0 + cpSe.points[pSE].x;
435  y = y0 + cpSe.points[pSE].y;
436  z = z0 + cpSe.points[pSE].z;
437 
438  if (oddLine)
439  x += (y + 1) % 2;
440 
441  nb_o = x + y * size[0] + z * size[0] * size[1];
442  if (x < size[0] && y < size[1] && z < size[2] &&
443  outP[nb_o] != lblNbr && inP[nb_o] == inP[o]) {
444  outP[nb_o] = T2(lblNbr);
445  propagation.push(nb_o);
446  }
447  }
448  } while (!propagation.empty());
449  }
450  }
451  }
452  }
453 
454  return lblNbr_real;
455  }
456 
457  template <class T1, class T2>
458  size_t labelWithoutFunctor2Partitions(const Image<T1> &imIn,
459  const Image<T1> &imIn2,
460  Image<T2> & imOut,
461  const StrElt & se = DEFAULT_SE)
462  {
463  // Checks
464  ASSERT_ALLOCATED(&imIn, &imIn2, &imOut);
465  ASSERT_SAME_SIZE(&imIn, &imOut);
466  ASSERT_SAME_SIZE(&imIn2, &imOut);
467 
468  // Typedefs
469  typedef Image<T1> inT;
470  typedef Image<T2> outT;
471  typedef typename inT::lineType inLineT;
472  typedef typename outT::lineType outLineT;
473 
474  // Initialisation.
475  StrElt cpSe = se.noCenter();
476  fill(imOut, T2(0));
477 
478  // Processing vars.
479  size_t lblNbr = 0;
480  size_t lblNbr_real = 0;
481  size_t size[3];
482  imIn.getSize(size);
483  UINT sePtsNumber = cpSe.points.size();
484  if (sePtsNumber == 0)
485  return 0;
486  queue<size_t> propagation;
487  size_t o, nb_o;
488  size_t x, x0, y, y0, z, z0;
489  bool oddLine;
490  // Image related.
491  inLineT inP = imIn.getPixels();
492  inLineT in2P = imIn2.getPixels();
493  outLineT outP = imOut.getPixels();
494 
495  for (size_t s = 0; s < size[2]; ++s) {
496  for (size_t l = 0; l < size[1]; ++l) {
497  for (size_t p = 0; p < size[0]; ++p) {
498  o = p + l * size[0] + s * size[0] * size[1];
499  if (inP[o] != T1(0) && outP[o] == T2(0)) {
500  ++lblNbr_real;
501  ++lblNbr;
502  if (lblNbr == (size_t) ImDtTypes<T2>::max() - 1)
503  lblNbr = 1;
504 
505  outP[o] = T2(lblNbr);
506  propagation.push(o);
507  do {
508  o = propagation.front();
509  propagation.pop();
510 
511  x0 = o % size[0];
512  y0 = (o % (size[1] * size[0])) / size[0];
513  z0 = o / (size[0] * size[1]);
514  oddLine = cpSe.odd && y0 % 2;
515  for (UINT pSE = 0; pSE < sePtsNumber; ++pSE) {
516  x = x0 + cpSe.points[pSE].x;
517  y = y0 + cpSe.points[pSE].y;
518  z = z0 + cpSe.points[pSE].z;
519 
520  if (oddLine)
521  x += (y + 1) % 2;
522 
523  nb_o = x + y * size[0] + z * size[0] * size[1];
524  if (x < size[0] && y < size[1] && z < size[2] &&
525  outP[nb_o] != lblNbr && inP[nb_o] == inP[o] &&
526  in2P[nb_o] == in2P[o]) {
527  outP[nb_o] = T2(lblNbr);
528  propagation.push(nb_o);
529  }
530  }
531  } while (!propagation.empty());
532  }
533  }
534  }
535  }
536 
537  return lblNbr_real;
538  }
540  /* @enddevdoc */
541 
542  /*
543  * ###### # # # # #### ##### # #### # # ####
544  * # # # ## # # # # # # # ## # #
545  * ##### # # # # # # # # # # # # # ####
546  * # # # # # # # # # # # # # # #
547  * # # # # ## # # # # # # # ## # #
548  * # #### # # #### # # #### # # ####
549  */
563  template <class T1, class T2>
564  size_t label(const Image<T1> &imIn, Image<T2> &imOut,
565  const StrElt &se = DEFAULT_SE)
566  {
567  if ((void *) &imIn == (void *) &imOut) {
568  // clone
569  Image<T1> tmpIm(imIn, true);
570  return label(tmpIm, imOut);
571  }
572 
573  ASSERT_ALLOCATED(&imIn, &imOut);
574  ASSERT_SAME_SIZE(&imIn, &imOut);
575 
576  labelFunctGeneric<T1, T2> f;
577 
578  ASSERT((f._exec(imIn, imOut, se) == RES_OK), 0);
579 
580  size_t lblNbr = f.getLabelNbr();
581 
582  if (lblNbr > size_t(ImDtTypes<T2>::max()))
583  std::cerr << "Label number exceeds data type max!" << std::endl;
584 
585  return lblNbr;
586  }
587 
605  template <class T1, class T2>
606  size_t lambdaLabel(const Image<T1> &imIn, const T1 &lambdaVal,
607  Image<T2> &imOut, const StrElt &se = DEFAULT_SE)
608  {
609  ASSERT_ALLOCATED(&imIn, &imOut);
610  ASSERT_SAME_SIZE(&imIn, &imOut);
611 
612  labelFunctGeneric<T1, T2, lambdaEqualOperator<T1>> f;
613  f.compareFunc.lambda = lambdaVal;
614 
615  ASSERT((f._exec(imIn, imOut, se) == RES_OK), 0);
616 
617  size_t lblNbr = f.getLabelNbr();
618 
619  if (lblNbr > size_t(ImDtTypes<T2>::max()))
620  std::cerr << "Label number exceeds data type max!" << std::endl;
621 
622  return lblNbr;
623  }
624 
633  template <class T1, class T2>
634  size_t fastLabel(const Image<T1> &imIn, Image<T2> &imOut,
635  const StrElt &se = DEFAULT_SE)
636  {
637  ASSERT_ALLOCATED(&imIn, &imOut);
638  ASSERT_SAME_SIZE(&imIn, &imOut);
639 
640  labelFunctFast<T1, T2> f;
641 
642  ASSERT((f._exec(imIn, imOut, se) == RES_OK), 0);
643 
644  size_t lblNbr = f.getLabelNbr();
645 
646  if (lblNbr > size_t(ImDtTypes<T2>::max()))
647  std::cerr << "Label number exceeds data type max!" << std::endl;
648 
649  return lblNbr;
650  }
651 
664  template <class T1, class T2>
665  size_t lambdaFastLabel(const Image<T1> &imIn, const T1 &lambdaVal,
666  Image<T2> &imOut, const StrElt &se = DEFAULT_SE)
667  {
668  ASSERT_ALLOCATED(&imIn, &imOut);
669  ASSERT_SAME_SIZE(&imIn, &imOut);
670 
671  labelFunctFast<T1, T2, lambdaEqualOperator<T1>> f;
672  f.compareFunc.lambda = lambdaVal;
673 
674  ASSERT((f._exec(imIn, imOut, se) == RES_OK), 0);
675 
676  size_t lblNbr = f.getLabelNbr();
677 
678  if (lblNbr < size_t(ImDtTypes<T2>::max()))
679  std::cerr << "Label number exceeds data type max!" << std::endl;
680 
681  return lblNbr;
682  }
683 
685  template <typename T>
686  inline double maxMapValueDouble(map<T, double> &m)
687  {
688  return std::max_element(m.begin(), m.end(), map_comp_value_less())->second;
689  }
690 
691  template <typename T>
692  inline double minMapValueDouble(map<T, double> &m)
693  {
694  return std::min_element(m.begin(), m.end(), map_comp_value_less())->second;
695  }
735  template <typename T1, typename T2, typename T3>
736  size_t
737  labelWithProperty(const Image<T1> &imRegions, const Image<T2> &imIn,
738  Image<T3> & imLabelOut,
739  const string property = "area", bool doRescale = false,
740  double scale = 1., const StrElt &se = DEFAULT_SE)
741  {
742  ASSERT_ALLOCATED(&imIn, &imRegions, &imLabelOut);
743  ASSERT_SAME_SIZE(&imIn, &imRegions, &imLabelOut);
744 
745  vector<double> retVal(3);
746 
747  map<string, int> property2key = {
748  {"area", 1}, {"volume", 2}, {"max", 3}, {"min", 4},
749  {"mean", 5}, {"stddev", 6}, {"median", 7}, {"mode", 8},
750  {"nbvalues", 9}, {"entropy", 10}};
751  if (property2key.find(property) == property2key.end()) {
752  ERR_MSG("Property unknown when calling function labelWithProperty");
753  return 0;
754  }
755  int key = property2key[property];
756 
757  ImageFreezer freezer(imLabelOut);
758 
759  Image<T3> imLabel(imIn);
760 
761  size_t nl = label(imRegions, imLabel, se);
762  if (nl > ImDtTypes<T3>::max()) {
763  string msg =
764  "Increase output image type to include value " + to_string(nl);
765  ERR_MSG(msg);
766  return 0;
767  }
768  if (nl == 0) {
769  ERR_MSG("No labels returned");
770  return nl;
771  }
772  map<T3, Blob> blobs = computeBlobs(imLabel, true);
773  map<T3, double> markers;
774 
775  typedef typename std::map<T3, T2>::iterator itT2_T;
776  typedef typename std::map<T3, std::vector<T2>>::iterator itT2Vec_T;
777  typedef typename std::map<T3, double>::iterator itD_T;
778  typedef typename std::map<T3, std::vector<double>>::iterator itDVec_T;
779 
780  switch (key) {
781  case 1: {
782  // area
783  map<T3, double> values = blobsArea(blobs);
784  for (itD_T iter = values.begin(); iter != values.end(); ++iter) {
785  markers[iter->first] = iter->second;
786  }
787  } break;
788  case 2: {
789  // volume
790  map<T3, double> values = blobsVolume(imIn, blobs);
791  for (itD_T iter = values.begin(); iter != values.end(); ++iter) {
792  markers[iter->first] = iter->second;
793  }
794  } break;
795  case 3: {
796  // min
797  map<T3, T2> values = blobsMinVal(imIn, blobs);
798  for (itT2_T iter = values.begin(); iter != values.end(); ++iter) {
799  markers[iter->first] = iter->second;
800  }
801  } break;
802  case 4: {
803  // max
804  map<T3, T2> values = blobsMaxVal(imIn, blobs);
805  for (itT2_T iter = values.begin(); iter != values.end(); ++iter) {
806  markers[iter->first] = iter->second;
807  }
808  } break;
809  case 5: {
810  // mean
811  map<T3, std::vector<double>> values = blobsMeanVal(imIn, blobs);
812  for (itDVec_T iter = values.begin(); iter != values.end(); ++iter) {
813  markers[iter->first] = (iter->second)[0];
814  }
815  } break;
816  case 6: {
817  // stddev
818  map<T3, std::vector<double>> values = blobsMeanVal(imIn, blobs);
819  for (itDVec_T iter = values.begin(); iter != values.end(); ++iter) {
820  markers[iter->first] = (iter->second)[1];
821  }
822  } break;
823  case 7: {
824  // median
825  map<T3, T2> values = blobsMedianVal(imIn, blobs);
826  for (itT2_T iter = values.begin(); iter != values.end(); ++iter) {
827  markers[iter->first] = iter->second;
828  }
829  } break;
830  case 8: {
831  // median
832  map<T3, T2> values = blobsModeVal(imIn, blobs);
833  for (itT2_T iter = values.begin(); iter != values.end(); ++iter) {
834  markers[iter->first] = iter->second;
835  }
836  } break;
837  case 9: {
838  // values count
839  map<T3, vector<T2>> values = blobsValueList(imIn, blobs);
840  for (itT2Vec_T iter = values.begin(); iter != values.end(); ++iter) {
841  markers[iter->first] = iter->second.size();
842  }
843  } break;
844  case 10: {
845  // entropy
846  map<T3, double> values = blobsEntropy(imIn, blobs);
847  for (itD_T iter = values.begin(); iter != values.end(); ++iter) {
848  markers[iter->first] = iter->second;
849  }
850  } break;
851  default:
852  return 0;
853  break;
854  }
855 
856  ASSERT(!markers.empty());
857 
858  double maxV = maxMapValueDouble(markers);
859  double minV = minMapValueDouble(markers);
860  double maxT = double(ImDtTypes<T3>::max());
861 
862  retVal[1] = minV;
863  retVal[2] = maxV;
864 
865  if (doRescale) {
866  if (maxV > minV) {
867  double k = (maxT - 1.) / (maxV - minV);
868  for (auto it = markers.begin(); it != markers.end(); it++) {
869  if (it->second > 0)
870  it->second = 1. + k * (it->second - minV);
871  }
872  cout << " Values where rescaled :" << endl;
873  cout << " Min : \t" << minV << "\t=> " << 1. << endl;
874  cout << " Max : \t" << maxV << "\t=> " << maxT << endl;
875  maxV = maxMapValueDouble(markers);
876  }
877  } else {
878  if (abs(scale - 1.) > 0.001)
879  {
880  for (auto it = markers.begin(); it != markers.end(); it++)
881  it->second *= scale;
882  }
883  }
884  if (maxV > maxT) {
885  stringstream ss;
886  ss << "Max " << property << " value (" << maxV
887  << ") exceeds data type upper limit (" << maxT << ")";
888  ERR_MSG(ss.str());
889  return 0;
890  }
891 
892  if (applyLookup(imLabel, markers, imLabelOut) != RES_OK)
893  return 0;
894 
895  retVal[0] = nl;
896  return nl;
897  }
898 
918  template <class T1, class T2>
919  size_t labelWithArea(const Image<T1> &imIn, Image<T2> &imOut,
920  const StrElt &se = DEFAULT_SE)
921  {
922 #if 1
923  return labelWithProperty(imIn, imIn, imOut, "area", false, 1., se);
924 #else
925  ASSERT_ALLOCATED(&imIn, &imOut);
926  ASSERT_SAME_SIZE(&imIn, &imOut);
927 
928  ImageFreezer freezer(imOut);
929 
930  Image<T2> imLabel(imIn);
931 
932  ASSERT(label(imIn, imLabel, se) != 0);
933  map<T2, double> areas = blobsArea(imLabel);
934  ASSERT(!areas.empty());
935 
936  double maxV =
937  std::max_element(areas.begin(), areas.end(), map_comp_value_less())
938  ->second;
939  ASSERT((maxV < double(ImDtTypes<T2>::max())),
940  "Areas max value exceeds data type max!", 0);
941 
942  ASSERT(applyLookup(imLabel, areas, imOut) == RES_OK);
943 
944  return RES_OK;
945 #endif
946  }
947 
968  template <class T1, class T2>
969  size_t labelWithVolume(const Image<T1> &imIn, const Image<T2> &imLabelIn,
970  Image<T2> &imLabelOut, const StrElt &se = DEFAULT_SE)
971  {
972 #if 1
973  return labelWithProperty(imLabelIn, imIn, imLabelOut, "volume", false, 1.,
974  se);
975 #else
976  ASSERT_ALLOCATED(&imIn, &imLabelOut);
977  ASSERT_SAME_SIZE(&imIn, &imLabelOut);
978 
979  ImageFreezer freezer(imLabelOut);
980 
981  Image<T2> imLabel(imIn);
982 
983  ASSERT(label(imLabelIn, imLabel, se) != 0);
984  label(imLabelIn, imLabel, se);
985  bool onlyNonZeros = true;
986  map<T2, Blob> blobs = computeBlobs(imLabel, onlyNonZeros);
987  map<T2, double> volumes = blobsVolume(imIn, blobs);
988  ASSERT(!volumes.empty());
989 
990  double maxV =
991  std::max_element(volumes.begin(), volumes.end(), map_comp_value_less())
992  ->second;
993  cout << maxV << endl;
994  ASSERT((maxV < double(ImDtTypes<T2>::max())),
995  "Volumes max value exceeds data type max!", 0);
996 
997  ASSERT(applyLookup(imLabel, volumes, imLabelOut) == RES_OK);
998 
999  return RES_OK;
1000 #endif
1001  }
1002 
1023  template <class T1, class T2>
1024  size_t labelWithMax(const Image<T1> &imIn, const Image<T2> &imLabelIn,
1025  Image<T2> &imLabelOut, const StrElt &se = DEFAULT_SE)
1026  {
1027 #if 1
1028  return labelWithProperty(imLabelIn, imIn, imLabelOut, "max", false, 1., se);
1029 #else
1030  ASSERT_ALLOCATED(&imIn, &imLabelOut);
1031  ASSERT_SAME_SIZE(&imIn, &imLabelOut);
1032 
1033  ImageFreezer freezer(imLabelOut);
1034 
1035  Image<T2> imLabel(imIn);
1036 
1037  ASSERT(label(imLabelIn, imLabel, se) != 0);
1038  label(imLabelIn, imLabel, se);
1039  bool onlyNonZeros = true;
1040  map<T2, Blob> blobs = computeBlobs(imLabel, onlyNonZeros);
1041  map<T2, T1> markers = blobsMaxVal(imIn, blobs);
1042  ASSERT(!markers.empty());
1043 
1044  double maxV =
1045  std::max_element(markers.begin(), markers.end(), map_comp_value_less())
1046  ->second;
1047  // cout << maxV << endl;
1048  ASSERT((maxV < double(ImDtTypes<T2>::max())),
1049  "Markers max value exceeds data type max!", 0);
1050 
1051  ASSERT(applyLookup(imLabel, markers, imLabelOut) == RES_OK);
1052 
1053  return RES_OK;
1054 #endif
1055  }
1056 
1077  template <class T1, class T2>
1078  size_t labelWithMean(const Image<T1> &imIn, const Image<T2> &imLabelIn,
1079  Image<T1> &imLabelOut, const StrElt &se = DEFAULT_SE)
1080  {
1081 #if 1
1082  return labelWithProperty(imLabelIn, imIn, imLabelOut, "mean", false, 1.,
1083  se);
1084 #else
1085  ASSERT_ALLOCATED(&imIn, &imLabelOut);
1086  ASSERT_SAME_SIZE(&imIn, &imLabelOut);
1087 
1088  ImageFreezer freezer(imLabelOut);
1089 
1090  Image<T2> imLabel(imIn);
1091 
1092  ASSERT(label(imLabelIn, imLabel, se) != 0);
1093  label(imLabelIn, imLabel, se);
1094  bool onlyNonZeros = true;
1095  map<T2, Blob> blobs = computeBlobs(imLabel, onlyNonZeros);
1096  map<T2, std::vector<double>> meanValsStd = blobsMeanVal(imIn, blobs);
1097  map<T2, double> markers;
1098 
1099  for (typename std::map<T2, std::vector<double>>::iterator iter =
1100  meanValsStd.begin();
1101  iter != meanValsStd.end(); ++iter) {
1102  markers[iter->first] = (iter->second)[0];
1103  // cout << "iter->first = " << iter->first << " iter->second[0] " <<
1104  // iter->second[0] << endl;
1105  }
1106 
1107  ASSERT(!markers.empty());
1108 
1109  double maxV =
1110  std::max_element(markers.begin(), markers.end(), map_comp_value_less())
1111  ->second;
1112  ASSERT((maxV < double(ImDtTypes<T2>::max())),
1113  "Markers max value exceeds data type max!", 0);
1114 
1115  ASSERT(applyLookup(imLabel, markers, imLabelOut) == RES_OK);
1116 
1117  return RES_OK;
1118 #endif
1119  }
1120 
1122  template <class T1, class T2>
1123  class neighborsFunct : public MorphImageFunctionBase<T1, T2>
1124  {
1125  public:
1126  typedef MorphImageFunctionBase<T1, T2> parentClass;
1127 
1128  virtual inline void processPixel(size_t pointOffset,
1129  vector<int> &dOffsetList)
1130  {
1131  vector<T1> vals;
1132  UINT nbrValues = 0;
1133  vector<int>::iterator dOffset = dOffsetList.begin();
1134  while (dOffset != dOffsetList.end()) {
1135  T1 val = parentClass::pixelsIn[pointOffset + *dOffset];
1136  if (find(vals.begin(), vals.end(), val) == vals.end()) {
1137  vals.push_back(val);
1138  nbrValues++;
1139  }
1140  dOffset++;
1141  }
1142  parentClass::pixelsOut[pointOffset] = T2(nbrValues);
1143  }
1144  };
1159  template <class T1, class T2>
1160  RES_T neighbors(const Image<T1> &imIn, Image<T2> &imOut,
1161  const StrElt &se = DEFAULT_SE)
1162  {
1163  ASSERT_ALLOCATED(&imIn, &imOut);
1164  ASSERT_SAME_SIZE(&imIn, &imOut);
1165 
1166  neighborsFunct<T1, T2> f;
1167 
1168  ASSERT((f._exec(imIn, imOut, se) == RES_OK));
1169 
1170  return RES_OK;
1171  }
1172 
1175 } // namespace smil
1176 
1177 #endif // _D_MORPHO_LABEL_HPP
Definition: DBaseImage.h:386
Base structuring element.
Definition: DStructuringElement.h:68
RES_T sub(const Image< T > &imIn1, const Image< T > &imIn2, Image< T > &imOut)
sub() - Subtraction between two images
Definition: DImageArith.hpp:160
RES_T applyLookup(const Image< T1 > &imIn, const mapT &_map, Image< T2 > &imOut, T2 defaultValue=T2(0))
applyLookup() - Apply a lookup map to a labeled image
Definition: DImageArith.hpp:1990
RES_T fill(Image< T > &imOut, const T &value)
fill() - Fill an image with a given value.
Definition: DImageArith.hpp:1456
map< labelT, double > blobsVolume(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsVolume() - Measure the sum of values of each blob in imIn.
Definition: DBlobMeasures.hpp:91
map< labelT, T > blobsMedianVal(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsMedianVal() - Measure the median value of imIn in each blob.
Definition: DBlobMeasures.hpp:193
map< T, Blob > computeBlobs(const Image< T > &imIn, bool onlyNonZero=true)
Create a map of blobs from a labeled image.
Definition: DBlob.hpp:98
map< labelT, double > blobsEntropy(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsEntropy() - Measure blobs entropy.
Definition: DBlobMeasures.hpp:340
map< labelT, Vector_double > blobsMeanVal(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsMeanVal() - Measure the mean value and the std dev.
Definition: DBlobMeasures.hpp:150
map< labelT, T > blobsMaxVal(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsMaxVal() - Measure the maximum value of each blob in imIn.
Definition: DBlobMeasures.hpp:120
map< labelT, T > blobsMinVal(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsMinVal() - Measure the minimum value of each blob in imIn.
Definition: DBlobMeasures.hpp:106
map< labelT, T > blobsModeVal(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsModeVal() - Measure the mode value of imIn in each blob.
Definition: DBlobMeasures.hpp:180
map< labelT, vector< T > > blobsValueList(const Image< T > &imIn, map< labelT, Blob > &blobs)
blobsValueList() - Measure the list of values of each blob in imIn.
Definition: DBlobMeasures.hpp:165
map< T, double > blobsArea(const Image< T > &imLbl, const bool onlyNonZero=true)
blobsArea() - Calculate the area of each region in a labeled image
Definition: DBlobMeasures.hpp:60
Point< int > IntPoint
IntPoint.
Definition: DCommon.h:212
RES_T neighbors(const Image< T1 > &imIn, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
neighbors() - Neighbors count
Definition: DMorphoLabel.hpp:1160
size_t labelWithVolume(const Image< T1 > &imIn, const Image< T2 > &imLabelIn, Image< T2 > &imLabelOut, const StrElt &se=DEFAULT_SE)
labelWithVolume() - Image labelization with the volume (sum of values) of each connected components i...
Definition: DMorphoLabel.hpp:969
size_t label(const Image< T1 > &imIn, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
label() - Image labelization
Definition: DMorphoLabel.hpp:564
size_t labelWithMax(const Image< T1 > &imIn, const Image< T2 > &imLabelIn, Image< T2 > &imLabelOut, const StrElt &se=DEFAULT_SE)
labelwithMax() - Image labelization with the maximum values of each connected components in the imLab...
Definition: DMorphoLabel.hpp:1024
size_t labelWithProperty(const Image< T1 > &imRegions, const Image< T2 > &imIn, Image< T3 > &imLabelOut, const string property="area", bool doRescale=false, double scale=1., const StrElt &se=DEFAULT_SE)
labelWithProperty() - Image labelization with the value of the property of each connected components ...
Definition: DMorphoLabel.hpp:737
size_t fastLabel(const Image< T1 > &imIn, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
fastLabel() - Image labelization (faster, use OpenMP)
Definition: DMorphoLabel.hpp:634
size_t labelWithArea(const Image< T1 > &imIn, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
labelWithArea() - Image labelization with the size (area) of each connected components
Definition: DMorphoLabel.hpp:919
size_t lambdaLabel(const Image< T1 > &imIn, const T1 &lambdaVal, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
lambdaLabel() - Lambda-flat zones labelization
Definition: DMorphoLabel.hpp:606
size_t labelWithMean(const Image< T1 > &imIn, const Image< T2 > &imLabelIn, Image< T1 > &imLabelOut, const StrElt &se=DEFAULT_SE)
labelWithMean() - Image labelization with the mean values of each connected components in the imLabel...
Definition: DMorphoLabel.hpp:1078
size_t lambdaFastLabel(const Image< T1 > &imIn, const T1 &lambdaVal, Image< T2 > &imOut, const StrElt &se=DEFAULT_SE)
lambdaFastLabel() - Lambda-flat zones labelization (faster, use OpenMP)
Definition: DMorphoLabel.hpp:665
RES_T erode(const Image< T > &imIn, Image< T > &imOut, const StrElt &se=DEFAULT_SE, const T borderVal=ImDtTypes< T >::max())
erode() - Morphological grayscale erosion
Definition: DMorphoBase.hpp:112
RES_T clone(const Image< T > &imIn, Image< T > &imOut)
clone() - Clone an image
Definition: DImageTransform.hpp:265
RES_T scale(Image< T > &imIn, double kx, double ky, double kz, Image< T > &imOut, string method="trilinear")
scale() - 3D image scale (resize by a factor)
Definition: DImageTransform.hpp:1265
Definition: DTypes.hpp:88
Definition: DCommon.h:111