image_processing/morphing.cpp
/*******************************************************
* Copyright (c) 2014, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
* The complete license agreement can be obtained at:
* https://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
#include <arrayfire.h>
#include <stdio.h>
#include <af/util.h>
#include <cstdlib>
using namespace af;
array morphopen(const array& img, const array& mask) {
return dilate(erode(img, mask), mask);
}
array morphclose(const array& img, const array& mask) {
return erode(dilate(img, mask), mask);
}
array morphgrad(const array& img, const array& mask) {
return (dilate(img, mask) - erode(img, mask));
}
array tophat(const array& img, const array& mask) {
return (img - morphopen(img, mask));
}
array bottomhat(const array& img, const array& mask) {
return (morphclose(img, mask) - img);
}
array border(const array& img, const int left, const int right, const int top,
const int bottom, const float value = 0.0) {
if ((int)img.dims(0) < (top + bottom))
printf("input does not have enough rows\n");
if ((int)img.dims(1) < (left + right))
fprintf(stderr, "input does not have enough columns\n");
dim4 imgDims = img.dims();
array ret = constant(value, imgDims);
ret(seq(top, imgDims[0] - bottom), seq(left, imgDims[1] - right), span,
span) = img(seq(top, imgDims[0] - bottom),
seq(left, imgDims[1] - right), span, span);
return ret;
}
array border(const array& img, const int w, const int h,
const float value = 0.0) {
return border(img, w, w, h, h, value);
}
array border(const array& img, const int size, const float value = 0.0) {
return border(img, size, size, size, size, value);
}
array blur(const array& img, const array mask = gaussianKernel(3, 3)) {
array blurred = array(img.dims(), img.type());
for (int i = 0; i < (int)blurred.dims(2); i++)
blurred(span, span, i) = convolve(img(span, span, i), mask);
return blurred;
}
// Demonstrates various image morphing manipulations.
static void morphing_demo() {
af::Window wnd(1280, 720, "Morphological Operations");
// load images
array img_rgb = loadImage(ASSETS_DIR "/examples/images/man.jpg", true) /
255.f; // 3 channel RGB [0-1]
array mask = constant(1, 5, 5);
array er = erode(img_rgb, mask);
array di = dilate(img_rgb, mask);
array op = morphopen(img_rgb, mask);
array cl = morphclose(img_rgb, mask);
array gr = morphgrad(img_rgb, mask);
array th = tophat(img_rgb, mask);
array bh = bottomhat(img_rgb, mask);
array bl = blur(img_rgb, gaussianKernel(5, 5));
array bp = border(img_rgb, 20, 30, 40, 50, 0.5);
array bo = border(img_rgb, 20);
while (!wnd.close()) {
wnd.grid(3, 4);
wnd(0, 0).image(img_rgb, "Input");
wnd(1, 0).image(er, "Erosion");
wnd(2, 0).image(di, "Dilation");
wnd(0, 1).image(op, "Opening");
wnd(1, 1).image(cl, "Closing");
wnd(2, 1).image(gr, "Gradient");
wnd(0, 2).image(th, "TopHat");
wnd(1, 2).image(bh, "BottomHat");
wnd(2, 2).image(bl, "Blur");
wnd(0, 3).image(bp, "Border to Gray");
wnd(1, 3).image(bo, "Border to black");
wnd.show();
}
}
int main(int argc, char** argv) {
int device = argc > 1 ? atoi(argv[1]) : 0;
try {
af::setDevice(device);
printf("** ArrayFire Image Morphing Demo **\n\n");
morphing_demo();
} catch (af::exception& e) {
fprintf(stderr, "%s\n", e.what());
throw;
}
return 0;
}