HoughCircles method: memory problem with large images

Hello,

I am applying the cv.HoughCircles method on a tif image. I am trying on larger and larger regions of the images. It works perfectly if the image size is ~ 3100 x 3500 pixels, but if I move to a region ~28000 x 34500 my computer turns off.

Is that related to a memory problem? If yes, how can I solve it?
Below, please find my code.

Thanks in advance for the help.
Barbara

import sys
import cv2 as cv
import numpy as np
import pdb

def main(argv):
    
    default_file = 'smarties.png'
    filename = argv[0] if len(argv) > 0 else default_file
    
    # Loads an image:
    src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR)

    # Print the dimension of the images:
    dimensions = src.shape
    print('Image dimensions:', dimensions, 'pixel')

    pdb.set_trace()

    # Check if image is loaded fine:
    if src is None:
        print ('Error opening image!')
        print ('Usage: hough_circle.py [image_name -- default ' + default_file + '] \n')
        return -1
    
    # Convert image to grayscale:
    gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    
    # Apply a median blur to reduce noise and avoid false circle detection:
    gray = cv.medianBlur(gray, 7)

    # Display the filtered image:
    #cv.imshow("Smoothed image", gray)
    #cv.waitKey(0)

    # Find the number of rows (pixel):
    rows = gray.shape[0]

    # Apply the Hough Circle detection method:
    #circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows/17,
    #                           param1=100, param2=30,
    #                           minRadius=1, maxRadius=50)

    circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, 100,
                               param1=100, param2=30,
                               minRadius=1, maxRadius=50)
    # Print the number of found circles:
    print('Number of detected circles:', circles.shape[1])

    # Retrieve the coordinates of all found circles:
    if circles is not None:
        circles = np.uint16(np.around(circles))
        for i in circles[0, :]:
            center = (i[0], i[1])
            # circle center
            cv.circle(src, center, 1, (0, 100, 100), 3)
            # circle outline
            radius = i[2]
            cv.circle(src, center, radius, (255, 0, 255), 3)
            #tot_found_circle=tot_found_circles+1

        # Print the number of found circles:
        #print('NUmber of found circles:', tot_found_circles)
    
    # Show circle in original image:
    cv.imshow("detected circles", src)
    cv.waitKey(0)
    
    return 0
if __name__ == "__main__":
    main(sys.argv[1:])``

reconsider your approach.

the Hough transform is always expensive in CPU and memory.

your computer should not simply “turn off” because a process tried to allocate an outrageous amount of memory.

present your problem/goal (and representative sample data), not your approach. then we can figure out how to solve the problem.

Hello,

Thanks for the quick answer.
I have a tif or png image and I want to recognize all the black circles in it, storing the information of center and radius. The image can be found at:

I see something that looks like a sheet of metal, with a grid of holes in it. there are some dark smudges on that, which look like the holes.

to distinguish true holes from dark smudges, it might be possible to vary the background (two aligned pictures), so the holes change appearance, and are clearly defined by that change in appearance, vs. anything that is simply just dark.

I would suggest thresholding, findContours, then filtering the contours by area and a measure of circularity.

that costs a lot less than a Hough transform.

circularity is any measure that relates area and circumference using the observation that for a given area, circles are the shapes with the smallest circumference.

Hello, thanks a lot for the hints.
Since I am a beginners, please could you mention the functions/methods for all the steps you described (thresholding, find contours, filtering contours by area, and measure of circularity)?

About the memory challenges. After color conversion your original image remains allocated, consuming a couple of gigabytes, which should not cause the computer to shut off, but is clearly not ideal, so the variable should be assigned to an empty image.

Hello, thanks for this suggestion.
I tried to delete the original image right after the color conversion (del src, see below), but this does not solve the problem. Am I using the wrong command?

import sys
import cv2 as cv
import numpy as np
import pdb
import os, psutil
import tracemalloc
import matplotlib.pyplot as plt


def main(argv):
    
    default_file = 'image.png'
    filename = argv[0] if len(argv) > 0 else default_file
    
    # Loads an image:
    src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR)

    # Print the dimension of the images:
    dimensions = src.shape
    print('Image dimensions:', dimensions, 'pixel')

    # Check if image is loaded fine:
    if src is None:
        print ('Error opening image!')
        print ('Usage: hough_circle.py [image_name -- default ' + default_file + '] \n')
        return -1
    
    # Convert image to grayscale:
    gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

    # Release memory deleting original image:
    del src
    
    # Apply a median blur to reduce noise and avoid false circle detection:
    gray = cv.medianBlur(gray, 7)

    # Find the number of rows (pixel):
    rows = gray.shape[0]

    # Apply the Hough Circle detection method:
    circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, 100,
                               param1=100, param2=30,
                               minRadius=30, maxRadius=40)

    # Print the number of found circles:
    print('Number of detected circles:', circles.shape[1])

    arr_radii = np.array([])

    #Reload the original image
    src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR)
    
    # Retrieve the coordinates of all found circles:
    if circles is not None:
        circles = np.uint16(np.around(circles))
        for i in circles[0, :]:
            #print(i)
            center = (i[0], i[1])
            # circle center
            cv.circle(src, center, 1, (0, 100, 100), 3)
            # circle outline
            radius = i[2]
            cv.circle(src, center, radius, (255, 0, 255), 3)
            arr_radii = np.append(arr_radii, i[2])
    
    # Show circle in original image:
    cv.imshow("detected circles", src)
    cv.waitKey(0)

    # Plot radius histogram:
    plt.hist(arr_radii, 5, density=True, alpha=0.75)
    plt.xlim(35, 40)
    plt.xlabel('Radius')
    plt.ylabel('Counts')
    plt.title('Histogram of radius distribution')
    plt.show()

    return 0
if __name__ == "__main__":
    main(sys.argv[1:])