14

I have to find corners of shapes in an image. i have used Harris corner detection algorithm to find corner, but it is giving total corners present in an image and for finding corners for a particular shape in that image it is not feasible. please suggest some other approach.enter image description here

r_ranjan
  • 189
  • 1
  • 2
  • 5
  • you should try [`findcontours`](https://docs.opencv.org/3.3.1/d4/d73/tutorial_py_contours_begin.html) – EdChum Jun 22 '18 at 08:53
  • I have to calculate corner co-ordinates for shapes. But findcontours provides edges. can you share some code or link. – r_ranjan Jun 22 '18 at 10:04
  • @r_ranjan First find the contours and find the edges, later find corners on that image, this is what EdChum was trying to say. – Jeru Luke Jun 22 '18 at 12:09

2 Answers2

24

You could use Harris corner detection algorithm. Corners are junction of two edges, where an edge is a sudden change in image brightness. This algorithm takes the differential of the corner score into account with reference to direction directly (wikipedia). Function cornerSubPix() refines the corner location - it iterates to find the sub-pixel accurate location of corners or radial saddle points (opencv documentation).

Example in code:

import cv2
import numpy as np


img = cv2.imread('edges.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv2.cornerHarris(gray,5,3,0.04)
ret, dst = cv2.threshold(dst,0.1*dst.max(),255,0)
dst = np.uint8(dst)
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv2.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)
for i in range(1, len(corners)):
    print(corners[i])
img[dst>0.1*dst.max()]=[0,0,255]
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows

enter image description here

enter image description here

to check if they are the real values you can add:

for i in range(1, len(corners)):
    print(corners[i,0])
    cv2.circle(img, (int(corners[i,0]), int(corners[i,1])), 7, (0,255,0), 2)

Result:

enter image description here

EDIT:

If you want to extract corners seperatly for every shape you could first search for contours then apply the Harris corner detection for each contour (you can draw it out on a mask with cv2.fillPolly() ). You can even define their shape based on their caracteristics (for example angle of rotation, number of corners,...). I have made an example code to help understand but note that there are other shapes that could fit the criteria I made up and you would have make other criteria (trapezoid, circle,...). This is just a simple example:

import cv2
import numpy as np


img = cv2.imread('edges.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

for i in contours:
    img = cv2.imread('edges.png')
    size = cv2.contourArea(i)
    rect = cv2.minAreaRect(i)
    if size <10000:
        gray = np.float32(gray)
        mask = np.zeros(gray.shape, dtype="uint8")
        cv2.fillPoly(mask, [i], (255,255,255))
        dst = cv2.cornerHarris(mask,5,3,0.04)
        ret, dst = cv2.threshold(dst,0.1*dst.max(),255,0)
        dst = np.uint8(dst)
        ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
        criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
        corners = cv2.cornerSubPix(gray,np.float32(centroids),(5,5),(-1,-1),criteria)
        if rect[2] == 0 and len(corners) == 5:
            x,y,w,h = cv2.boundingRect(i)
            if w == h or w == h +3: #Just for the sake of example
                print('Square corners: ')
                for i in range(1, len(corners)):
                    print(corners[i])
            else:
                print('Rectangle corners: ')
                for i in range(1, len(corners)):
                    print(corners[i])
        if len(corners) == 5 and rect[2] != 0:
            print('Rombus corners: ')
            for i in range(1, len(corners)):
                print(corners[i])
        if len(corners) == 4:
            print('Triangle corners: ')
            for i in range(1, len(corners)):
                print(corners[i])
        if len(corners) == 6:
            print('Pentagon corners: ')
            for i in range(1, len(corners)):
                print(corners[i])
        img[dst>0.1*dst.max()]=[0,0,255]
        cv2.imshow('image', img)
        cv2.waitKey(0)
        cv2.destroyAllWindows

enter image description here

Output (after all shapes are detected):

enter image description here

kavko
  • 2,751
  • 13
  • 27
  • 3
    This answer would be perfect if you could brief on what `cv2.cornerSubPix()` and `cv2.cornerHarris()` do; considering someone coming across this answer to be a layman. Great answer though !! +1 !! – Jeru Luke Jun 22 '18 at 18:17
  • 6
    Thanks for the feedback. I try not to write to much because my english is not so good. Made an effort of briefing on those functions. Cheers – kavko Jun 22 '18 at 18:32
  • 3
    never shy away from trying. If there is some mistake someone will help edit it !! Good effort ! – Jeru Luke Jun 22 '18 at 18:37
  • I have to find corners for every shape **separately**. There are 6 shapes in the image. So I have to find 6 sets of corners that will represent all shapes. In your case it is giving all corners present in images collectively. So how to separate the corners?? – r_ranjan Jun 23 '18 at 21:23
  • You can make a mask for each contour and draw it on the mask, then search for corners (for c in contours, draw, corner detection) – kavko Jun 24 '18 at 07:46
  • @kavko: you are not really answering the question, just perfoming corner detection. –  Jun 29 '18 at 15:53
  • I have made an edit to my answer with an example on how to detect corners for every shape on the image. – kavko Jun 29 '18 at 17:08
0

For every shape, trace the contour, and for every pixel of the contour, check if a nearby corner was found (say in a 3x3 or 5x5 neighborhood).