Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
vpMorph.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Additional image morphology functions.
33  *
34  * Authors:
35  * Souriya Trinh
36  *
37  *****************************************************************************/
38 
44 #include <visp3/core/vpImageTools.h>
45 #include <visp3/imgproc/vpImgproc.h>
46 
55 #if USE_OLD_FILL_HOLE
56  ,
57  const vpImageMorphology::vpConnexityType &connexity
58 #endif
59 )
60 {
61  if (I.getSize() == 0) {
62  return;
63  }
64 
65 #if USE_OLD_FILL_HOLE
66  // Code similar to Matlab imfill(BW,'holes')
67  // Replaced by flood fill as imfill use imreconstruct
68  // and our reconstruct implementation is naive and inefficient
69  // Difference between new and old implementation:
70  // - new implementation allows to set the fill value
71  // - only background==0 is required, before it was 0 (background) / 1
72  // (foreground)
73  // - no more connexity option
74  vpImage<unsigned char> mask(I.getHeight() + 2, I.getWidth() + 2, 255);
75  // Copy I to mask + add border padding + complement
76  for (unsigned int i = 0; i < I.getHeight(); i++) {
77  for (unsigned int j = 0; j < I.getWidth(); j++) {
78  mask[i + 1][j + 1] = 255 - I[i][j];
79  }
80  }
81 
82  vpImage<unsigned char> marker(I.getHeight() + 2, I.getWidth() + 2, 0);
83  // Create marker with 255 1-pixel border
84  for (unsigned int i = 0; i < marker.getHeight(); i++) {
85  if (i == 0 || i == marker.getHeight() - 1) {
86  for (unsigned int j = 0; j < marker.getWidth(); j++) {
87  marker[i][j] = 255;
88  }
89  } else {
90  marker[i][0] = 255;
91  marker[i][marker.getWidth() - 1] = 255;
92  }
93  }
94 
95  vpImage<unsigned char> I_reconstruct;
96  reconstruct(marker, mask, I_reconstruct, connexity);
97 
98  for (unsigned int i = 0; i < I.getHeight(); i++) {
99  for (unsigned int j = 0; j < I.getWidth(); j++) {
100  I[i][j] = 255 - I_reconstruct[i + 1][j + 1];
101  }
102  }
103 #else
104  // Create flood fill mask
105  vpImage<unsigned char> flood_fill_mask(I.getHeight() + 2, I.getWidth() + 2, 0);
106  // Copy I to mask + add border padding
107  for (unsigned int i = 0; i < I.getHeight(); i++) {
108  memcpy(flood_fill_mask[i + 1] + 1, I[i], sizeof(unsigned char) * I.getWidth());
109  }
110 
111  // Perform flood fill
112  vp::floodFill(flood_fill_mask, vpImagePoint(0, 0), 0, 255);
113 
114  // Get current mask
116  for (unsigned int i = 0; i < mask.getHeight(); i++) {
117  memcpy(mask[i], flood_fill_mask[i + 1] + 1, sizeof(unsigned char) * mask.getWidth());
118  }
119 
120  // Get image with holes filled
121  vpImage<unsigned char> I_white(I.getHeight(), I.getWidth(), 255), I_holes;
122  vpImageTools::imageSubtract(I_white, mask, I_holes);
123  vpImageTools::imageAdd(I, I_holes, I, true);
124 #endif
125 }
126 
146  vpImage<unsigned char> &h_kp1 /*alias I */, const vpImageMorphology::vpConnexityType &connexity)
147 {
148  if (marker.getHeight() != mask.getHeight() || marker.getWidth() != mask.getWidth()) {
149  std::cerr << "marker.getHeight() != mask.getHeight() || "
150  "marker.getWidth() != mask.getWidth()"
151  << std::endl;
152  return;
153  }
154 
155  if (marker.getSize() == 0) {
156  std::cerr << "Input images are empty!" << std::endl;
157  return;
158  }
159 
160  vpImage<unsigned char> h_k = marker;
161  h_kp1 = h_k;
162 
163  do {
164  // Dilatation
165  vpImageMorphology::dilatation(h_kp1, connexity);
166 
167  // Keep min
168  for (unsigned int i = 0; i < h_kp1.getHeight(); i++) {
169  for (unsigned int j = 0; j < h_kp1.getWidth(); j++) {
170  h_kp1[i][j] = std::min(h_kp1[i][j], mask[i][j]);
171  }
172  }
173 
174  if (h_kp1 == h_k) {
175  break;
176  }
177 
178  h_k = h_kp1;
179  } while (true);
180 }
VISP_EXPORT void reconstruct(const vpImage< unsigned char > &marker, const vpImage< unsigned char > &mask, vpImage< unsigned char > &I, const vpImageMorphology::vpConnexityType &connexity=vpImageMorphology::CONNEXITY_4)
Definition: vpMorph.cpp:145
static void imageAdd(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, bool saturate=false)
static void dilatation(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
VISP_EXPORT void fillHoles(vpImage< unsigned char > &I)
Definition: vpMorph.cpp:54
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:85
unsigned int getHeight() const
Definition: vpImage.h:186
unsigned int getSize() const
Definition: vpImage.h:225
static void imageSubtract(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, bool saturate=false)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
unsigned int getWidth() const
Definition: vpImage.h:244