0

I'm programming morphological opening and it's returning the result that's the same as the input image. Am I misunderstanding the explanation of it? My code is:

Var x, y;
Func limit, erosion, dilation;

ImageParam input(type_of<uint8_t>(), 2);
Param<int> dimension;

RDom r(-1 * dimension / 2, dimension, -1 * dimension / 2, dimension);
limit = BoundaryConditions::repeat_edge(input);

erosion(x, y) = argmin(r, limit(x + r.x, y + r.y), "erosion")[2];
dilation(x, y) = argmax(r, erosion(x + r.x, y + r.y), "dilation")[2];

erosion.compute_root();
dilation.vectorize(x, 4).parallel(y);

Target target = get_host_target();

target.set_feature(Target::NoRuntime, true);

dilation.compile_to_static_library(path, { input,dimension }, target);
Rok
  • 476
  • 1
  • 5
  • 12
  • Morphological opening can be a no-op. Have you added salt noise to the image as a test, and does it remain after the opening operation? – Malcolm McLean Oct 04 '16 at 12:53
  • I tried using the pictures that are used as examples from the OpenCV documentation so I have an idea what the result is going to be but my function doesn't produce the same result. the image I'm using is the left part of this [image](http://docs.opencv.org/2.4/_images/Morphology_2_Tutorial_Theory_Opening.png) – Rok Oct 04 '16 at 12:58
  • Also, the first thing to check is that you aren't getting an error back from the call to the Halide generated code... – Zalman Stern Oct 04 '16 at 22:29

1 Answers1

2

The following seems to produce similar results to the OpenCV tutorial image for me:

#include "Halide.h"
#include "../../tools/halide_image_io.h"

using namespace Halide;

int main(int argc, char **argv) {
    Var x, y;
    Func limit, erosion, dilation;

    ImageParam input(type_of<uint8_t>(), 2);
    Param<int> dimension;

    RDom r(-1 * dimension / 2, dimension, -1 * dimension / 2, dimension);
    limit = BoundaryConditions::repeat_edge(input);

#if 0
    erosion(x, y) = minimum(limit(x + r.x, y + r.y), "erosion");
    dilation(x, y) = maximum(erosion(x + r.x, y + r.y), "dilation");
#else
    erosion(x, y) = argmin(r, limit(x + r.x, y + r.y), "erosion")[2];
    dilation(x, y) = argmax(r, erosion(x + r.x, y + r.y), "dilation")[2];
#endif

    erosion.compute_root();
    dilation.vectorize(x, 4).parallel(y);

    Image<uint8_t> in = Halide::Tools::load_image("/some/path/morphology.png");
    input.set(in);
    dimension.set(10);

    Image<uint8_t> result = dilation.realize(in.width(), in.height());

    Halide::Tools::save_image(result, "/some/path/morphology_out.png");

    return 0;
}

The #if 0 block is intended to show just using the minimum and maximum operators instead of argmin/argmax. Also the r argument to argmin/argmax is optional.

I would ask if the error is in how you are passing the image to the Halide AOT compiled function or in how you are treating the returned output. You can also use debug_to_file or print in the Halide code to debug intermediate stages of the pipeline.

Zalman Stern
  • 3,161
  • 12
  • 18
  • Your code works as it should but when I tried to use it with AOT compilation (with modified objects for AOT) I couldn't make it work ... I pass the images by loading them and then using their raw_buffer as the argument for calling the AOT function – Rok Oct 05 '16 at 07:16
  • 1
    The bug is almost certainly with the code that is calling the generated filter. You'll need to debug how that is failing. The first thing to do is to make sure there are no assertion failures happening. These would result in an error return from the filter. The next step is to make sure the bounds and strides are such that the Halide generated code is processing the area you expect. Adding print statements or turning on tracing may help. It is remotely possible that there is some difference between JIT and AOT compilation, but that is very very unlikely. – Zalman Stern Oct 05 '16 at 17:51