Home > Blockchain >  Using a function as a convolution kernel
Using a function as a convolution kernel

Time:12-11

Hello fellow programmers,

I am currently doing this years advent of code. On day 9 I need to find out wether a pixel in an image has the smallest value of the adjacent pixels.

I first solved this very intuitively and crudely, but now after looking at it for a while was wondering if there was a way to define a convolution kernel for opencv's filter2D-function or another appropriate library I could try where I can define the kernel as a function, such that I can not only perform linear transformations, but also others.

In this specific example I was thinking about a kernel, that can tell if the middle pixel has the lowest value. Maybe there even is a way to do this using linear transformations, however i am not able to find it.

Any help is appreciated.

CodePudding user response:

I found a solution myself simply using scipy.ndimage.generic_filter

import numpy as np
from scipy.ndimage import generic_filter

# First define the footprint of the filter you are going to use:
footprint = np.array([[False, True, False],
                     [True, True, True],
                     [False, True, False]])

# Then define the filter you want to use:
def lowpoint_kernel(a):
    return 0 if a[2] < a[0] and a[2] < a[1] and a[2] < a[3] and a[2] < a[4] else 10

# Get your input here
image = ...

# Pad your image
image = np.pad(image, 1, constant_values=10)

lowpoints = generic_filter(image, lowpoint_kernel, footprint=footprint)
lowpoint_indices = lowpoints == 0

This might very well be a very complicated solution, but maybe someone can find this useful. See my full solution here.

CodePudding user response:

if you want to use OpenCV functions to do so, you can first apply an erosion morphology operation (cv::erode) (with your desire windows size and binary mask) to obtain the minimum at each pixel neighborhood and then compare the resulted image with the original one using cv::compare method or the like.
To exclude center pixel in minimum (erosion), you can pass a customized binary kernel to cv::erode, where the center pixel is zero in the generated kernel.
All in all, you should do something like this:

  1. cv::Mat kernel = cv::Mat::ones(3,3,CV_8UC1);
    kernel.at(1, 1)=0;
  2. cv::erode(src, dst_min, kernel);
  3. cv::compare(src, dst_min, dst, cv::CMP_EQ);

Having said that the only limitation of this method is that the minimum operation is computed over non-zero neighbors in the cv::erode function. If this is not your desire effect, you can add a bias to the src, an then subtract it!

Last but not least, if you are working with cpu (and not gpu), I do recommend cv::ParallelLoopBody to implement all of the procedure in parallel with just one call (memory access).

  • Related