PICCANTE  0.4
The hottest HDR imaging library!
connected_components.hpp
Go to the documentation of this file.
1 /*
2 
3 PICCANTE
4 The hottest HDR imaging library!
5 http://vcg.isti.cnr.it/piccante
6 
7 Copyright (C) 2014
8 Visual Computing Laboratory - ISTI CNR
9 http://vcg.isti.cnr.it
10 First author: Francesco Banterle
11 
12 This Source Code Form is subject to the terms of the Mozilla Public
13 License, v. 2.0. If a copy of the MPL was not distributed with this
14 file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 
16 */
17 
18 #ifndef PIC_ALGORITHMS_CONNECTED_COMPONENTS_HPP
19 #define PIC_ALGORITHMS_CONNECTED_COMPONENTS_HPP
20 
21 #include <vector>
22 #include <set>
23 #include <map>
24 #include <utility>
25 
26 #include "../base.hpp"
27 
28 #include "../image.hpp"
29 
30 #include "../util/buffer.hpp"
31 
32 namespace pic {
33 
34 struct LabelInfo
35 {
38 
39  friend bool operator<(LabelInfo const &a, LabelInfo const &b)
40  {
41  return a.id < b.id;
42  }
43 };
44 
46 {
47 public:
49  std::vector< int > coords;
50  std::set< int > neighbors;
51  bool bValid;
52 
54  {
55  id = 0;
56  bValid = true;
57  }
58 
59  LabelOutput(uint id, int i)
60  {
61  this->id = id;
62  coords.push_back(i);
63  bValid = true;
64  }
65 
66  void push_back(int i)
67  {
68  coords.push_back(i);
69  }
70 
71  friend bool operator<(LabelOutput const &a, LabelOutput const &b)
72  {
73  return a.id < b.id;
74  }
75 };
76 
77 template<class T>
79 {
80 protected:
81  float thr;
82 
88  void secondPass(uint *imgOut, std::vector<LabelOutput> &ret, std::set<LabelInfo> &labelEq, int n)
89  {
90  //Label Search
91  LabelInfo tmpLI;
92  std::set<LabelInfo> labelEq_new;
93 
94  for(auto it2 = labelEq.begin() ; it2 != labelEq.end(); it2++) {
95  auto minVal = it2->minLabel;
96  bool test = true;
97 
98  while(test) {
99  test = false;
100  tmpLI.id = minVal;
101  auto it = labelEq.find(tmpLI);
102 
103  if(it != labelEq.end()) {
104  auto tmpMinLabel = (*it).minLabel;
105 
106  if(minVal > tmpMinLabel) {
107  minVal = tmpMinLabel;
108  test = true;
109  }
110  }
111  }
112 
113  LabelInfo tmp_it;
114  tmp_it.id = it2->id;
115  tmp_it.minLabel = minVal;
116  labelEq_new.insert(tmp_it);
117  }
118 
119  //Second pass: using tracked neighbors
120  //for assigning the correct labels
121  //TO DO: optimizing outside this loop
122  std::set<uint> unique;
123  //std::set<uint>::iterator uniqueIt;
124  std::map<uint, int> mapping;
125 
126  int counter = 0;
127 
128  for(int i = 0; i < n; i++) {
129  tmpLI.id = imgOut[i];
130  auto it = labelEq_new.find(tmpLI);
131 
132  if(it != labelEq_new.end()) {
133  imgOut[i] = it->minLabel;
134  }
135 
136  //store coordiantes of the connected components
137  auto id = imgOut[i];
138  auto uniqueIt = unique.find(id);
139 
140  if(uniqueIt != unique.end()) {
141  ret[mapping[id]].push_back(i);
142  } else {
143  std::pair<uint, int> tmp = std::make_pair(id, counter);
144  mapping.insert(tmp);
145 
146  LabelOutput tmpRet(id, i);
147  ret.push_back(tmpRet);
148 
149  unique.insert(id);
150  counter++;
151  }
152  }
153  }
154 
155  void track(uint *imgOut, int &label, std::set<LabelInfo> &labelEq,
156  int neighbors[2], int nNeighbors, int ind)
157  {
158  std::set<LabelInfo>::iterator it;
159  //No neighbors?
160  if(nNeighbors == 0) {
161  imgOut[ind] = label;
162  label++;
163  }
164 
165  if(nNeighbors == 1) {
166  imgOut[ind] = imgOut[neighbors[0]];
167  }
168 
169  if(nNeighbors == 2) {
170  //Assign the label of neighbors
171  uint minVal, t1, t2;
172  t1 = imgOut[neighbors[0]];
173  t2 = imgOut[neighbors[1]];
174  minVal = MIN(t1, t2);
175 
176  //Track neighbors
177  LabelInfo tmpLI;
178  bool test = true;
179 
180  while(test) {
181  test = false;
182  tmpLI.id = minVal;
183  it = labelEq.find(tmpLI);
184 
185  if(it != labelEq.end()) {
186  float tmpMinLabel = it->minLabel;
187 
188  if(minVal > tmpMinLabel) {
189  minVal = tmpMinLabel;
190  test = true;
191  }
192  }
193  }
194 
195  imgOut[ind] = minVal;
196 
197  //Track T1
198  test = true;
199  tmpLI.id = t1;
200  it = labelEq.find(tmpLI);
201 
202  if(it != labelEq.end()) {
203  LabelInfo tmp_it;
204  tmp_it.id = it->id;
205  tmp_it.minLabel = minVal;
206 
207  labelEq.erase(it);
208  labelEq.insert(tmp_it);
209  } else {
210  LabelInfo tmpLabelInfo;
211  tmpLabelInfo.id = t1;
212  tmpLabelInfo.minLabel = minVal;
213  labelEq.insert(tmpLabelInfo);
214  }
215 
216  //Track T2
217  tmpLI.id = t2;
218  it = labelEq.find(tmpLI);
219 
220  if(it != labelEq.end()) {
221  LabelInfo tmp_it;
222  tmp_it.id = it->id;
223  tmp_it.minLabel = minVal;
224 
225  labelEq.erase(it);
226  labelEq.insert(tmp_it);
227  } else {
228  LabelInfo tmpLabelInfo;
229  tmpLabelInfo.id = t2;
230  tmpLabelInfo.minLabel = minVal;
231  labelEq.insert(tmpLabelInfo);
232  }
233  }
234  }
235 
236 public:
237 
242  ConnectedComponents(float thr = 0.05f)
243  {
244  this->thr = thr > 0.0f ? thr : 0.05f;
245  }
246 
253  uint *execute(Image *imgIn, uint *imgOut, std::vector<LabelOutput> &ret)
254  {
255  //Check input paramters
256  if(imgIn == NULL) {
257  return imgOut;
258  }
259 
260  float *data = imgIn->data;
261  int width = imgIn->width;
262  int height = imgIn->height;
263  int channels = imgIn->channels;
264 
265  int n = width * height;
266 
267  if(imgOut == NULL) {
268  imgOut = new uint[n];
269  }
270 
271  Buffer<uint>::assign(imgOut, n, 0);
272 
273  //First pass:
274  // 1) assign basics labels
275  // 2) generate the list of neighbors
276  int label = 1;
277  std::set<LabelInfo> labelEq;
278  for(int j = 0; j < height; j++) {
279  int indY = j * width;
280 
281  for(int i = 0; i < width; i++) {
282  int ind = (indY + i);
283 
284  int ind_img = ind * channels;
285 
286  //neighbors
287  int neighbors[2];
288  int nNeighbors = 0;
289 
290  if((i - 1) > -1) {
291  int ind_img_prev = ind_img - channels;
292 
293  float n1 = Arrayf::norm(&data[ind_img], channels);
294  float n2 = Arrayf::norm(&data[ind_img_prev], channels);
295  float dist = sqrtf(Arrayf::distanceSq(&data[ind_img], &data[ind_img_prev], channels));
296 
297  if(dist <= (thr * MAX(n1, n2))) {
298  neighbors[0] = ind - 1;
299  nNeighbors++;
300  }
301  }
302 
303  if((j - 1) > -1) {
304  int ind_img_prev = ind_img - (width * channels);
305 
306  float n1 = Arrayf::norm(&data[ind_img], channels);
307  float n2 = Arrayf::norm(&data[ind_img_prev], channels);
308  float dist = sqrtf(Arrayf::distanceSq(&data[ind_img], &data[ind_img_prev], channels));
309 
310  if(dist <= (thr * MAX(n1, n2))) {
311  neighbors[nNeighbors] = ind - width;
312  nNeighbors++;
313  }
314  }
315 
316  track(imgOut, label, labelEq, neighbors, nNeighbors, ind);
317  }
318  }
319 
320  secondPass(imgOut, ret, labelEq, n);
321  return imgOut;
322  }
323 
333  uint *execute(T *imgIn, int width, int height, uint *imgOut, std::vector<LabelOutput> &ret)
334  {
335  //Check input paramters
336  if(imgIn == NULL) {
337  return imgOut;
338  }
339 
340  int n = width * height;
341 
342  if(imgOut == NULL) {
343  imgOut = new uint[n];
344  }
345 
346  Buffer<uint>::assign(imgOut, n, 0);
347 
348  T *data = imgIn;
349  //First pass:
350  // 1) assign basics labels
351  // 2) generate the list of neighbors
352  int label = 1;
353  std::set<LabelInfo> labelEq;
354  for(int j = 0; j < height; j++) {
355  int indY = j * width;
356 
357  for(int i = 0; i < width; i++) {
358  int ind = (indY + i);
359 
360  //neighbors
361  int neighbors[2];
362  int nNeighbors = 0;
363 
364  if((i - 1) > -1) {
365  int ind_prev = ind - 1;
366  if(data[ind] == data[ind_prev]) {
367  neighbors[0] = ind_prev;
368  nNeighbors++;
369  }
370  }
371 
372  if((j - 1) > -1) {
373  int ind_prev = ind - width;
374  if(data[ind] == data[ind_prev]) {
375  neighbors[nNeighbors] = ind_prev;
376  nNeighbors++;
377  }
378  }
379 
380  track(imgOut, label, labelEq, neighbors, nNeighbors, ind);
381  }
382  }
383 
384  secondPass(imgOut, ret, labelEq, n);
385  return imgOut;
386  }
387 
394  static uint *reCount(uint *imgLabel, std::vector<LabelOutput> &labelsList)
395  {
396  if(imgLabel == NULL) {
397  return NULL;
398  }
399 
400  uint c = 0;
401  for(uint i = 0; i < labelsList.size(); i++) {
402  if(labelsList[i].bValid) {
403  labelsList[i].id = c;
404  IndexedArrayui::assign(imgLabel, labelsList[i].coords, c);
405  c++;
406  }
407  }
408 
409  return imgLabel;
410  }
411 
420  static Image* convertFromIntegerToImage(uint *imgLabel, Image *imgOut, int width, int height)
421  {
422  if(imgLabel == NULL) {
423  return imgOut;
424  }
425 
426  if(imgOut == NULL) {
427  imgOut = new Image(1, width, height, 1);
428  }
429 
430  int n = width * height;
431  for(int i = 0; i < n; i++) {
432  imgOut->data[i] = float(imgLabel[i]);
433  }
434 
435  return imgOut;
436  }
437 
444  static void computeLabelsListFromImageLabels(uint *labels, int n, std::vector<LabelOutput> &labelsList)
445  {
446  if(labels == NULL || n < 1) {
447  return;
448  }
449 
450  labelsList.clear();
451 
452  std::set<uint> labels_tracker;
453 
454  std::map<uint, int> labels_map;
455 
456  int c = 0;
457  for(int i = 0; i < n; i++) {
458  uint j = labels[i];
459  auto search = labels_tracker.find(j);
460  if (search != labels_tracker.end()) {
461  labels_tracker.insert(j);
462  labels_map[j] = c;
463 
464  LabelOutput tmp;
465  tmp.id = j;
466  labelsList.push_back(tmp);
467 
468  c++;
469  }
470 
471  labelsList[labels_map[j]].push_back(i);
472  }
473  }
474 
482  static uint *computeImageLabelsFromLabelsList(std::vector<LabelOutput> &labelsList, uint *labels, int n)
483  {
484  if(n < 1 || labelsList.empty()) {
485  return labels;
486  }
487 
488  if(labels == NULL) {
489  labels = new uint[n];
490  }
491 
492  for(uint i = 0; i < labelsList.size(); i++) {
493  if(labelsList[i].bValid) {
494  for(uint j = 0; j < labelsList[i].coords.size(); j++) {
495  int k = labelsList[i].coords[j];
496  labels[k] = labelsList[i].id;
497  }
498  }
499  }
500 
501  return labels;
502  }
503 
504 
510  static void getMappingLabelsList(std::vector<LabelOutput> &labelsList, std::map<uint, int> &labels_map)
511  {
512  for(uint i = 0; i < labelsList.size(); i++) {
513  labels_map[labelsList[i].id] = i;
514  }
515  }
516 
524  static void computeNeighbors(uint *labels, int width, int height, std::vector<LabelOutput> &labelsList)
525  {
526  std::map<uint, int> labels_map;
527  getMappingLabelsList(labelsList, labels_map);
528 
529  int width_m_1 = width - 1;
530  int height_m_1 = height - 1;
531 
532  for(int i = 0; i < height; i++) {
533  int shift = i * width;
534 
535  for(int j = 0; j < width; j++) {
536  int ind = shift + j;
537 
538  uint l_ind = labels[ind];
539  int ind2 = labels_map[l_ind];
540 
541  if(i > 0) {
542  if(l_ind != labels[ind - width]) {
543  labelsList[ind2].neighbors.insert(labels[ind - width]);
544  }
545  }
546 
547  if(j > 0) {
548  if(l_ind != labels[ind - 1]) {
549  labelsList[ind2].neighbors.insert(labels[ind - 1]);
550  }
551  }
552 
553  if(i < height_m_1) {
554  if(l_ind != labels[ind + width]) {
555  labelsList[ind2].neighbors.insert(labels[ind + width]);
556  }
557  }
558 
559  if(j < width_m_1) {
560  if(l_ind != labels[ind + 1]) {
561  labelsList[ind2].neighbors.insert(labels[ind + 1]);
562  }
563  }
564 
565  }
566  }
567  }
568 
577  static void mergeIsolatedAreasWithThreshold(uint *labels, int width, int height, std::vector<LabelOutput> &labelsList, int threshold = 1)
578  {
579  if(threshold < 1 || labels == NULL || labelsList.empty()) {
580  return;
581  }
582 
583  if(labelsList[0].neighbors.empty()) {
584  computeNeighbors(labels, width, height, labelsList);
585  }
586 
587  std::map<uint, int> labels_map;
588  getMappingLabelsList(labelsList, labels_map);
589 
590  for(uint i = 0; i < labelsList.size(); i++) {
591  if(!labelsList[i].bValid || labelsList[i].neighbors.empty()) {
592  continue;
593  }
594 
595  if(labelsList[i].neighbors.size() == 1) {
596  uint id = *labelsList[i].neighbors.begin();
597  int index = labels_map[id];
598 
599  if(labelsList[index].bValid) {
600 
601  if(labelsList[i].coords.size() > labelsList[index].coords.size()) {
602  labelsList[index].bValid = false;
603 
604  //update coordinates
605  labelsList[i].coords.insert(labelsList[i].coords.begin(),
606  labelsList[index].coords.begin(),
607  labelsList[index].coords.end());
608 
609  //update neighbors
610  if(labelsList[index].neighbors.size() > 1) {
611  labelsList[i].neighbors.insert(labelsList[index].neighbors.begin(), labelsList[index].neighbors.end());
612 
613  //update all neighbors removing index and adding i!
614  for (auto it = labelsList[index].neighbors.begin(); it != labelsList[index].neighbors.end(); it++) {
615  uint id2 = *it;
616  int index2 = labels_map[id2];
617 
618  labelsList[index2].neighbors.erase(index);
619  labelsList[index2].neighbors.insert(i);
620  }
621  }
622  } else {
623  labelsList[i].bValid = false;
624 
625  //update coordinates
626  labelsList[index].coords.insert(labelsList[index].coords.begin(),
627  labelsList[i].coords.begin(),
628  labelsList[i].coords.end());
629 
630  //it does not have anymore this neighbor because it has been merged
631  labelsList[index].neighbors.erase(i);
632  }
633  }
634  }
635  }
636 
637  computeImageLabelsFromLabelsList(labelsList, labels, width * height);
638  }
639 
640 };
641 
642 
643 } // end namespace pic
644 
645 #endif /* PIC_ALGORITHMS_CONNECTED_COMPONENTS_HPP */
646 
unsigned int uint
Definition: base.hpp:23
static void getMappingLabelsList(std::vector< LabelOutput > &labelsList, std::map< uint, int > &labels_map)
getMappingLabelsList
Definition: connected_components.hpp:510
static Image * convertFromIntegerToImage(uint *imgLabel, Image *imgOut, int width, int height)
convertFromIntegerToImage
Definition: connected_components.hpp:420
float * data
data is the main buffer where pixel values are stored.
Definition: image.hpp:91
int channels
Definition: image.hpp:80
std::set< int > neighbors
Definition: connected_components.hpp:50
uint id
Definition: connected_components.hpp:48
float thr
Definition: connected_components.hpp:81
static void assign(T *dataDst, IntCoord &coord, T dataSrc)
assign
Definition: indexed_array.hpp:340
static void mergeIsolatedAreasWithThreshold(uint *labels, int width, int height, std::vector< LabelOutput > &labelsList, int threshold=1)
mergeIsolatedAreasWithThreshold
Definition: connected_components.hpp:577
bool bValid
Definition: connected_components.hpp:51
uint minLabel
Definition: connected_components.hpp:37
uint id
Definition: connected_components.hpp:36
LabelOutput()
Definition: connected_components.hpp:53
static T distanceSq(T *data0, T *data1, int n)
distanceSq
Definition: array.hpp:195
static uint * computeImageLabelsFromLabelsList(std::vector< LabelOutput > &labelsList, uint *labels, int n)
computeImageLabelsFromLabelsList
Definition: connected_components.hpp:482
static uint * reCount(uint *imgLabel, std::vector< LabelOutput > &labelsList)
reCount
Definition: connected_components.hpp:394
uint * execute(T *imgIn, int width, int height, uint *imgOut, std::vector< LabelOutput > &ret)
execute
Definition: connected_components.hpp:333
Definition: connected_components.hpp:45
void track(uint *imgOut, int &label, std::set< LabelInfo > &labelEq, int neighbors[2], int nNeighbors, int ind)
Definition: connected_components.hpp:155
static void computeLabelsListFromImageLabels(uint *labels, int n, std::vector< LabelOutput > &labelsList)
computeLabelsList
Definition: connected_components.hpp:444
void secondPass(uint *imgOut, std::vector< LabelOutput > &ret, std::set< LabelInfo > &labelEq, int n)
secondPass
Definition: connected_components.hpp:88
void push_back(int i)
Definition: connected_components.hpp:66
#define MIN(a, b)
Definition: math.hpp:69
The Image class stores an image as buffer of float.
Definition: image.hpp:60
Definition: connected_components.hpp:34
ConnectedComponents(float thr=0.05f)
ConnectedComponents.
Definition: connected_components.hpp:242
Definition: bilateral_separation.hpp:25
#define MAX(a, b)
Definition: math.hpp:73
static T norm(float *data, int n)
norm
Definition: array.hpp:245
static void computeNeighbors(uint *labels, int width, int height, std::vector< LabelOutput > &labelsList)
computeNeighbors
Definition: connected_components.hpp:524
uint * execute(Image *imgIn, uint *imgOut, std::vector< LabelOutput > &ret)
execute
Definition: connected_components.hpp:253
int width
Definition: image.hpp:80
int height
Definition: image.hpp:80
std::vector< int > coords
Definition: connected_components.hpp:49
Definition: connected_components.hpp:78
static T * assign(T *buffer, int n, T value)
assign assigns value to buffer
Definition: buffer.hpp:45
LabelOutput(uint id, int i)
Definition: connected_components.hpp:59
friend bool operator<(LabelOutput const &a, LabelOutput const &b)
Definition: connected_components.hpp:71
friend bool operator<(LabelInfo const &a, LabelInfo const &b)
Definition: connected_components.hpp:39