Ocean
Loading...
Searching...
No Matches
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
14#include "ocean/base/RandomI.h"
15#include "ocean/base/Worker.h"
16
17namespace Ocean
18{
19
20namespace CV
21{
22
23namespace 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 */
31template <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 */
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
353template <unsigned int tChannels>
354inline 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
365template <unsigned int tChannels>
366inline uint8_t Clustering<tChannels>::Data::value(const unsigned int channel) const
367{
368 ocean_assert(channel < tChannels);
369
370 return values_[channel];
371}
372
373template <unsigned int tChannels>
374inline unsigned int Clustering<tChannels>::Data::id() const
375{
376 return id_;
377}
378
379template <unsigned int tChannels>
380inline unsigned int Clustering<tChannels>::Data::channels() const
381{
382 return tChannels;
383}
384
385template <unsigned int tChannels>
386inline 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
398template <unsigned int tChannels>
399inline 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
413template <unsigned int tChannels>
414inline const uint8_t* Clustering<tChannels>::Data::operator()() const
415{
416 return values_;
417}
418
419template <unsigned int tChannels>
420inline 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
433template <unsigned int tChannels>
434inline 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
449template <unsigned int tChannels>
451{
452 *this = std::move(cluster);
453}
454
455template <unsigned int tChannels>
456inline 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
476template <unsigned int tChannels>
477inline uint8_t Clustering<tChannels>::Cluster::center(const unsigned int channel) const
478{
479 ocean_assert(channel < tChannels);
480 return centers_[channel];
481}
482
483template <unsigned int tChannels>
484inline 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
492template <unsigned int tChannels>
493inline const uint8_t* Clustering<tChannels>::Cluster::centers() const
494{
495 return centers_;
496}
497
498template <unsigned int tChannels>
500{
501 return datas_;
502}
503
504template <unsigned int tChannels>
506{
507 return datas_.size();
508}
509
510template <unsigned int tChannels>
512{
513 datas_.push_back(data);
514}
515
516template <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
546template <unsigned int tChannels>
548{
549 return !datas_.empty();
550}
551
552template <unsigned int tChannels>
553inline bool Clustering<tChannels>::Cluster::operator<(const Cluster& cluster) const
554{
555 return datas_.size() > cluster.datas_.size();
556}
557
558template <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
579template <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
603template <unsigned int tChannels>
605{
606 *this = std::move(segmentation);
607}
608
609template <unsigned int tChannels>
611{
612 return clusters_;
613}
614
615template <unsigned int tChannels>
617{
618 return averageClusterSize_;
619}
620
621template <unsigned int tChannels>
623{
624 return maximalClusterSize_;
625}
626
627template <unsigned int tChannels>
629{
630 return first.maximalClusterSize() > second.maximalClusterSize();
631}
632
633template <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
646template <unsigned int tChannels>
647typename 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
683template <unsigned int tChannels>
684typename 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
761template <unsigned int tChannels>
762typename 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
825template <unsigned int tChannels>
826void 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