Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpConnectedComponents.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Connected components.
32 */
33
38
39#include <queue>
40#include <visp3/imgproc/vpImgproc.h>
41
42namespace VISP_NAMESPACE_NAME
43{
44
45void getNeighbors(const vpImage<unsigned char> &I, std::queue<vpImagePoint> &listOfNeighbors, unsigned int i,
46 unsigned int j, const vpImageMorphology::vpConnexityType &connexity);
47void visitNeighbors(vpImage<unsigned char> &I_copy, std::queue<vpImagePoint> &listOfNeighbors, vpImage<int> &labels,
48 int current_label, const vpImageMorphology::vpConnexityType &connexity);
49void connectedComponents(const vpImage<unsigned char> &I, vpImage<int> &labels, int &nbComponents, const vpImageMorphology::vpConnexityType &connexity);
50
51void getNeighbors(const vpImage<unsigned char> &I, std::queue<vpImagePoint> &listOfNeighbors, unsigned int i,
52 unsigned int j, const vpImageMorphology::vpConnexityType &connexity)
53{
54 unsigned char currValue = I[i][j];
55
56 if (connexity == vpImageMorphology::CONNEXITY_4) {
57 // Top
58 if (I[i - 1][j] == currValue) {
59 listOfNeighbors.push(vpImagePoint(i - 1, j));
60 }
61
62 // Left
63 if (I[i][j - 1] == currValue) {
64 listOfNeighbors.push(vpImagePoint(i, j - 1));
65 }
66
67 // Right
68 if (I[i][j + 1] == currValue) {
69 listOfNeighbors.push(vpImagePoint(i, j + 1));
70 }
71
72 // Bottom
73 if (I[i + 1][j] == currValue) {
74 listOfNeighbors.push(vpImagePoint(i + 1, j));
75 }
76 }
77 else {
78 for (int cpt1 = -1; cpt1 <= 1; ++cpt1) {
79 for (int cpt2 = -1; cpt2 <= 1; ++cpt2) {
80 // Everything except the current position
81 if ((cpt1 != 0) || (cpt2 != 0)) {
82 if (I[static_cast<int>(i) + cpt1][static_cast<int>(j) + cpt2] == currValue) {
83 listOfNeighbors.push(vpImagePoint(static_cast<int>(i) + cpt1, static_cast<int>(j) + cpt2));
84 }
85 }
86 }
87 }
88 }
89}
90
91void visitNeighbors(vpImage<unsigned char> &I_copy, std::queue<vpImagePoint> &listOfNeighbors, vpImage<int> &labels,
92 int current_label, const vpImageMorphology::vpConnexityType &connexity)
93{
94 // Visit the neighbors
95 while (!listOfNeighbors.empty()) {
96 vpImagePoint imPt = listOfNeighbors.front();
97 unsigned int i = static_cast<unsigned int>(imPt.get_i());
98 unsigned int j = static_cast<unsigned int>(imPt.get_j());
99 listOfNeighbors.pop();
100
101 if (I_copy[i][j]) {
102 getNeighbors(I_copy, listOfNeighbors, i, j, connexity);
103
104 // Reset current position and set label
105 I_copy[i][j] = 0;
106 labels[i][j] = current_label;
107 }
108 }
109}
110
111void connectedComponents(const vpImage<unsigned char> &I, vpImage<int> &labels, int &nbComponents, const vpImageMorphology::vpConnexityType &connexity)
112{
113 if (I.getSize() == 0) {
114 return;
115 }
116
117 labels.resize(I.getHeight(), I.getWidth());
118
119 vpImage<unsigned char> I_copy(I.getHeight() + 2, I.getWidth() + 2);
120 // Copy and add border
121 unsigned int i_copy_height = I_copy.getHeight();
122 for (unsigned int i = 0; i < i_copy_height; ++i) {
123 if ((i == 0) || (i == (I_copy.getHeight() - 1))) {
124 memset(I_copy[i], 0, sizeof(unsigned char) * I_copy.getWidth());
125 }
126 else {
127 I_copy[i][0] = 0;
128 memcpy(I_copy[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
129 I_copy[i][I_copy.getWidth() - 1] = 0;
130 }
131 }
132
133 vpImage<int> labels_copy(I.getHeight() + 2, I.getWidth() + 2, 0);
134
135 int current_label = 1;
136 std::queue<vpImagePoint> listOfNeighbors;
137
138 unsigned int i_height = I.getHeight();
139 for (unsigned int cpt1 = 0; cpt1 < i_height; ++cpt1) {
140 unsigned int i = cpt1 + 1;
141
142 unsigned int i_width = I.getWidth();
143 for (unsigned int cpt2 = 0; cpt2 < i_width; ++cpt2) {
144 unsigned int j = cpt2 + 1;
145
146 if (I_copy[i][j] && (labels_copy[i][j] == 0)) {
147 // Get all the neighbors relative to the current position
148 getNeighbors(I_copy, listOfNeighbors, i, j, connexity);
149
150 // Reset current position and set label
151 I_copy[i][j] = 0;
152 labels_copy[i][j] = current_label;
153
154 visitNeighbors(I_copy, listOfNeighbors, labels_copy, current_label, connexity);
155
156 // Increment label
157 ++current_label;
158 }
159 }
160 }
161 unsigned int labels_height = labels.getHeight();
162 for (unsigned int i = 0; i < labels_height; ++i) {
163 memcpy(labels[i], labels_copy[i + 1] + 1, sizeof(int) * labels.getWidth());
164 }
165
166 nbComponents = current_label - 1;
167}
168
169} // namespace
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_j() const
double get_i() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getHeight() const
Definition vpImage.h:181
VISP_EXPORT void connectedComponents(const VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, VISP_NAMESPACE_ADDRESSING vpImage< int > &labels, int &nbComponents, const VISP_NAMESPACE_ADDRESSING vpImageMorphology::vpConnexityType &connexity=VISP_NAMESPACE_ADDRESSING vpImageMorphology::CONNEXITY_4)
void getNeighbors(const vpImage< unsigned char > &I, std::queue< vpImagePoint > &listOfNeighbors, unsigned int i, unsigned int j, const vpImageMorphology::vpConnexityType &connexity)
void visitNeighbors(vpImage< unsigned char > &I_copy, std::queue< vpImagePoint > &listOfNeighbors, vpImage< int > &labels, int current_label, const vpImageMorphology::vpConnexityType &connexity)