Visual Servoing Platform  version 3.6.0 under development (2023-09-29)
vpImageMorphology.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 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  * Morphology tools.
32  */
33 
34 #ifndef _vpImageMorphology_h_
35 #define _vpImageMorphology_h_
36 
42 #include <visp3/core/vpImage.h>
43 #include <visp3/core/vpImageException.h>
44 #include <visp3/core/vpMatrix.h>
45 
46 #include <fstream>
47 #include <iostream>
48 #include <math.h>
49 #include <string.h>
50 
62 class VISP_EXPORT vpImageMorphology
63 {
64 public:
68  typedef enum
69  {
70  CONNEXITY_4,
72  CONNEXITY_8
75  } vpConnexityType;
76 
77 private:
89  template <typename T>
90  static void imageOperation(vpImage<T> &I, const T &null_value, const T &(*operation)(const T &, const T &), const vpConnexityType &connexity = CONNEXITY_4);
91 
92 public:
93  template <class Type>
94  static void erosion(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity = CONNEXITY_4);
95 
96  template <class Type>
97  static void dilatation(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity = CONNEXITY_4);
98 
99  template <typename T>
100  static void erosion(vpImage<T> &I, const vpConnexityType &connexity = CONNEXITY_4);
101 
102  template <typename T>
103  static void dilatation(vpImage<T> &I, const vpConnexityType &connexity = CONNEXITY_4);
104 
105 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
121  vp_deprecated static void erosion(vpImage<unsigned char> &I, const vpConnexityType &connexity = CONNEXITY_4)
122  {
123  vpImageMorphology::erosion<unsigned char>(I, connexity);
124  }
125 
138  vp_deprecated static void dilatation(vpImage<unsigned char> &I, const vpConnexityType &connexity = CONNEXITY_4)
139  {
140  vpImageMorphology::dilatation<unsigned char>(I, connexity);
141  }
143 #endif
144 };
145 
163 template <class Type>
164 void vpImageMorphology::erosion(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity)
165 {
166  if (I.getSize() == 0) {
167  std::cerr << "Input image is empty!" << std::endl;
168  return;
169  }
170 
171  vpImage<Type> J(I.getHeight() + 2, I.getWidth() + 2);
172  // Copy I to J and add border
173  for (unsigned int i = 0; i < J.getHeight(); i++) {
174  if (i == 0 || i == J.getHeight() - 1) {
175  for (unsigned int j = 0; j < J.getWidth(); j++) {
176  J[i][j] = value;
177  }
178  }
179  else {
180  J[i][0] = value;
181  memcpy(J[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
182  J[i][J.getWidth() - 1] = value;
183  }
184  }
185 
186  if (connexity == CONNEXITY_4) {
187  for (unsigned int i = 0; i < I.getHeight(); i++) {
188  for (unsigned int j = 0; j < I.getWidth(); j++) {
189  if (J[i + 1][j + 1] == value) {
190  // Consider 4 neighbors
191  if ((J[i][j + 1] == value_out) || // Top
192  (J[i + 2][j + 1] == value_out) || // Bottom
193  (J[i + 1][j] == value_out) || // Left
194  (J[i + 1][j + 2] == value_out)) { // Right
195  I[i][j] = value_out;
196  }
197  }
198  }
199  }
200  }
201  else {
202  for (unsigned int i = 0; i < I.getHeight(); i++) {
203  for (unsigned int j = 0; j < I.getWidth(); j++) {
204  if (J[i + 1][j + 1] == value) {
205  // Consider 8 neighbors
206  if ((J[i][j] == value_out) || (J[i][j + 1] == value_out) || (J[i][j + 2] == value_out) ||
207  (J[i + 1][j] == value_out) || (J[i + 1][j + 2] == value_out) || (J[i + 2][j] == value_out) ||
208  (J[i + 2][j + 1] == value_out) || (J[i + 2][j + 2] == value_out))
209  I[i][j] = value_out;
210  }
211  }
212  }
213  }
214 }
215 
233 template <class Type>
234 void vpImageMorphology::dilatation(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity)
235 {
236  if (I.getSize() == 0) {
237  std::cerr << "Input image is empty!" << std::endl;
238  return;
239  }
240 
241  vpImage<Type> J(I.getHeight() + 2, I.getWidth() + 2);
242  // Copy I to J and add border
243  for (unsigned int i = 0; i < J.getHeight(); i++) {
244  if (i == 0 || i == J.getHeight() - 1) {
245  for (unsigned int j = 0; j < J.getWidth(); j++) {
246  J[i][j] = value_out;
247  }
248  }
249  else {
250  J[i][0] = value_out;
251  memcpy(J[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
252  J[i][J.getWidth() - 1] = value_out;
253  }
254  }
255 
256  if (connexity == CONNEXITY_4) {
257  for (unsigned int i = 0; i < I.getHeight(); i++) {
258  for (unsigned int j = 0; j < I.getWidth(); j++) {
259  if (J[i + 1][j + 1] == value_out) {
260  // Consider 4 neighbors
261  if ((J[i][j + 1] == value) || // Top
262  (J[i + 2][j + 1] == value) || // Bottom
263  (J[i + 1][j] == value) || // Left
264  (J[i + 1][j + 2] == value)) { // Right
265  I[i][j] = value;
266  }
267  }
268  }
269  }
270  }
271  else {
272  for (unsigned int i = 0; i < I.getHeight(); i++) {
273  for (unsigned int j = 0; j < I.getWidth(); j++) {
274  if (J[i + 1][j + 1] == value_out) {
275  // Consider 8 neighbors
276  if ((J[i][j] == value) || (J[i][j + 1] == value) || (J[i][j + 2] == value) || (J[i + 1][j] == value) ||
277  (J[i + 1][j + 2] == value) || (J[i + 2][j] == value) || (J[i + 2][j + 1] == value) ||
278  (J[i + 2][j + 2] == value)) {
279  I[i][j] = value;
280  }
281  }
282  }
283  }
284  }
285 }
286 
287 template<typename T>
288 void vpImageMorphology::imageOperation(vpImage<T> &I, const T &null_value, const T &(*operation)(const T &, const T &), const vpConnexityType &connexity)
289 {
290  const int width_in = I.getWidth();
291  const int height_in = I.getHeight();
292  const int width_dilat = width_in + 2;
293  const int height_dilat = height_in + 2;
294  vpImage<T> J(height_dilat, width_dilat, null_value);
295 
296  // Copy I to J and add border
297  J.insert(I, vpImagePoint(1, 1));
298 
299  if (connexity == vpImageMorphology::CONNEXITY_4) {
300  const int nbOffset = 5;
301  int offset_x[nbOffset] = { 0, -1, 0, 1, 0 };
302  int offset_y[nbOffset] = { -1, 0, 0, 0, 1 };
303 
304  for (int i = 0; i < height_in; i++) {
305  for (int j = 0; j < width_in; j++) {
306  T value = null_value;
307  for (int k = 0; k < nbOffset; k++) {
308  value = operation(value, J[i + 1 + offset_y[k]][j + 1 + offset_x[k]]);
309  }
310 
311  I[i][j] = value;
312  }
313  }
314  }
315  else {
316  const int nbOffset = 9;
317  int offset_x[nbOffset] = { -1, 0, 1,-1, 0, 1,-1, 0, 1 };
318  int offset_y[nbOffset] = { -1,-1,-1, 0, 0, 0, 1, 1, 1 };
319 
320  for (int i = 0; i < height_in; i++) {
321  for (int j = 0; j < width_in; j++) {
322  T value = null_value;
323  for (int k = 0; k < nbOffset; k++) {
324  value = operation(value, J[i + 1 + offset_y[k]][j + 1 + offset_x[k]]);
325  }
326 
327  I[i][j] = value;
328  }
329  }
330  }
331 }
332 
356 template <typename T>
358 {
359  const T &(*operation)(const T & a, const T & b) = std::min;
360  vpImageMorphology::imageOperation(I, std::numeric_limits<T>::max(), operation, connexity);
361 }
362 
386 template <typename T>
388 {
389  const T &(*operation)(const T & a, const T & b) = std::max;
390  vpImageMorphology::imageOperation(I, std::numeric_limits<T>::min(), operation, connexity);
391 }
392 #endif
393 
394 /*
395  * Local variables:
396  * c-basic-offset: 2
397  * End:
398  */
Various mathematical morphology tools, erosion, dilatation...
static void dilatation(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
static vp_deprecated void erosion(vpImage< unsigned char > &I, const vpConnexityType &connexity=CONNEXITY_4)
An erosion is performed with a flat structuring element . The erosion using such a structuring elemen...
static void erosion(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
static vp_deprecated void dilatation(vpImage< unsigned char > &I, const vpConnexityType &connexity=CONNEXITY_4)
A dilatation is performed with a flat structuring element . The erosion using such a structuring elem...
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
Definition of the vpImage class member functions.
Definition: vpImage.h:69
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getSize() const
Definition: vpImage.h:223
unsigned int getHeight() const
Definition: vpImage.h:184