I have a computer vision algorithm on my Pi 3B+ that uses the following function, myVision(), that takes in a frame and outputs the pixel coordinates of a certain colored dot (tuned according to the HSV range at the top of the function). The function is contained within a processor class that contains the attribute frame, and so myVision() accesses the current frame in the object.

The problem is, myVision() is incredibly slow despite doing all we can to optimize it - profiling the code and timing each line, performing a medianBlur instead of GaussianBlur, etc, but the function usually takes 2-4 seconds to complete, with medianBlur() usually taking the longest (~2 sec). The other openCV functions each take around 20-70ms. The code takes ~10ms to run on a somewhat old laptop with 4GB of RAM. We also upped the GPU capacity of the Pi to 256 (the max), and that didn't seem to do much. We have the camera IO relegated to its own separate thread, and tried to create a thread dedicated to processing frames, but that ran into syncronization issues and didn't seem to speed things up.

Any ideas for how we can speed up the algorithm?

def myVision(self):
        h_min = 150
        h_max = 179
        s_min = 100
        s_max = 255
        v_min = 32
        v_max = 255
        lower = np.array([h_min,s_min,v_min])
        upper = np.array([h_max,s_max,v_max])
        blurred = cv2.medianBlur(self.frame,5)  # blurs the image to remove noise 
        hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV) # Converts BGR to HSV
        mask = cv2.inRange(hsv, lower, upper) # defines the masks color Range
        mask = cv2.erode(mask, None, iterations=2) # erode/dilate filters out colors not in range
        mask = cv2.dilate(mask, None, iterations=2)
        cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # find countours
        cnts = imutils.grab_contours(cnts) # grab contours
        center = None
        # If a countour is found...
        x0=999 # set to junk in case no contours found
        if len(cnts) > 0:
            c = max(cnts, key=cv2.contourArea) # finds contour with largest area
            ((x0, y0), r0) = cv2.minEnclosingCircle(c) # draw a circle around it
        print(f'process time: {time.time()-t0}')
        return x0,y0,r0
  • 1
    consider keeping arrays' memory around as globals so you don't have to keep allocating on each call
    – Abel
    Apr 17, 2021 at 15:15
  • Would that just mean defining them as globals and initializing them to the same type and size as the image arrays? Apr 17, 2021 at 23:19
  • that would be one way to do it. some folks prefer to rotate among a few of them (fed in as an argument) for things like multithreading.
    – Abel
    Apr 18, 2021 at 1:06


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.