#Morphological open/close transformation problems

8 messages · Page 1 of 1 (latest)

gaunt marsh
#

Can anybody see if there is an issue with this code because for some reason my open/close transformations don't work as opencv's

template <bool is_erosion, size_t N>
auto apply_mask(const mask_t<N>& mask, const point<int16_t>& p, coords_translate_fn fn_src) {
    constexpr auto lower_boundary = -(static_cast<ssize_t>(N)/2);
    constexpr auto upper_boundary = (static_cast<ssize_t>(N)/2);

    // N = 3 => N/2 = 1
    // i,j range: -1 0 1
    // i + N/2 range: 0 1 2
    uint16_t result = 0;

    for (int16_t i = lower_boundary; i <= upper_boundary; i++) {
        for (int16_t j = lower_boundary; j <= upper_boundary; j++) {
            const point<int16_t>& current_position{
                static_cast<int16_t>(p.x + i),
                static_cast<int16_t>(p.y + j)};

            if (is_erosion) {
                if (current_position.x < 0 || current_position.x >= height) {
                    result += 1;
                    continue;
                }
                if (current_position.y < 0 || current_position.y >= width) {
                    result += 1;
                    continue;
                }
            } else {
                if (current_position.x < 0 || current_position.x >= height) continue;
                if (current_position.y < 0 || current_position.y >= width) continue;
            }

            const auto& current_pixel = fn_src(current_position.x, current_position.y);
            result += mask[i + upper_boundary][j + upper_boundary] * (current_pixel == 0xff);
        }
    }


    return result;
}

template <size_t N>
void close(const mask_t<N>& mask, coords_translate_fn src, coords_translate_fn dst, uint16_t iterations = 1) {
    for (uint16_t i = 0; i < iterations; ++i) {
        //std::cout << i << std::endl;
        Serial.println(i);
        dilate(mask, src, dst);
        erode(mask, dst, src);
    }
}
broken abyssBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

gaunt marsh
#
template <size_t N>
void dilate(const mask_t<N>& mask, coords_translate_fn fn_src, coords_translate_fn fn_dst) {
    constexpr auto using_dilation = false;

    for (int16_t i = 0; i < height; ++i) {
        for (int16_t j = 0; j < width; ++j) {
            const auto& result = apply_mask<using_dilation, N>(mask, {i, j}, fn_src);
            fn_dst(i, j) = result > 0 ? 0xff : 0x0;
        }
    }
}

template <size_t N>
void erode(const mask_t<N>& mask, coords_translate_fn fn_src, coords_translate_fn fn_dst) {
    constexpr auto using_erosion = true;

    uint16_t mask_sum = 0;
     for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            mask_sum += mask[i][j];
        }
     }

    //std::cout << mask_sum << std::endl;
  
    for (int16_t i = 0; i < height; ++i) {
        for (int16_t j = 0; j < width; ++j) {
            const auto& result = apply_mask<using_erosion, N>(mask, {i, j}, fn_src);
            fn_dst(i, j) = result == mask_sum ? 0xff : 0x0;
        }
    }
}

template <size_t N>
void open(const mask_t<N>& mask, coords_translate_fn src, coords_translate_fn dst, uint16_t iterations = 1) {
    for (uint16_t i = 0; i < iterations; ++i) {
        erode(mask, src, dst);
        dilate(mask, dst, src);
    }
}
gaunt marsh
hushed chasm
# gaunt marsh Like after 3 or 4 iterations it won't do nothing to the image

The main issue causing the difference is how you are handling your input and output buffers in the open and close functions. Currently, your open function erodes from src to dst, but then immediately dilates from dst back into src; this means your final result actually overwrites your input image, while dst is left holding only the intermediate (eroded) step. Your iteration logic is mathematically different from OpenCV's: for an opening with 2 iterations, OpenCV performs "Erode \to Erode \to Dilate \to Dilate," whereas your code performs "(Erode \to Dilate) \to (Erode \to Dilate)." Since morphological opening is idempotent your loop does nothing after the first iteration and just messes up

gaunt marsh
hushed chasm
# gaunt marsh So I should dilate twice and the erode it twice?

That depends on which function you are implementing. If you are fixing Close (which fills holes), then yes, you absolutely dilate N times and then erode N times. However, for Open (which removes noise), you must do the opposite: erode N times first, followed by dilating N times. The architectural shift here is that you must apply the iterations to the individual atomic operations effectively simulating a larger kernel rather than repeating the combined sequence, which becomes redundant after the first pass

gaunt marsh
#

!solved