Reputation: 13
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
EDIT 2: what i see with plotting code
Upvotes: 0
Views: 1165
Reputation: 15354
You have 80 corners on the white components of your image.
findContours
with a gentle approximation mode (enough for rectilinear 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
Upvotes: 0
Reputation: 21203
I experimented using Hit and Miss transform details on this site
Following is the key take-away:
If the foreground and background pixels in the structuring element exactly match foreground and background pixels in the image, then the pixel underneath the origin of the structuring element is set to the foreground color. If it doesn't match, then that pixel is set to the background color.
Illustration
The image you have shared is smudged along the edges. So I had to create a different image for illustration:
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:
(Please note the above is not the final solution but a step/direction towards a good one. Hope you find it helpful)
Upvotes: 1