Visual Servoing Platform version 3.5.0
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 ,
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}
static void dilatation(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
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:246
unsigned int getSize() const
Definition: vpImage.h:227
unsigned int getHeight() const
Definition: vpImage.h:188
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
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