Visual Servoing Platform  version 3.2.1 under development (2020-01-21)
vpImageMorphology.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  * Image morphology.
33  *
34  * Authors:
35  * Souriya Trinh
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpCPUFeatures.h>
40 #include <visp3/core/vpImageMorphology.h>
41 
42 #if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2)
43 #include <emmintrin.h>
44 #define VISP_HAVE_SSE2 1
45 #endif
46 
71 {
72  if (I.getSize() == 0) {
73  std::cerr << "Input image is empty!" << std::endl;
74  return;
75  }
76 
77  const unsigned char null_value = 255;
78 
79  vpImage<unsigned char> J(I.getHeight() + 2, I.getWidth() + 2);
80  // Copy I to J and add border
81  for (unsigned int i = 0; i < J.getHeight(); i++) {
82  if (i == 0 || i == J.getHeight() - 1) {
83  for (unsigned int j = 0; j < J.getWidth(); j++) {
84  J[i][j] = null_value;
85  }
86  } else {
87  J[i][0] = null_value;
88  memcpy(J[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
89  J[i][J.getWidth() - 1] = null_value;
90  }
91  }
92 
93  if (connexity == CONNEXITY_4) {
94  unsigned int offset[5] = {1, J.getWidth(), J.getWidth() + 1, J.getWidth() + 2, J.getWidth() * 2 + 1};
95 #if VISP_HAVE_SSE2
96  bool checkSSE2 = vpCPUFeatures::checkSSE2();
97 #endif
98 
99  for (unsigned int i = 0; i < I.getHeight(); i++) {
100  unsigned int j = 0;
101  unsigned char *ptr_curr_J = J.bitmap + i * J.getWidth();
102  unsigned char *ptr_curr_I = I.bitmap + i * I.getWidth();
103 
104 #if VISP_HAVE_SSE2
105  if (checkSSE2 && I.getWidth() >= 16) {
106  for (; j <= I.getWidth() - 16; j += 16) {
107  __m128i m = _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[0]));
108  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[1])));
109  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[2])));
110  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[3])));
111  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[4])));
112 
113  _mm_storeu_si128((__m128i *)(ptr_curr_I + j), m);
114  }
115  }
116 #endif
117 
118  for (; j < I.getWidth(); j++) {
119  unsigned char min_value = null_value;
120  for (int k = 0; k < 5; k++) {
121  min_value = (std::min)(min_value, *(ptr_curr_J + j + offset[k]));
122  }
123 
124  *(ptr_curr_I + j) = min_value;
125  }
126  }
127  } else {
128  // CONNEXITY_8
129  unsigned int offset[9] = {0,
130  1,
131  2,
132  J.getWidth(),
133  J.getWidth() + 1,
134  J.getWidth() + 2,
135  J.getWidth() * 2,
136  J.getWidth() * 2 + 1,
137  J.getWidth() * 2 + 2};
138 #if VISP_HAVE_SSE2
139  bool checkSSE2 = vpCPUFeatures::checkSSE2();
140 #endif
141 
142  for (unsigned int i = 0; i < I.getHeight(); i++) {
143  unsigned int j = 0;
144  unsigned char *ptr_curr_J = J.bitmap + i * J.getWidth();
145  unsigned char *ptr_curr_I = I.bitmap + i * I.getWidth();
146 
147 #if VISP_HAVE_SSE2
148  if (checkSSE2 && I.getWidth() >= 16) {
149  for (; j <= I.getWidth() - 16; j += 16) {
150  __m128i m = _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[0]));
151  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[1])));
152  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[2])));
153  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[3])));
154  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[4])));
155  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[5])));
156  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[6])));
157  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[7])));
158  m = _mm_min_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[8])));
159 
160  _mm_storeu_si128((__m128i *)(ptr_curr_I + j), m);
161  }
162  }
163 #endif
164 
165  for (; j < I.getWidth(); j++) {
166  unsigned char min_value = null_value;
167  for (int k = 0; k < 9; k++) {
168  min_value = (std::min)(min_value, *(ptr_curr_J + j + offset[k]));
169  }
170 
171  *(ptr_curr_I + j) = min_value;
172  }
173  }
174  }
175 }
176 
201 {
202  if (I.getSize() == 0) {
203  std::cerr << "Input image is empty!" << std::endl;
204  return;
205  }
206 
207  const unsigned char null_value = 0;
208 
209  vpImage<unsigned char> J(I.getHeight() + 2, I.getWidth() + 2);
210  // Copy I to J and add border
211  for (unsigned int i = 0; i < J.getHeight(); i++) {
212  if (i == 0 || i == J.getHeight() - 1) {
213  for (unsigned int j = 0; j < J.getWidth(); j++) {
214  J[i][j] = null_value;
215  }
216  } else {
217  J[i][0] = null_value;
218  memcpy(J[i] + 1, I[i - 1], sizeof(unsigned char) * I.getWidth());
219  J[i][J.getWidth() - 1] = null_value;
220  }
221  }
222 
223  if (connexity == CONNEXITY_4) {
224  unsigned int offset[5] = {1, J.getWidth(), J.getWidth() + 1, J.getWidth() + 2, J.getWidth() * 2 + 1};
225 #if VISP_HAVE_SSE2
226  bool checkSSE2 = vpCPUFeatures::checkSSE2();
227 #endif
228 
229  for (unsigned int i = 0; i < I.getHeight(); i++) {
230  unsigned int j = 0;
231  unsigned char *ptr_curr_J = J.bitmap + i * J.getWidth();
232  unsigned char *ptr_curr_I = I.bitmap + i * I.getWidth();
233 
234 #if VISP_HAVE_SSE2
235  if (checkSSE2 && I.getWidth() >= 16) {
236  for (; j <= I.getWidth() - 16; j += 16) {
237  __m128i m = _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[0]));
238  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[1])));
239  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[2])));
240  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[3])));
241  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[4])));
242 
243  _mm_storeu_si128((__m128i *)(ptr_curr_I + j), m);
244  }
245  }
246 #endif
247 
248  for (; j < I.getWidth(); j++) {
249  unsigned char max_value = null_value;
250  for (int k = 0; k < 5; k++) {
251  max_value = (std::max)(max_value, *(ptr_curr_J + j + offset[k]));
252  }
253 
254  *(ptr_curr_I + j) = max_value;
255  }
256  }
257  } else {
258  // CONNEXITY_8
259  unsigned int offset[9] = {0,
260  1,
261  2,
262  J.getWidth(),
263  J.getWidth() + 1,
264  J.getWidth() + 2,
265  J.getWidth() * 2,
266  J.getWidth() * 2 + 1,
267  J.getWidth() * 2 + 2};
268 #if VISP_HAVE_SSE2
269  bool checkSSE2 = vpCPUFeatures::checkSSE2();
270 #endif
271 
272  for (unsigned int i = 0; i < I.getHeight(); i++) {
273  unsigned int j = 0;
274  unsigned char *ptr_curr_J = J.bitmap + i * J.getWidth();
275  unsigned char *ptr_curr_I = I.bitmap + i * I.getWidth();
276 
277 #if VISP_HAVE_SSE2
278  if (checkSSE2 && I.getWidth() >= 16) {
279  for (; j <= I.getWidth() - 16; j += 16) {
280  __m128i m = _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[0]));
281  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[1])));
282  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[2])));
283  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[3])));
284  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[4])));
285  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[5])));
286  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[6])));
287  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[7])));
288  m = _mm_max_epu8(m, _mm_loadu_si128((const __m128i *)(ptr_curr_J + j + offset[8])));
289 
290  _mm_storeu_si128((__m128i *)(ptr_curr_I + j), m);
291  }
292  }
293 #endif
294 
295  for (; j < I.getWidth(); j++) {
296  unsigned char max_value = null_value;
297  for (int k = 0; k < 9; k++) {
298  max_value = (std::max)(max_value, *(ptr_curr_J + j + offset[k]));
299  }
300 
301  *(ptr_curr_I + j) = max_value;
302  }
303  }
304  }
305 }
static void dilatation(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
Type * bitmap
points toward the bitmap
Definition: vpImage.h:141
static void erosion(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
VISP_EXPORT bool checkSSE2()
unsigned int getHeight() const
Definition: vpImage.h:186
unsigned int getSize() const
Definition: vpImage.h:225
unsigned int getWidth() const
Definition: vpImage.h:244