Home > Back-end >  Count corners in 2D numpy array or image
Count corners in 2D numpy array or image

Time:07-09

I need to find the number of corners (don't need the location of them, but would be preferred to verify) in the white area of this numpy array.

The white area is all 1's and everything else is 0.

I tried some if/else logic that kept being incomplete for edge cases, and I tried a Harris Corner detector from cv2 but it seems like its designed for denser (large number of pixel) images. In my case a corner can be small like

[0 0 0 0]

[0 1 1 1]

[0 1 1 1]

plot of numpy image with plt

EDIT:

image with corners circled here

image with corners circled

CodePudding user response:

I experimented using Hit and Miss transform enter image description here

There are 8 possible variations of corners that can be found:

The first 4 are white corners:

[0 0 0]     [0 1 1]     [1 1 0]     [0 0 0]
[0 1 1]     [0 1 1]     [1 1 0]     [1 1 0]
[0 1 1]     [0 0 0]     [0 0 0]     [1 1 0]

These 4 are black corners:

[1 1 1]     [1 0 0]     [0 0 1]     [1 1 1]
[1 0 0]     [1 0 0]     [0 0 1]     [0 0 1]
[1 0 0]     [1 1 1]     [1 1 1]     [0 0 1]

OpenCV has cv2.morphologyEx function to perform advanced morphological operations. Here we will use the same.

Code:

# Read image and convert to grayscale
img = cv2.imread('image.png', 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Create kernels to find 4 white corners
kernel1 = np.array((
        [[-1, -1, -1],
        [-1, 1, 1],
        [-1, 1, 1]]))
kernel2 = np.array((
        [[-1, -1, -1],
        [1, 1, -1],
        [1, 1, -1]]))
kernel3 = np.array((
        [[1, 1, -1],
        [1, 1, -1],
        [-1, -1, -1]])) 
kernel4 = np.array((
        [[-1, 1, 1],
        [-1, 1, 1],
        [-1, -1, -1]])) 

# The next four kernels are created by multiplying existing ones with '-1'
# Storing all of them in a list 
kernels = [kernel1, kernel2, kernel3, kernel4, kernel1*-1, kernel2*-1, kernel3*-1, kernel4*-1]

# Create a mask (in black) with same image shape to store corner points
mask = np.zeros(gray.shape,np.uint8)
mask_fin = mask.copy()

# Find corner points by performing morphology with each kernel and accumulate them to 'mask'
for kernel in kernels:
    out_image = cv2.morphologyEx(gray, cv2.MORPH_HITMISS, kernel)
    mask = cv2.bitwise_or(out_image, mask)

# Since image is in grayscale there are corner points always greater than 0
# For this image They are all greater than 10
mask_fin[mask > 10] = 255

Position of all corners in the image:

enter image description here

# Create copy of original image and assign colored value to corners found
img2 = img.copy()
img2[mask_fin == 255] = (50, 255, 50)

You will have to zoom the image to see them clearly.

enter image description here

End Notes:

If you look closely:

  • There are false corners being found at the 4 corners of the image. The kernels that find black corners find them.
  • Corners close to the white, gray and black regions are often missed out. And that's because those regions don't match any of the kernels

(Please note the above is not the final solution but a step/direction towards a good one. Hope you find it helpful)

CodePudding user response:

You have 80 corners on the white components of your image.

  • threshold the image
  • findContours with a gentle approximation mode (enough for rectilinear contours)
  • count corners in contours

input image:

im

(rv, thresholded) = cv.threshold(im, thresh=192, maxval=255, type=cv.THRESH_BINARY)
# imshow(thresholded)

thresholded:

thresholded

contours:

(contours, hierarchy) = cv.findContours(thresholded, mode=cv.RETR_LIST, method=cv.CHAIN_APPROX_SIMPLE)

draw some things:

canvas = cv.cvtColor(im, cv.COLOR_GRAY2BGR)
cv.drawContours(canvas, contours, contourIdx=-1, color=(0,0,255))
for contour in contours:
    for corner in contour[:,0,:]:
        cv.circle(canvas, center=corner, radius=3, color=(0,0,255), lineType=cv.LINE_AA)
# imshow(canvas)

canvas

count some things:

for contour in contours:
    print(" ", len(contour))
print("=", sum(len(contour) for contour in contours), "in", len(contours))
  14
  8
  58
= 80 in 3
  • Related