40#ifndef VP_IMAGE_MORPHOLOGY_H
41#define VP_IMAGE_MORPHOLOGY_H
43#include <visp3/core/vpConfig.h>
44#include <visp3/core/vpImage.h>
45#include <visp3/core/vpImageException.h>
46#include <visp3/core/vpMatrix.h>
55# pragma clang diagnostic push
56# pragma clang diagnostic ignored "-Wexit-time-destructors"
84 static void erosion(
vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity = CONNEXITY_4);
87 static void dilatation(
vpImage<Type> &I, Type value, Type value_out, vpConnexityType connexity = CONNEXITY_4);
90 static void erosion(
vpImage<T> &I,
const vpConnexityType &connexity = CONNEXITY_4);
93 static void dilatation(
vpImage<T> &I,
const vpConnexityType &connexity = CONNEXITY_4);
96 static void erosion(
vpImage<T> &I,
const int &size);
99 static void dilatation(
vpImage<T> &I,
const int &size);
101#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
142 template <
typename T>
143 class vpPixelOperation
146 vpPixelOperation() { }
148#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
149 virtual ~vpPixelOperation() =
default;
152 virtual T operator()(
const T &,
const T &) = 0;
155 template <
typename T>
156 class vpPixelOperationMax :
public vpPixelOperation<T>
159 vpPixelOperationMax() { }
161 virtual T operator()(
const T &a,
const T &b) VP_OVERRIDE
163 return std::max<T>(a, b);
167 template <
typename T>
168 class vpPixelOperationMin :
public vpPixelOperation<T>
171 vpPixelOperationMin() { }
173 T operator()(
const T &a,
const T &b) VP_OVERRIDE
175 return std::min<T>(a, b);
190 template <
typename T>
191 static void imageOperation(vpImage<T> &I,
const T &null_value, vpPixelOperation<T> *operation,
const vpConnexityType &connexity = CONNEXITY_4);
202 template <
typename T>
203 static void imageOperation(vpImage<T> &I, vpPixelOperation<T> *operation,
const int &size = 3);
227 if (I.getSize() == 0) {
228 std::cerr <<
"Input image is empty!" << std::endl;
235 unsigned int j_width = J.
getWidth();
236 for (
unsigned int i = 0; i < j_height; ++i) {
237 if ((i == 0) || (i == (j_height - 1))) {
238 for (
unsigned int j = 0; j < j_width; ++j) {
244 memcpy(J[i] + 1, I[i - 1],
sizeof(
unsigned char) * I.
getWidth());
250 unsigned int i_height = I.getHeight();
251 unsigned int i_width = I.getWidth();
252 for (
unsigned int i = 0; i < i_height; ++i) {
253 for (
unsigned int j = 0; j < i_width; ++j) {
254 if (J[i + 1][j + 1] == value) {
256 if ((J[i][j + 1] == value_out) ||
257 (J[i + 2][j + 1] == value_out) ||
258 (J[i + 1][j] == value_out) ||
259 (J[i + 1][j + 2] == value_out)) {
267 unsigned int i_height = I.getHeight();
268 unsigned int i_width = I.getWidth();
269 for (
unsigned int i = 0; i < i_height; ++i) {
270 for (
unsigned int j = 0; j < i_width; ++j) {
271 if (J[i + 1][j + 1] == value) {
273 bool cond4firstneighbors = (J[i][j] == value_out) || (J[i][j + 1] == value_out) ||
274 (J[i][j + 2] == value_out) || (J[i + 1][j] == value_out);
275 bool cond4secondneighbors = (J[i + 1][j + 2] == value_out) || (J[i + 2][j] == value_out) ||
276 (J[i + 2][j + 1] == value_out) || (J[i + 2][j + 2] == value_out);
277 if (cond4firstneighbors || cond4secondneighbors) {
306 if (I.getSize() == 0) {
307 std::cerr <<
"Input image is empty!" << std::endl;
314 unsigned int j_width = J.
getWidth();
315 for (
unsigned int i = 0; i < j_height; ++i) {
316 if ((i == 0) || (i == (j_height - 1))) {
317 for (
unsigned int j = 0; j < j_width; ++j) {
323 memcpy(J[i] + 1, I[i - 1],
sizeof(
unsigned char) * I.
getWidth());
329 unsigned int i_height = I.getHeight();
330 unsigned int i_width = I.getWidth();
331 for (
unsigned int i = 0; i < i_height; ++i) {
332 for (
unsigned int j = 0; j < i_width; ++j) {
333 if (J[i + 1][j + 1] == value_out) {
335 if ((J[i][j + 1] == value) ||
336 (J[i + 2][j + 1] == value) ||
337 (J[i + 1][j] == value) ||
338 (J[i + 1][j + 2] == value)) {
346 unsigned int i_height = I.getHeight();
347 unsigned int i_width = I.getWidth();
348 for (
unsigned int i = 0; i < i_height; ++i) {
349 for (
unsigned int j = 0; j < i_width; ++j) {
350 if (J[i + 1][j + 1] == value_out) {
352 bool cond4firstneighbors = (J[i][j] == value) || (J[i][j + 1] == value) || (J[i][j + 2] == value) || (J[i + 1][j] == value);
353 bool cond4secondneighbors = (J[i + 1][j + 2] == value) || (J[i + 2][j] == value) || (J[i + 2][j + 1] == value) ||
354 (J[i + 2][j + 2] == value);
355 if (cond4firstneighbors || cond4secondneighbors) {
365void vpImageMorphology::imageOperation(
vpImage<T> &I,
const T &null_value, vpPixelOperation<T> *operation,
const vpConnexityType &connexity)
367 const int width_in =
static_cast<int>(I.getWidth());
368 const int height_in =
static_cast<int>(I.getHeight());
369 const unsigned int width_dilat = I.getWidth() + 2;
370 const unsigned int height_dilat = I.getHeight() + 2;
371 vpImage<T> J(height_dilat, width_dilat, null_value);
377 const int nbOffset = 5;
378 int offset_x[nbOffset] = { 0, -1, 0, 1, 0 };
379 int offset_y[nbOffset] = { -1, 0, 0, 0, 1 };
381 for (
int i = 0;
i < height_in; ++
i) {
382 for (
int j = 0;
j < width_in; ++
j) {
383 T value = null_value;
384 for (
int k = 0; k < nbOffset; ++k) {
385 value = (*operation)(value, J[
i + 1 + offset_y[k]][
j + 1 + offset_x[k]]);
393 const int nbOffset = 9;
394 int offset_x[nbOffset] = { -1, 0, 1,-1, 0, 1,-1, 0, 1 };
395 int offset_y[nbOffset] = { -1,-1,-1, 0, 0, 0, 1, 1, 1 };
397 for (
int i = 0;
i < height_in; ++
i) {
398 for (
int j = 0;
j < width_in; ++
j) {
399 T value = null_value;
400 for (
int k = 0; k < nbOffset; ++k) {
401 value = (*operation)(value, J[
i + 1 + offset_y[k]][
j + 1 + offset_x[k]]);
436 vpPixelOperationMin<T> operation;
437 vpImageMorphology::imageOperation(I, std::numeric_limits<T>::max(), &operation, connexity);
466 vpPixelOperationMax<T> operation;
467 vpImageMorphology::imageOperation(I, std::numeric_limits<T>::min(), &operation, connexity);
471void vpImageMorphology::imageOperation(
vpImage<T> &I, vpPixelOperation<T> *operation,
const int &size)
473 if ((size % 2) != 1) {
479 int halfKernelSize = size / 2;
482 for (
int r = 0;
r < height_in; ++
r) {
484 int r_iterator_start = -halfKernelSize, r_iterator_stop = halfKernelSize + 1;
485 if ((r - halfKernelSize) < 0) {
486 r_iterator_start = -
r;
488 else if ((r + halfKernelSize) >= height_in) {
489 r_iterator_stop = height_in -
r;
491 for (
int c = 0; c < width_in; ++c) {
494 int c_iterator_start = -halfKernelSize, c_iterator_stop = halfKernelSize + 1;
495 if ((c - halfKernelSize) < 0) {
496 c_iterator_start = -c;
498 else if ((c + halfKernelSize) >= width_in) {
499 c_iterator_stop = width_in - c;
501 for (
int r_iterator = r_iterator_start; r_iterator < r_iterator_stop; ++r_iterator) {
502 for (
int c_iterator = c_iterator_start; c_iterator < c_iterator_stop; ++c_iterator) {
503 value = (*operation)(value, J[
r + r_iterator][c + c_iterator]);
540 vpPixelOperationMin<T> operation;
541 vpImageMorphology::imageOperation(I, &operation, size);
572 vpPixelOperationMax<T> operation;
573 vpImageMorphology::imageOperation(I, &operation, size);
577#if defined(__clang__)
578# pragma clang diagnostic pop
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.
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 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...
static void erosion(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 of the vpImage class member functions.
unsigned int getWidth() const
unsigned int getHeight() const