Search code examples
pythonopencvimage-processingcomputer-visionobject-detection

Jitter in OpenCV Circle Detection


I am working on a project and I need to determine the location of circles in a live feed from a camera.

I have already managed to get this kinda running, but I get a weird jitter with the recognition of the circles, and sometimes a circle is not recognized at all.

Here is a Example of this:

enter image description here

The function I Use for editing the Image is:

    def preprocess_image(self):
        self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
        
        # apply GuassianBlur to reduce noise. medianBlur is also added for smoothening, reducing noise.
        self.image = cv2.GaussianBlur(self.image,(5,5),0);
        self.image = cv2.medianBlur(self.image,5)
        
        # Adaptive Guassian Threshold is to detect sharp edges in the Image. For more information Google it.
        self.image = cv2.adaptiveThreshold(self.image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
                cv2.THRESH_BINARY,11,3.5)
        
        kernel = np.ones((2,2),np.uint8)
        self.image = cv2.erode(self.image,kernel,iterations = 1) # gray = erosion
        self.image = cv2.dilate(self.image,kernel,iterations = 1) # gray = dilation    

And the Method for detecting the circles is:


    def get_circles(self):
        rows = self.image.shape[0] # width of the image (1280)
        # detect circles in the image
        self.circles = cv2.HoughCircles(
            self.image, 
            cv2.HOUGH_GRADIENT, 
            1, 
            rows / 8, 
            param1=self.parameters["param1"], 
            param2=self.parameters["param2"], 
            minRadius=self.parameters["minRadius"], 
            maxRadius=self.parameters["maxRadius"]
        )

        if self.circles is None: return None
        self.circles = np.round(self.circles[0, :]).astype("int")

How do I get rid of this jitter and the sometimes missing recognition of the circles?


Solution

  • I solved the issue by ditching hough transforms and instead using connectedComponentsWithStats to transform the circles into black blobs as suggested by Christoph Rackwitz.

    Then I used the SimpleBlobDetector to detect the wanted circles.

    This works way better then before!

    Here is the Code I used:

    import cv2
    import numpy as np
    
    def detect_circles(image):
        _, labels, _, _ = cv2.connectedComponentsWithStats(image)
    
        # Extract the pixels associated with the current label
        label_mask = np.zeros(image.shape, dtype=np.uint8)
        label_mask[labels == 1] = 255
    
        params = cv2.SimpleBlobDetector_Params()
    
        # Set Area filtering parameters
        params.filterByArea = True
        params.minArea = 1000
        params.maxArea = 10000
    
        params.filterByCircularity = True
        params.minCircularity = .7
    
        # Create a detector with the parameters
        detector = cv2.SimpleBlobDetector_create(params)
    
        # Detect blobs
        keypoints = detector.detect(label_mask)
        circles = []
        for kp in keypoints:
            circles.append(np.array([int(kp.pt[0]), int(kp.pt[1]), int(kp.size / 2)]))
        
        return circles
    
    cap = cv2.VideoCapture("<your sample video>")
    
    while True:
        ret, frame = cap.read()
        if np.sum(frame) == 0:[![enter image description here][1]][1]
            break
    
        detect_circles(frame)
    
        # draw the circles on image here 
    
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break   
    
    cv2.destroyAllWindows()
    cap.release()
    

    And this is the result: enter image description here