Visual Servoing Platform  version 3.6.1 under development (2024-05-28)
vpMorph.cpp
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  * Additional image morphology functions.
32  */
33 
39 #include <visp3/core/vpImageTools.h>
40 #include <visp3/imgproc/vpImgproc.h>
41 
42 namespace vp
43 {
44 
46 #if USE_OLD_FILL_HOLE
47  ,
48  const vpImageMorphology::vpConnexityType &connexity
49 #endif
50 )
51 {
52  if (I.getSize() == 0) {
53  return;
54  }
55 
56 #if USE_OLD_FILL_HOLE
57  // Code similar to Matlab imfill(BW,'holes')
58  // Replaced by flood fill as imfill use imreconstruct
59  // and our reconstruct implementation is naive and inefficient
60  // Difference between new and old implementation:
61  // - new implementation allows to set the fill value
62  // - only background==0 is required, before it was 0 (background) / 1
63  // (foreground)
64  // - no more connexity option
65  vpImage<unsigned char> mask(I.getHeight() + 2, I.getWidth() + 2, 255);
66  // Copy I to mask + add border padding + complement
67  for (unsigned int i = 0; i < I.getHeight(); ++i) {
68  for (unsigned int j = 0; j < I.getWidth(); ++j) {
69  mask[i + 1][j + 1] = 255 - I[i][j];
70  }
71  }
72 
73  vpImage<unsigned char> marker(I.getHeight() + 2, I.getWidth() + 2, 0);
74  // Create marker with 255 1-pixel border
75  for (unsigned int i = 0; i < marker.getHeight(); ++i) {
76  if (i == 0 || i == marker.getHeight() - 1) {
77  for (unsigned int j = 0; j < marker.getWidth(); ++j) {
78  marker[i][j] = 255;
79  }
80  }
81  else {
82  marker[i][0] = 255;
83  marker[i][marker.getWidth() - 1] = 255;
84  }
85  }
86 
87  vpImage<unsigned char> I_reconstruct;
88  reconstruct(marker, mask, I_reconstruct, connexity);
89 
90  for (unsigned int i = 0; i < I.getHeight(); ++i) {
91  for (unsigned int j = 0; j < I.getWidth(); ++j) {
92  I[i][j] = 255 - I_reconstruct[i + 1][j + 1];
93  }
94  }
95 #else
96  // Create flood fill mask
97  vpImage<unsigned char> flood_fill_mask(I.getHeight() + 2, I.getWidth() + 2, 0);
98  // Copy I to mask + add border padding
99  unsigned int i_height = I.getHeight();
100  for (unsigned int i = 0; i < i_height; ++i) {
101  memcpy(flood_fill_mask[i + 1] + 1, I[i], sizeof(unsigned char) * I.getWidth());
102  }
103 
104  // Perform flood fill
105  vp::floodFill(flood_fill_mask, vpImagePoint(0, 0), 0, 255);
106 
107  // Get current mask
109  unsigned int mask_height = mask.getHeight();
110  for (unsigned int i = 0; i < mask_height; ++i) {
111  memcpy(mask[i], flood_fill_mask[i + 1] + 1, sizeof(unsigned char) * mask.getWidth());
112  }
113 
114  // Get image with holes filled
115  vpImage<unsigned char> I_white(I.getHeight(), I.getWidth(), 255), I_holes;
116  vpImageTools::imageSubtract(I_white, mask, I_holes);
117  vpImageTools::imageAdd(I, I_holes, I, true);
118 #endif
119 }
120 
122  vpImage<unsigned char> &h_kp1 /*alias I */, const vpImageMorphology::vpConnexityType &connexity)
123 {
124  if ((marker.getHeight() != mask.getHeight()) || (marker.getWidth() != mask.getWidth())) {
125  std::cerr << "marker.getHeight() != mask.getHeight() || "
126  "marker.getWidth() != mask.getWidth()"
127  << std::endl;
128  return;
129  }
130 
131  if (marker.getSize() == 0) {
132  std::cerr << "Input images are empty!" << std::endl;
133  return;
134  }
135 
136  vpImage<unsigned char> h_k = marker;
137  h_kp1 = h_k;
138 
139  bool h_kp1_eq_h_k = false;
140  do {
141  // Dilatation
142  vpImageMorphology::dilatation<unsigned char>(h_kp1, connexity);
143 
144  // Keep min
145  unsigned int h_kp1_height = h_kp1.getHeight();
146  unsigned int h_kp1_width = h_kp1.getWidth();
147  for (unsigned int i = 0; i < h_kp1_height; ++i) {
148  for (unsigned int j = 0; j < h_kp1_width; ++j) {
149  h_kp1[i][j] = std::min<unsigned char>(h_kp1[i][j], mask[i][j]);
150  }
151  }
152 
153  if (h_kp1 == h_k) {
154  h_kp1_eq_h_k = true;
155  // break
156  }
157  else {
158  h_k = h_kp1;
159  }
160  } while (h_kp1_eq_h_k == false);
161 }
162 };
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
static void imageSubtract(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, bool saturate=false)
static void imageAdd(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, bool saturate=false)
unsigned int getWidth() const
Definition: vpImage.h:245
unsigned int getSize() const
Definition: vpImage.h:224
unsigned int getHeight() const
Definition: vpImage.h:184
VISP_EXPORT void floodFill(vpImage< unsigned char > &I, const vpImagePoint &seedPoint, const unsigned char oldValue, const unsigned char newValue, const vpImageMorphology::vpConnexityType &connexity=vpImageMorphology::CONNEXITY_4)
Definition: vpFloodFill.cpp:71
VISP_EXPORT void fillHoles(vpImage< unsigned char > &I)
Definition: vpMorph.cpp:45
VISP_EXPORT void reconstruct(const vpImage< unsigned char > &marker, const vpImage< unsigned char > &mask, vpImage< unsigned char > &h_kp1, const vpImageMorphology::vpConnexityType &connexity=vpImageMorphology::CONNEXITY_4)
Definition: vpMorph.cpp:121