4

For the Code below, I am wondering how to make a circular kernel instead of a rectangular one. I am currently looking at something circular, and I want to find the BGR average values for it. By adjusting my kernel, my data will be more accurate.

for center in c_1:
    b = img2[center[0]-4: center[0]+5, center[1]-4: center[1]+5, 0]
    g = img2[center[0]-4: center[0]+5, center[1]-4: center[1]+5, 1]
    r = img2[center[0]-4: center[0]+5, center[1]-4: center[1]+5, 2]
Guillaume Jacquenot
  • 11,217
  • 6
  • 43
  • 49

4 Answers4

7

From: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html

We manually created a structuring elements in the previous examples with help of Numpy. It is rectangular shape. But in some cases, you may need elliptical/circular shaped kernels. So for this purpose, OpenCV has a function, cv2.getStructuringElement(). You just pass the shape and size of the kernel, you get the desired kernel.

# Elliptical Kernel
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
Kohanz
  • 1,510
  • 16
  • 35
  • 3
    The question is specifically asking for a circular kernel, not elliptical. I came here after reading those linked docs as I couldn't find any mention of how to make a true circular kernel. Its clear to see the resulting numpy array is not symmetric wrt to the x and y dimensions, which one would expect with a circular kernel. – RTbecard Jan 30 '20 at 20:50
  • 1
    You're right, and I'll admit I relied too much on the OpenCV documentation as gospel. I think this answer (https://stackoverflow.com/a/47636524/9315280) does a good job of explaining why this result isn't what one might expect. – Kohanz Jan 31 '20 at 21:08
5

Get the circle region when given the center, you could try the following function:

def circleAverage(center, r = 4):
    """
    """
    for i in range(center[0]-r, center[0]+r):
        for j in range(center[1]-r, center[1] + r):
            if (center[0] - i) ** 2 + (center[1] - j) ** 2 <= r**2:
                // do your computation here.

Hope this helps you.

chenxingwei
  • 251
  • 1
  • 9
1

Came here to find how to make a circular (symmetric) kernel. Ended up with my own implementation.

import numpy as np

def get_circular_kernel(diameter):

    mid = (diameter - 1) / 2
    distances = np.indices((diameter, diameter)) - np.array([mid, mid])[:, None, None]
    kernel = ((np.linalg.norm(distances, axis=0) - mid) <= 0).astype(int)

    return kernel

Note that for low diameters, behavior is perhaps unexpected. Variable mid when used for the second time can for example be replaced by diameter / 2.

F.Wessels
  • 179
  • 11
1

I've implemented it in a following way:

r = 16
kernel = np.fromfunction(lambda x, y: ((x-r)**2 + (y-r)**2 <= r**2)*1, (2*r+1, 2*r+1), dtype=int).astype(np.uint8)

Extra type conversion is needed to avoid overflow

Paul
  • 33
  • 6
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 31 '22 at 07:01