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]
EDIT:
image with corners circled here
CodePudding user response:
I experimented using Hit and Miss transform
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:
# 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.
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:
(rv, thresholded) = cv.threshold(im, thresh=192, maxval=255, type=cv.THRESH_BINARY)
# imshow(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)
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