Visual Servoing Platform  version 3.6.1 under development (2024-05-27)
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 public:
78  template <class Type>
79  static void erosion(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity = CONNEXITY_4);
80 
81  template <class Type>
82  static void dilatation(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity = CONNEXITY_4);
83 
84  template <typename T>
85  static void erosion(vpImage<T> &I, const vpConnexityType &connexity = CONNEXITY_4);
86 
87  template <typename T>
88  static void dilatation(vpImage<T> &I, const vpConnexityType &connexity = CONNEXITY_4);
89 
90  template <typename T>
91  static void erosion(vpImage<T> &I, const int &size);
92 
93  template <typename T>
94  static void dilatation(vpImage<T> &I, const int &size);
95 
96 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
112  vp_deprecated static void erosion(vpImage<unsigned char> &I, const vpConnexityType &connexity = CONNEXITY_4)
113  {
114  vpImageMorphology::erosion<unsigned char>(I, connexity);
115  }
116 
129  vp_deprecated static void dilatation(vpImage<unsigned char> &I, const vpConnexityType &connexity = CONNEXITY_4)
130  {
131  vpImageMorphology::dilatation<unsigned char>(I, connexity);
132  }
134 #endif
135 
136 private:
148  template <typename T>
149  static void imageOperation(vpImage<T> &I, const T &null_value, const T &(*operation)(const T &, const T &), const vpConnexityType &connexity = CONNEXITY_4);
150 
160  template <typename T>
161  static void imageOperation(vpImage<T> &I, const T &(*operation)(const T &, const T &), const int &size = 3);
162 
163 };
164 
182 template <class Type>
183 void vpImageMorphology::erosion(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity)
184 {
185  if (I.getSize() == 0) {
186  std::cerr << "Input image is empty!" << std::endl;
187  return;
188  }
189 
190  vpImage<Type> J(I.getHeight() + 2, I.getWidth() + 2);
191  // Copy I to J and add border
192  unsigned int j_height = J.getHeight();
193  unsigned int j_width = J.getWidth();
194  for (unsigned int i = 0; i < j_height; ++i) {
195  if ((i == 0) || (i == (j_height - 1))) {
196  for (unsigned int j = 0; j < j_width; ++j) {
197  J[i][j] = value;
198  }
199  }
200  else {
201  J[i][0] = value;
202  memcpy(J[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
203  J[i][J.getWidth() - 1] = value;
204  }
205  }
206 
207  if (connexity == CONNEXITY_4) {
208  unsigned int i_height = I.getHeight();
209  unsigned int i_width = I.getWidth();
210  for (unsigned int i = 0; i < i_height; ++i) {
211  for (unsigned int j = 0; j < i_width; ++j) {
212  if (J[i + 1][j + 1] == value) {
213  // Consider 4 neighbors
214  if ((J[i][j + 1] == value_out) || // Top
215  (J[i + 2][j + 1] == value_out) || // Bottom
216  (J[i + 1][j] == value_out) || // Left
217  (J[i + 1][j + 2] == value_out)) { // Right
218  I[i][j] = value_out;
219  }
220  }
221  }
222  }
223  }
224  else {
225  unsigned int i_height = I.getHeight();
226  unsigned int i_width = I.getWidth();
227  for (unsigned int i = 0; i < i_height; ++i) {
228  for (unsigned int j = 0; j < i_width; ++j) {
229  if (J[i + 1][j + 1] == value) {
230  // Consider 8 neighbors
231  bool cond4firstneighbors = (J[i][j] == value_out) || (J[i][j + 1] == value_out) ||
232  (J[i][j + 2] == value_out) || (J[i + 1][j] == value_out);
233  bool cond4secondneighbors = (J[i + 1][j + 2] == value_out) || (J[i + 2][j] == value_out) ||
234  (J[i + 2][j + 1] == value_out) || (J[i + 2][j + 2] == value_out);
235  if (cond4firstneighbors || cond4secondneighbors) {
236  I[i][j] = value_out;
237  }
238  }
239  }
240  }
241  }
242 }
243 
261 template <class Type>
262 void vpImageMorphology::dilatation(vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity)
263 {
264  if (I.getSize() == 0) {
265  std::cerr << "Input image is empty!" << std::endl;
266  return;
267  }
268 
269  vpImage<Type> J(I.getHeight() + 2, I.getWidth() + 2);
270  // Copy I to J and add border
271  unsigned int j_height = J.getHeight();
272  unsigned int j_width = J.getWidth();
273  for (unsigned int i = 0; i < j_height; ++i) {
274  if ((i == 0) || (i == (j_height - 1))) {
275  for (unsigned int j = 0; j < j_width; ++j) {
276  J[i][j] = value_out;
277  }
278  }
279  else {
280  J[i][0] = value_out;
281  memcpy(J[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
282  J[i][J.getWidth() - 1] = value_out;
283  }
284  }
285 
286  if (connexity == CONNEXITY_4) {
287  unsigned int i_height = I.getHeight();
288  unsigned int i_width = I.getWidth();
289  for (unsigned int i = 0; i < i_height; ++i) {
290  for (unsigned int j = 0; j < i_width; ++j) {
291  if (J[i + 1][j + 1] == value_out) {
292  // Consider 4 neighbors
293  if ((J[i][j + 1] == value) || // Top
294  (J[i + 2][j + 1] == value) || // Bottom
295  (J[i + 1][j] == value) || // Left
296  (J[i + 1][j + 2] == value)) { // Right
297  I[i][j] = value;
298  }
299  }
300  }
301  }
302  }
303  else {
304  unsigned int i_height = I.getHeight();
305  unsigned int i_width = I.getWidth();
306  for (unsigned int i = 0; i < i_height; ++i) {
307  for (unsigned int j = 0; j < i_width; ++j) {
308  if (J[i + 1][j + 1] == value_out) {
309  // Consider 8 neighbors
310  bool cond4firstneighbors = (J[i][j] == value) || (J[i][j + 1] == value) || (J[i][j + 2] == value) || (J[i + 1][j] == value);
311  bool cond4secondneighbors = (J[i + 1][j + 2] == value) || (J[i + 2][j] == value) || (J[i + 2][j + 1] == value) ||
312  (J[i + 2][j + 2] == value);
313  if (cond4firstneighbors || cond4secondneighbors) {
314  I[i][j] = value;
315  }
316  }
317  }
318  }
319  }
320 }
321 
322 template<typename T>
323 void vpImageMorphology::imageOperation(vpImage<T> &I, const T &null_value, const T &(*operation)(const T &, const T &), const vpConnexityType &connexity)
324 {
325  const int width_in = I.getWidth();
326  const int height_in = I.getHeight();
327  const int width_dilat = width_in + 2;
328  const int height_dilat = height_in + 2;
329  vpImage<T> J(height_dilat, width_dilat, null_value);
330 
331  // Copy I to J and add border
332  J.insert(I, vpImagePoint(1, 1));
333 
334  if (connexity == vpImageMorphology::CONNEXITY_4) {
335  const int nbOffset = 5;
336  int offset_x[nbOffset] = { 0, -1, 0, 1, 0 };
337  int offset_y[nbOffset] = { -1, 0, 0, 0, 1 };
338 
339  for (int i = 0; i < height_in; ++i) {
340  for (int j = 0; j < width_in; ++j) {
341  T value = null_value;
342  for (int k = 0; k < nbOffset; ++k) {
343  value = operation(value, J[i + 1 + offset_y[k]][j + 1 + offset_x[k]]);
344  }
345 
346  I[i][j] = value;
347  }
348  }
349  }
350  else {
351  const int nbOffset = 9;
352  int offset_x[nbOffset] = { -1, 0, 1,-1, 0, 1,-1, 0, 1 };
353  int offset_y[nbOffset] = { -1,-1,-1, 0, 0, 0, 1, 1, 1 };
354 
355  for (int i = 0; i < height_in; ++i) {
356  for (int j = 0; j < width_in; ++j) {
357  T value = null_value;
358  for (int k = 0; k < nbOffset; ++k) {
359  value = operation(value, J[i + 1 + offset_y[k]][j + 1 + offset_x[k]]);
360  }
361 
362  I[i][j] = value;
363  }
364  }
365  }
366 }
367 
391 template <typename T>
393 {
394  const T &(*operation)(const T & a, const T & b) = std::min;
395  vpImageMorphology::imageOperation(I, std::numeric_limits<T>::max(), operation, connexity);
396 }
397 
421 template <typename T>
423 {
424  const T &(*operation)(const T & a, const T & b) = std::max;
425  vpImageMorphology::imageOperation(I, std::numeric_limits<T>::min(), operation, connexity);
426 }
427 
428 template<typename T>
429 void vpImageMorphology::imageOperation(vpImage<T> &I, const T &(*operation)(const T &, const T &), const int &size)
430 {
431  if (size % 2 != 1) {
432  throw(vpException(vpException::badValue, "Dilatation/erosion kernel must be odd."));
433  }
434 
435  const int width_in = I.getWidth();
436  const int height_in = I.getHeight();
437  int halfKernelSize = size / 2;
438  vpImage<T> J = I;
439 
440  for (int r = 0; r < height_in; ++r) {
441  // Computing the rows we can explore without going outside the limits of the image
442  int r_iterator_start = -halfKernelSize, r_iterator_stop = halfKernelSize + 1;
443  if ((r - halfKernelSize) < 0) {
444  r_iterator_start = -r;
445  }
446  else if ((r + halfKernelSize) >= height_in) {
447  r_iterator_stop = height_in - r;
448  }
449  for (int c = 0; c < width_in; ++c) {
450  T value = I[r][c];
451  // Computing the columns we can explore without going outside the limits of the image
452  int c_iterator_start = -halfKernelSize, c_iterator_stop = halfKernelSize + 1;
453  if ((c - halfKernelSize) < 0) {
454  c_iterator_start = -c;
455  }
456  else if ((c + halfKernelSize) >= width_in) {
457  c_iterator_stop = width_in - c;
458  }
459  for (int r_iterator = r_iterator_start; r_iterator < r_iterator_stop; ++r_iterator) {
460  for (int c_iterator = c_iterator_start; c_iterator < c_iterator_stop; ++c_iterator) {
461  value = operation(value, J[r + r_iterator][c + c_iterator]);
462  }
463  }
464  I[r][c] = value;
465  }
466  }
467 }
468 
495 template <typename T>
496 void vpImageMorphology::erosion(vpImage<T> &I, const int &size)
497 {
498  const T &(*operation)(const T & a, const T & b) = std::min;
499  vpImageMorphology::imageOperation(I, operation, size);
500 }
501 
527 template<typename T>
528 void vpImageMorphology::dilatation(vpImage<T> &I, const int &size)
529 {
530  const T &(*operation)(const T & a, const T & b) = std::max;
531  vpImageMorphology::imageOperation(I, operation, size);
532 }
533 #endif
534 
535 /*
536  * Local variables:
537  * c-basic-offset: 2
538  * End:
539  */
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:72
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:245
unsigned int getSize() const
Definition: vpImage.h:224
unsigned int getHeight() const
Definition: vpImage.h:184