pythonopencvsiftsurfkeypoint

Remove key points from edges of an object


I am working with images with objects in it. I used canny edge detection and contours to detect and draw the edges of the objects in it. Then I used both SIFT and SURF to detect key points in the object. Here is the sample code I've been working on.

import cv2 as cv
import numpy as np 
import matplotlib.pyplot as plt
img = cv.imread(image)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 100,200)
image, contours, hierarchy = cv.findContours(edges, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
outimg = cv.drawContours(img, contours, -1, (0,255,0), 3)
sift = cv.xfeatures2d_SIFT.create()
kp, des = sift.detectAndCompute(outimg,None)

Is there any way to remove the key points that are on the edge? Answer with example will be really helpful. Thanks.

Original Image output image


Solution

  • You can use pointPolygonTest method to filter detected keypoints. Use detected contours as boundary polygon. You will also be able to define desired margin.

    Simaple example (fot 4 point contour):

    def inside_point(self, point, rect):
    
            # point is a list (x, y)
            # rect is a contour with shape [4, 2]
    
            rect = rect.reshape([4, 1, 2]).astype(np.int64)
    
            dist = cv2.pointPolygonTest(rect,(point[0], point[1]),True)
    
            if dist>=0:
                # print(dist)
                return True
            else:
                return False 
    

    You can also draw contours on mask image and to check if the point is inside contours, just check the pixel value with the point coordinates, and if it not 0 then point is valid.

    Seems everythig woeks fine: I have no xfeatures2d, so used ORB features here.

    import cv2 as cv
    import numpy as np 
    import matplotlib.pyplot as plt
    
    img = cv.imread('image.jpg')
    #img = cv.resize(img,(512,512))
    img = cv.copyMakeBorder(img,20,20,20,20, 0)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    
    _ , gray = cv.threshold(gray,20,255,cv.THRESH_TOZERO)
    
    gray=cv.erode(gray,np.ones( (5,5), np.int8) )
    edges = cv.Canny(gray, 100,200)
    contours, hierarchy = cv.findContours(edges, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    
    orb = cv.ORB_create(nfeatures=10000)
    kp, des = orb.detectAndCompute(gray,None)
    
    outimg = cv.drawContours(img, contours, -1, (0,255,0), 3)
    
    k = []
    for cont in contours:   
        for i in kp: 
            (x, y) =i.pt
            dist = cv.pointPolygonTest(cont, (x,y), True)
            if dist>=0:
                k.append(i)
    
    for i in k:
        pt=(int(i.pt[0]),int(i.pt[1]) )
        cv.circle(outimg,pt,3, (255,255,255),-1)
    
    cv.imwrite('result.jpg',outimg)        
    cv.imshow('outimg',outimg)
    cv.waitKey()
    

    enter image description here