Ocean
Clustering.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_CV_SEGMENTATION_CLUSTERING_H
9 #define META_OCEAN_CV_SEGMENTATION_CLUSTERING_H
10 
12 
13 #include "ocean/base/Utilities.h"
14 #include "ocean/base/RandomI.h"
15 #include "ocean/base/Worker.h"
16 
17 namespace Ocean
18 {
19 
20 namespace CV
21 {
22 
23 namespace Segmentation
24 {
25 
26 /**
27  * This class implements simple clustering functions for image information.
28  * @tparam tChannels The number of data channels of the image information to be clustered, with range [1, infinity)
29  * @ingroup cvsegmentation
30  */
31 template <unsigned int tChannels>
33 {
34  public:
35 
36  /**
37  * This class implements a single data to be clustered.
38  */
39  class Data
40  {
41  public:
42 
43  /**
44  * Creates a default data object.
45  */
46  Data() = default;
47 
48  /**
49  * Creates a new data object.
50  * @param value The values of the data object
51  * @param id The id of the data
52  */
53  inline Data(const uint8_t* const value, const unsigned int id);
54 
55  /**
56  * Returns a specified element of this data object.
57  * @param channel The channel of the element to be returned
58  * @return Data value
59  */
60  inline uint8_t value(unsigned int channel) const;
61 
62  /**
63  * Returns the id of this data object.
64  * @return The object's id
65  */
66  inline unsigned int id() const;
67 
68  /**
69  * Returns the number of channels this data object stores.
70  * @return Number of channels
71  */
72  inline unsigned int channels() const;
73 
74  /**
75  * Returns the ssd between two data values.
76  * @param data Second data object.
77  * @return Resulting ssd
78  */
79  inline unsigned int ssd(const Data& data) const;
80 
81  /**
82  * Returns the ssd between this data value and an array of elements.
83  * @param values Second data object.
84  * @return Resulting ssd
85  */
86  inline unsigned int ssd(const uint8_t* values) const;
87 
88  /**
89  * Returns whether all per-channel square differences are below a given threshold.
90  * @param data The second data object to be used
91  * @param sqrChannel The per-channel threshold
92  * @return True, if so
93  */
94  inline bool ssd(const Data& data, const unsigned int sqrChannel) const;
95 
96  /**
97  * Returns whether all per-channel square differences are below a given threshold.
98  * @param values The second values to be used
99  * @param sqrChannel The per-channel threshold
100  * @return True, if so
101  */
102  inline bool ssd(const uint8_t* values, const unsigned int sqrChannel) const;
103 
104  /**
105  * Returns the data of this object.
106  * @return Encapsulated data of this object
107  */
108  inline const uint8_t* operator()() const;
109 
110  private:
111 
112  /// The values.
113  uint8_t values_[tChannels] = {0u};
114 
115  /// the id of the data.
116  unsigned int id_ = (unsigned int)(-1);
117  };
118 
119  /**
120  * Definition of a vector holding data object.
121  */
122  typedef std::vector<Data> Datas;
123 
124  /**
125  * This class implements a single cluster for 3 channel 24 bit data objects.
126  */
127  class Cluster
128  {
129  public:
130 
131  /**
132  * Creates a default cluster object.
133  */
134  Cluster() = default;
135 
136  /**
137  * Copy constructor.
138  * @param cluster The cluster to be copied
139  */
140  Cluster(const Cluster& cluster) = default;
141 
142  /**
143  * Move constructor.
144  * @param cluster The cluster to be moved
145  */
146  Cluster(Cluster&& cluster) noexcept;
147 
148  /**
149  * Creates a new cluster object by a given center position.
150  * @param center The center positions
151  * @param expectedElements Optional number of expected elements to reserve memory
152  */
153  explicit inline Cluster(const uint8_t* center, const size_t expectedElements = 0);
154 
155  /**
156  * Returns the first center value of this cluster.
157  * @param channel The channel to return the center value for, with range [0, tChannels- 1]
158  * @return Center value
159  */
160  inline uint8_t center(const unsigned int channel) const;
161 
162  /**
163  * Returns the variance of the first value.
164  * @param channel The channel to return the variance for, with range [0, tChannels - 1]
165  * @return First variance
166  */
167  inline unsigned int variance(const unsigned int channel) const;
168 
169  /**
170  * Returns the centers of this cluster.
171  * @return Cluster centers
172  */
173  inline const uint8_t* centers() const;
174 
175  /**
176  * Returns the elements of this cluster.
177  * @return Cluster elements
178  */
179  inline const Datas& datas() const;
180 
181  /**
182  * Returns the number of elements this cluster holds.
183  * @return Cluster size
184  */
185  inline size_t size() const;
186 
187  /**
188  * Adds a new data value object to this cluster.
189  * @param data The data object to be added
190  */
191  inline void addData(const Data& data);
192 
193  /**
194  * Calculates or updates the value variance of this cluster.
195  */
196  void calculateVariance();
197 
198  /**
199  * Returns whether this cluster holds at least one element.
200  * @return True if so
201  */
202  explicit inline operator bool() const;
203 
204  /**
205  * Returns whether this cluster holds more elements than a second one.
206  * @param cluster Second cluster object to compare
207  * @return True, if so
208  */
209  inline bool operator<(const Cluster& cluster) const;
210 
211  /**
212  * Move operator
213  * @param right The right cluster to assign
214  * @return Reference to this cluster
215  */
216  Cluster& operator=(Cluster&& right) noexcept;
217 
218  private:
219 
220  // Center values.
221  uint8_t centers_[tChannels] = {0u};
222 
223  /// Variance values.
224  unsigned int variances_[tChannels] = {0u};
225 
226  /// Data values of this cluster.
228  };
229 
230  /// Definition of a vector holding cluster objects.
231  typedef std::vector<Cluster> Clusters;
232 
233  /**
234  * This class implements the management of clusters.
235  */
237  {
238  public:
239 
240  /**
241  * Creates a new segmentation object.
242  */
243  Segmentation() = default;
244 
245  /**
246  * Creates a new segmentation object.
247  * @param clusters The clusters defining the segmentation
248  */
249  explicit Segmentation(const Clusters& clusters);
250 
251  /**
252  * Move constructor.
253  * @param segmentation The segmentation to be moved
254  */
255  Segmentation(Segmentation&& segmentation) noexcept;
256 
257  /**
258  * Returns the clusters defined by this segmentation.
259  * @return Segmentation clusters
260  */
261  inline const Clusters& clusters() const;
262 
263  /**
264  * Returns the average cluster size.
265  * @return Average cluster size
266  */
267  inline float averageClusterSize() const;
268 
269  /**
270  * Returns the maximal cluster size of this segmentation.
271  * @return Maximal cluster size
272  */
273  inline size_t maximalClusterSize() const;
274 
275  /**
276  * Compares two segmentation regarding to the maximal cluster size.
277  * @param first The first segmentation object
278  * @param second the second segmentation object
279  */
280  static inline bool compareMaximalClusterSize(const Segmentation& first, const Segmentation& second);
281 
282  /**
283  * Move operator
284  * @param right The right segmentation to assign
285  * @return Reference to this segmentation
286  */
287  Segmentation& operator=(Segmentation&& right) noexcept;
288 
289  private:
290 
291  /// Clusters of this segmentation object.
293 
294  /// Average cluster size of this segmentation.
295  float averageClusterSize_ = -1.0f;
296 
297  /// Maximal cluster size of this segmentation.
299  };
300 
301  public:
302 
303  /**
304  * Determines a random cluster for data elements by application of one seeking iteration.
305  * @param datas The data objects to distribute into clusters
306  * @param clusterRadius Radius of each cluster
307  * @param randomGenerator Random number generator
308  * @param expectedClusters Optional number of expected clusters allowing to reserve enough space in the beginning
309  * @return Resulting segmentation with clusters
310  */
311  static Segmentation findRandomClusteringOneIteration(const Datas& datas, const unsigned int clusterRadius, RandomGenerator& randomGenerator, const size_t expectedClusters = 20);
312 
313  /**
314  * Determines a random cluster for data elements by application of two seeking iterations.
315  * The first iteration determines all elements belonging to a randomly selected cluster element.<br>
316  * The second iteration seeks all element belonging to the average data as determined by the first iteration.<br>
317  * @param datas The data objects to distribute into clusters
318  * @param clusterRadius Radius of each cluster
319  * @param randomGenerator Random number generator
320  * @param expectedClusters Optional number of expected clusters allowing to reserve enough space in the beginning
321  * @return Resulting segmentation with clusters
322  */
323  static Segmentation findRandomClusteringTwoIterations(const Datas& datas, const unsigned int clusterRadius, RandomGenerator& randomGenerator, const size_t expectedClusters = 20);
324 
325  /**
326  * Determines an optimal cluster from a set of random clusters for 3 channel 24 bit data elements
327  * @param datas The data objects to distribute into clusters
328  * @param clusterRadius Radius of a single cluster
329  * @param randomGenerator Random number generator
330  * @param iterations The number of clustering steps, with range [1, infinity)
331  * @param worker Optional worker object to distribute the computation
332  * @param oneIteration State determining whether one ore two seeking iterations are applied for each individual clustering step
333  * @return Resulting optimal segmentation with clusters
334  */
335  static Segmentation findOptimalRandomClustering(const Datas& datas, const unsigned int clusterRadius, RandomGenerator& randomGenerator, const unsigned int iterations = 10u, Worker* worker = nullptr, const bool oneIteration = true);
336 
337  private:
338 
339  /**
340  * Determines an optimal cluster from a set of random clusters for 3 channel 24 bit data elements
341  * @param datas The data objects to distribute into clusters
342  * @param clusterRadius Radius of a single cluster
343  * @param randomGenerator Random number generator
344  * @param segmentation Resulting optimal segmentation
345  * @param oneIteration State determining whether one or two seeking iterations are executed for each clustering
346  * @param firstIteration First iteration to be handled
347  * @param numberIterations Number iterations to be handled
348  * @param iterationIndex Iteration index
349  */
350  static void findOptimalRandomClusteringSubset(const Datas* datas, const unsigned int clusterRadius, RandomGenerator* randomGenerator, Segmentation* segmentation, const bool oneIteration, const unsigned int firstIteration, const unsigned int numberIterations, const unsigned int iterationIndex);
351 };
352 
353 template <unsigned int tChannels>
354 inline Clustering<tChannels>::Data::Data(const uint8_t* const value, const unsigned int id) :
355  id_(id)
356 {
357  ocean_assert(value != nullptr);
358 
359  for (unsigned int n = 0u; n < tChannels; ++n)
360  {
361  values_[n] = value[n];
362  }
363 }
364 
365 template <unsigned int tChannels>
366 inline uint8_t Clustering<tChannels>::Data::value(const unsigned int channel) const
367 {
368  ocean_assert(channel < tChannels);
369 
370  return values_[channel];
371 }
372 
373 template <unsigned int tChannels>
374 inline unsigned int Clustering<tChannels>::Data::id() const
375 {
376  return id_;
377 }
378 
379 template <unsigned int tChannels>
380 inline unsigned int Clustering<tChannels>::Data::channels() const
381 {
382  return tChannels;
383 }
384 
385 template <unsigned int tChannels>
386 inline unsigned int Clustering<tChannels>::Data::ssd(const Data& data) const
387 {
388  unsigned int result = 0u;
389 
390  for (unsigned int n = 0u; n < tChannels; ++n)
391  {
392  result += sqrDistance(values_[n], data.values_[n]);
393  }
394 
395  return result;
396 }
397 
398 template <unsigned int tChannels>
399 inline unsigned int Clustering<tChannels>::Data::ssd(const uint8_t* values) const
400 {
401  ocean_assert(values);
402 
403  unsigned int result = 0u;
404 
405  for (unsigned int n = 0u; n < tChannels; ++n)
406  {
407  result += sqrDistance(values_[n], values[n]);
408  }
409 
410  return result;
411 }
412 
413 template <unsigned int tChannels>
414 inline const uint8_t* Clustering<tChannels>::Data::operator()() const
415 {
416  return values_;
417 }
418 
419 template <unsigned int tChannels>
420 inline bool Clustering<tChannels>::Data::ssd(const Data& data, const unsigned int sqrChannel) const
421 {
422  for (unsigned int n = 0u; n < tChannels; ++n)
423  {
424  if (sqrDistance(values_[n], data.values_[n]) > sqrChannel)
425  {
426  return false;
427  }
428  }
429 
430  return true;
431 }
432 
433 template <unsigned int tChannels>
434 inline bool Clustering<tChannels>::Data::ssd(const uint8_t* values, const unsigned int sqrChannel) const
435 {
436  ocean_assert(values != nullptr);
437 
438  for (unsigned int n = 0u; n < tChannels; ++n)
439  {
440  if (sqrDistance(values_[n], values[n]) > sqrChannel)
441  {
442  return false;
443  }
444  }
445 
446  return true;
447 }
448 
449 template <unsigned int tChannels>
451 {
452  *this = std::move(cluster);
453 }
454 
455 template <unsigned int tChannels>
456 inline Clustering<tChannels>::Cluster::Cluster(const uint8_t* center, const size_t expectedElements)
457 {
458  ocean_assert(center != nullptr);
459 
460  for (unsigned int n = 0u; n < tChannels; ++n)
461  {
462  centers_[n] = center[n];
463  }
464 
465  for (unsigned int n = 0u; n < tChannels; ++n)
466  {
467  variances_[n] = (unsigned int)(-1);
468  }
469 
470  if (expectedElements != 0)
471  {
472  datas_.reserve(expectedElements);
473  }
474 }
475 
476 template <unsigned int tChannels>
477 inline uint8_t Clustering<tChannels>::Cluster::center(const unsigned int channel) const
478 {
479  ocean_assert(channel < tChannels);
480  return centers_[channel];
481 }
482 
483 template <unsigned int tChannels>
484 inline unsigned int Clustering<tChannels>::Cluster::variance(const unsigned int channel) const
485 {
486  ocean_assert(channel < tChannels);
487  ocean_assert(variances_[channel] != (unsigned int)(-1));
488 
489  return variances_[channel];
490 }
491 
492 template <unsigned int tChannels>
493 inline const uint8_t* Clustering<tChannels>::Cluster::centers() const
494 {
495  return centers_;
496 }
497 
498 template <unsigned int tChannels>
500 {
501  return datas_;
502 }
503 
504 template <unsigned int tChannels>
506 {
507  return datas_.size();
508 }
509 
510 template <unsigned int tChannels>
512 {
513  datas_.push_back(data);
514 }
515 
516 template <unsigned int tChannels>
518 {
519  if (datas_.empty())
520  {
521  return;
522  }
523 
524  uint64_t means[tChannels] = {0u};
525  uint64_t sqrMeans[tChannels] = {0u};
526 
527  for (const Data& data : datas_)
528  {
529  for (unsigned int n = 0u; n < tChannels; ++n)
530  {
531  means[n] += uint64_t(data.value(n));
532  }
533 
534  for (unsigned int n = 0u; n < tChannels; ++n)
535  {
536  sqrMeans[n] += uint64_t(sqr(data.value(n)));
537  }
538  }
539 
540  for (unsigned int n = 0u; n < tChannels; ++n)
541  {
542  variances_[n] = (unsigned int)((sqrMeans[n] * uint64_t(datas_.size()) - sqr(means[n])) / sqr(uint64_t(datas_.size())));
543  }
544 }
545 
546 template <unsigned int tChannels>
548 {
549  return !datas_.empty();
550 }
551 
552 template <unsigned int tChannels>
553 inline bool Clustering<tChannels>::Cluster::operator<(const Cluster& cluster) const
554 {
555  return datas_.size() > cluster.datas_.size();
556 }
557 
558 template <unsigned int tChannels>
560 {
561  if (this != &right)
562  {
563  datas_ = std::move(right.datas_);
564 
565  for (unsigned int n = 0u; n < tChannels; ++n)
566  {
567  centers_[n] = right.centers_[n];
568  }
569 
570  for (unsigned int n = 0u; n < tChannels; ++n)
571  {
572  variances_[n] = right.variances_[n];
573  }
574  }
575 
576  return *this;
577 }
578 
579 template <unsigned int tChannels>
581  clusters_(clusters),
582  averageClusterSize_(-1.0f),
583  maximalClusterSize_(0u)
584 {
585  size_t total = 0u;
586 
587  for (const Cluster& cluster : clusters)
588  {
589  if (cluster.size() > maximalClusterSize_)
590  {
591  maximalClusterSize_ = cluster.size();
592  }
593 
594  total += cluster.size();
595  }
596 
597  if (!clusters.empty())
598  {
599  averageClusterSize_ = float(total) / float(clusters.size());
600  }
601 }
602 
603 template <unsigned int tChannels>
605 {
606  *this = std::move(segmentation);
607 }
608 
609 template <unsigned int tChannels>
611 {
612  return clusters_;
613 }
614 
615 template <unsigned int tChannels>
617 {
618  return averageClusterSize_;
619 }
620 
621 template <unsigned int tChannels>
623 {
624  return maximalClusterSize_;
625 }
626 
627 template <unsigned int tChannels>
629 {
630  return first.maximalClusterSize() > second.maximalClusterSize();
631 }
632 
633 template <unsigned int tChannels>
635 {
636  if (this != &right)
637  {
638  clusters_ = std::move(right.clusters_);
639  averageClusterSize_ = right.averageClusterSize_;
640  maximalClusterSize_ = right.maximalClusterSize_;
641  }
642 
643  return *this;
644 }
645 
646 template <unsigned int tChannels>
647 typename Clustering<tChannels>::Segmentation Clustering<tChannels>::findRandomClusteringOneIteration(const Datas& datas, const unsigned int clusterRadius, RandomGenerator& randomGenerator, const size_t expectedClusters)
648 {
649  static_assert(tChannels != 0u, "Invalid channel number!");
650 
651  Datas remainingDatas(datas);
652  const unsigned int sqrClusterRadius = sqr(clusterRadius);
653 
654  Datas tmpDatas;
655  tmpDatas.reserve(datas.size());
656 
657  Clusters clusters;
658  clusters.reserve(expectedClusters);
659 
660  while (!remainingDatas.empty())
661  {
662  const unsigned int randomFingerprintIndex = RandomI::random(randomGenerator, min((unsigned int)remainingDatas.size() - 1u, randomGenerator.randMax()));
663  const Data& randomData = remainingDatas[randomFingerprintIndex];
664 
665  clusters.push_back(Cluster(randomData(), remainingDatas.size()));
666  Cluster& newCluster = clusters.back();
667 
668  tmpDatas.clear();
669 
670  // create new cluster
671  for (typename Datas::const_iterator i = remainingDatas.begin(); i != remainingDatas.end(); ++i)
672  if (randomData.ssd(*i, sqrClusterRadius))
673  newCluster.addData(*i);
674  else
675  tmpDatas.push_back(*i);
676 
677  std::swap(remainingDatas, tmpDatas);
678  }
679 
680  return Segmentation(std::move(clusters));
681 };
682 
683 template <unsigned int tChannels>
684 typename Clustering<tChannels>::Segmentation Clustering<tChannels>::findRandomClusteringTwoIterations(const Datas& datas, const unsigned int clusterRadius, RandomGenerator& randomGenerator, const size_t expectedClusters)
685 {
686  static_assert(tChannels != 0u, "Invalid channel number!");
687 
688  Datas copyDatas(datas);
689 
690  const unsigned int sqrClusterRadius = sqr(clusterRadius);
691 
692  Datas remainingDatas;
693  remainingDatas.reserve(datas.size());
694 
695  Clusters clusters;
696  clusters.reserve(expectedClusters);
697 
698  while (!copyDatas.empty())
699  {
700  const unsigned int randomFingerprintIndex = RandomI::random(randomGenerator, (unsigned int)(copyDatas.size()) - 1u);
701 
702  const Data& randomData = copyDatas[randomFingerprintIndex];
703 
704  // create new cluster
705 
706  unsigned int total[tChannels] = {0u};
707  unsigned int totalNumber = 0u;
708 
709  // front
710  for (const Data& copyData : copyDatas)
711  {
712  if (randomData.ssd(copyData, sqrClusterRadius))
713  {
714  for (unsigned int n = 0u; n < tChannels; ++n)
715  {
716  // check that enough space is left
717  ocean_assert(uint64_t(total[n]) + uint64_t(copyData.value(n)) < uint64_t((unsigned int)(-1)));
718 
719  total[n] += copyData.value(n);
720  }
721 
722  ++totalNumber;
723  }
724  }
725 
726  ocean_assert(totalNumber != 0u);
727 
728  uint8_t centers[tChannels];
729 
730  for (unsigned int n = 0u; n < tChannels; ++n)
731  {
732  const unsigned int center = (total[n] + totalNumber / 2u) / totalNumber;
733  ocean_assert(center <= 255u);
734 
735  centers[n] = uint8_t(center);
736  }
737 
738  clusters.emplace_back(centers, copyDatas.size());
739  Cluster& newCluster = clusters.back();
740 
741  remainingDatas.clear();
742 
743  for (const Data& copyData : copyDatas)
744  {
745  if (copyData.ssd(newCluster.centers(), sqrClusterRadius))
746  {
747  newCluster.addData(copyData);
748  }
749  else
750  {
751  remainingDatas.emplace_back(copyData);
752  }
753  }
754 
755  std::swap(copyDatas, remainingDatas);
756  }
757 
758  return Segmentation(std::move(clusters));
759 };
760 
761 template <unsigned int tChannels>
762 typename Clustering<tChannels>::Segmentation Clustering<tChannels>::findOptimalRandomClustering(const Datas& datas, const unsigned int clusterRadius, RandomGenerator& randomGenerator, const unsigned int iterations, Worker* worker, const bool oneIteration)
763 {
764  static_assert(tChannels != 0u, "Invalid channel number!");
765 
766  ocean_assert(!datas.empty() && iterations > 0u);
767 
768  if (datas.empty() || iterations == 0u)
769  {
770  return Segmentation();
771  }
772 
773  if (worker)
774  {
775  std::vector<Segmentation> results(worker->threads());
776  ocean_assert(!results.empty());
777 
778  worker->executeFunction(Worker::Function::createStatic(&Clustering<tChannels>::findOptimalRandomClusteringSubset, &datas, clusterRadius, &randomGenerator, &results[0], oneIteration, 0u, 0u, 0u), 0u, iterations, 5u, 6u, 1u, 7u);
779 
780  unsigned int bestIndex = 0u;
781 
782  for (unsigned int n = 1u; n < results.size(); ++n)
783  {
784  if (results[n].clusters().size() < results[bestIndex].clusters().size())
785  {
786  bestIndex = n;
787  }
788  else if (results[n].clusters().size() == results[bestIndex].clusters().size())
789  {
790  /*unsigned int maxVariance = 0u;
791  for (Clusters::const_iterator i = clusters.begin(); i != clusters.end(); ++i)
792  {
793  maxVariance = max(maxVariance, max(i->clusterVariance0, max(i->clusterVariance1, i->clusterVariance2)));
794  }
795 
796  unsigned int testMaxVariance = 0u;
797  for (Clusters::const_iterator i = testClusters.begin(); i != testClusters.end(); ++i)
798  {
799  testMaxVariance = max(maxVariance, max(i->clusterVariance0, max(i->clusterVariance1, i->clusterVariance2)));
800  }
801 
802  if (testMaxVariance < maxVariance)
803  {
804  clusters = testClusters;
805  }*/
806 
807  if (results[n].maximalClusterSize() > results[n].maximalClusterSize())
808  {
809  bestIndex = n;
810  }
811  }
812  }
813 
814  return std::move(results[bestIndex]);
815  }
816  else
817  {
818  Segmentation result;
819  findOptimalRandomClusteringSubset(&datas, clusterRadius, &randomGenerator, &result, oneIteration, 0u, iterations, 0u);
820 
821  return result;
822  }
823 }
824 
825 template <unsigned int tChannels>
826 void Clustering<tChannels>::findOptimalRandomClusteringSubset(const Datas* datas, const unsigned int clusterRadius, RandomGenerator* randomGenerator, Segmentation* segmentation, const bool oneIteration, const unsigned int /*firstIteration*/, const unsigned int numberIterations, const unsigned int iterationIndex)
827 {
828  ocean_assert(datas != nullptr && randomGenerator != nullptr && segmentation != nullptr);
829  ocean_assert(numberIterations > 0u);
830 
831  RandomGenerator generator(*randomGenerator);
832 
833  Segmentation& result = segmentation[iterationIndex];
834 
835  result = oneIteration ? findRandomClusteringOneIteration(*datas, clusterRadius, generator, 20u)
836  : findRandomClusteringTwoIterations(*datas, clusterRadius, generator, 20u);
837 
838  for (unsigned int n = 1u; n < numberIterations; ++n)
839  {
840  Segmentation testSegmentation(oneIteration ? findRandomClusteringOneIteration(*datas, clusterRadius, generator, max(20u, (unsigned int)(result.clusters().size()) * 2u))
841  : findRandomClusteringTwoIterations(*datas, clusterRadius, generator, max(20u, (unsigned int)(result.clusters().size()) * 2u)));
842 
843  if (testSegmentation.clusters().size() < result.clusters().size())
844  {
845  result = std::move(testSegmentation);
846  }
847  else if (testSegmentation.clusters().size() == result.clusters().size())
848  {
849  /*unsigned int maxVariance = 0u;
850  for (Clusters::const_iterator i = clusters.begin(); i != clusters.end(); ++i)
851  {
852  maxVariance = max(maxVariance, max(i->clusterVariance0, max(i->clusterVariance1, i->clusterVariance2)));
853  }
854 
855  unsigned int testMaxVariance = 0u;
856  for (Clusters::const_iterator i = testClusters.begin(); i != testClusters.end(); ++i)
857  {
858  testMaxVariance = max(maxVariance, max(i->clusterVariance0, max(i->clusterVariance1, i->clusterVariance2)));
859  }
860 
861  if (testMaxVariance < maxVariance)
862  {
863  clusters = testClusters;
864  }*/
865 
866  if (testSegmentation.maximalClusterSize() > result.maximalClusterSize())
867  {
868  result = std::move(testSegmentation);
869  }
870  }
871  }
872 }
873 
874 }
875 
876 }
877 
878 }
879 
880 #endif // META_OCEAN_CV_SEGMENTATION_CLUSTERING_H
This class implements a single cluster for 3 channel 24 bit data objects.
Definition: Clustering.h:128
unsigned int variance(const unsigned int channel) const
Returns the variance of the first value.
Definition: Clustering.h:484
Cluster & operator=(Cluster &&right) noexcept
Move operator.
Definition: Clustering.h:559
const Datas & datas() const
Returns the elements of this cluster.
Definition: Clustering.h:499
const uint8_t * centers() const
Returns the centers of this cluster.
Definition: Clustering.h:493
uint8_t center(const unsigned int channel) const
Returns the first center value of this cluster.
Definition: Clustering.h:477
bool operator<(const Cluster &cluster) const
Returns whether this cluster holds more elements than a second one.
Definition: Clustering.h:553
size_t size() const
Returns the number of elements this cluster holds.
Definition: Clustering.h:505
Cluster()=default
Creates a default cluster object.
void addData(const Data &data)
Adds a new data value object to this cluster.
Definition: Clustering.h:511
Datas datas_
Data values of this cluster.
Definition: Clustering.h:227
uint8_t centers_[tChannels]
Definition: Clustering.h:221
void calculateVariance()
Calculates or updates the value variance of this cluster.
Definition: Clustering.h:517
unsigned int variances_[tChannels]
Variance values.
Definition: Clustering.h:224
Cluster(const Cluster &cluster)=default
Copy constructor.
This class implements a single data to be clustered.
Definition: Clustering.h:40
const uint8_t * operator()() const
Returns the data of this object.
Definition: Clustering.h:414
uint8_t value(unsigned int channel) const
Returns a specified element of this data object.
Definition: Clustering.h:366
Data()=default
Creates a default data object.
unsigned int id_
the id of the data.
Definition: Clustering.h:116
unsigned int id() const
Returns the id of this data object.
Definition: Clustering.h:374
unsigned int channels() const
Returns the number of channels this data object stores.
Definition: Clustering.h:380
uint8_t values_[tChannels]
The values.
Definition: Clustering.h:113
unsigned int ssd(const Data &data) const
Returns the ssd between two data values.
Definition: Clustering.h:386
This class implements the management of clusters.
Definition: Clustering.h:237
Segmentation & operator=(Segmentation &&right) noexcept
Move operator.
Definition: Clustering.h:634
float averageClusterSize_
Average cluster size of this segmentation.
Definition: Clustering.h:295
float averageClusterSize() const
Returns the average cluster size.
Definition: Clustering.h:616
Clusters clusters_
Clusters of this segmentation object.
Definition: Clustering.h:292
static bool compareMaximalClusterSize(const Segmentation &first, const Segmentation &second)
Compares two segmentation regarding to the maximal cluster size.
Definition: Clustering.h:628
const Clusters & clusters() const
Returns the clusters defined by this segmentation.
Definition: Clustering.h:610
size_t maximalClusterSize_
Maximal cluster size of this segmentation.
Definition: Clustering.h:298
Segmentation()=default
Creates a new segmentation object.
size_t maximalClusterSize() const
Returns the maximal cluster size of this segmentation.
Definition: Clustering.h:622
This class implements simple clustering functions for image information.
Definition: Clustering.h:33
std::vector< Data > Datas
Definition of a vector holding data object.
Definition: Clustering.h:122
std::vector< Cluster > Clusters
Definition of a vector holding cluster objects.
Definition: Clustering.h:231
static void findOptimalRandomClusteringSubset(const Datas *datas, const unsigned int clusterRadius, RandomGenerator *randomGenerator, Segmentation *segmentation, const bool oneIteration, const unsigned int firstIteration, const unsigned int numberIterations, const unsigned int iterationIndex)
Determines an optimal cluster from a set of random clusters for 3 channel 24 bit data elements.
Definition: Clustering.h:826
static Segmentation findRandomClusteringTwoIterations(const Datas &datas, const unsigned int clusterRadius, RandomGenerator &randomGenerator, const size_t expectedClusters=20)
Determines a random cluster for data elements by application of two seeking iterations.
Definition: Clustering.h:684
static Segmentation findRandomClusteringOneIteration(const Datas &datas, const unsigned int clusterRadius, RandomGenerator &randomGenerator, const size_t expectedClusters=20)
Determines a random cluster for data elements by application of one seeking iteration.
Definition: Clustering.h:647
static Segmentation findOptimalRandomClustering(const Datas &datas, const unsigned int clusterRadius, RandomGenerator &randomGenerator, const unsigned int iterations=10u, Worker *worker=nullptr, const bool oneIteration=true)
Determines an optimal cluster from a set of random clusters for 3 channel 24 bit data elements.
Definition: Clustering.h:762
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition: Caller.h:2876
This class implements a generator for random numbers.
Definition: RandomGenerator.h:42
static constexpr unsigned int randMax()
Returns the maximal random value of this generator.
Definition: RandomGenerator.h:183
static unsigned int random(const unsigned int maxValue)
Returns one random integer value with specified maximum value.
This class implements a worker able to distribute function calls over different threads.
Definition: Worker.h:33
unsigned int threads() const
Returns the number of threads this worker uses.
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
unsigned int sqrDistance(const char first, const char second)
Returns the square distance between two values.
Definition: base/Utilities.h:1089
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition: base/Utilities.h:1029
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15