[Python] How to robustly detect Earth's edge (circle) in old satellite images using image...

Discussão em 'Python' iniciado por Stack, Julho 17, 2025.

  1. Stack

    Stack Membro Participativo

    I have thousands of old satellite images of Earth, each containing a visible circular edge of the Earth (partially or fully), and my goal is to extract the center (x, y) and radius of this circle as accurately as possible.

    I’m currently using OpenCV’s Hough Circle Transform, and while it works to a certain extent, it's not consistently robust across my dataset. My current pipeline:

    # Load image and grayscale
    img = cv2.imread(image_path)
    gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    height, width = gray.shape

    # Mild contrast enhancement
    eq = cv2.equalizeHist(gray)
    enhanced = cv2.addWeighted(gray, 0.7, eq, 0.3, 0)

    # Blur and threshold
    blurred = cv2.GaussianBlur(enhanced, (5, 5), 0)
    _, thresh = cv2.threshold(blurred, 100, 255, cv2.THRESH_BINARY)
    display_image("Thresh", thresh)

    # Mask out borders to remove scanning artifacts
    border = 200
    thresh[:border, :] = 0
    thresh[-border:, :] = 0
    thresh[:, :border] = 0
    thresh[:, -border:] = 0


    # Find largest valid contours
    contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    earth_mask = np.zeros_like(gray)
    for cnt in contours:
    if cv2.contourArea(cnt) > 500:
    cv2.drawContours(earth_mask, [cnt], -1, 255, -1)
    display_image("Earth-mask", earth_mask)

    circles = cv2.HoughCircles(
    earth_mask,
    cv2.HOUGH_GRADIENT,
    dp=1.5,
    minDist=height,
    param1=70,
    param2=30,
    minRadius=int(height / 4),
    maxRadius=int(height / 2)
    )


    This gives reasonable results, but not robust enough across varying image conditions. I have attached images for the above method.

    Attempted improvements:

    1. I use a custom radial scan method from a roughly estimated center of mass to get an approximate radius:

    def radial_gradient(img, center, directions=32, stop_count = 3):
    radii = []
    height, width = img.shape
    cx, cy = center

    for angle in np.linspace(0, 360, directions, endpoint=False):
    x, y = cx, cy
    dx, dy = np.cos(angle), np.sin(angle)
    r = 0
    black_streak = 0

    while 0 <= int(x) < width and 0 <= int(y) < height:
    pixel = img[int(y), int(x)]
    if pixel == 0:
    black_streak += 1
    else:
    black_streak = 0

    if black_streak >= stop_count:
    break

    x += dx
    y += dy
    r += 1

    radii.append(r)

    # remove outliers with iqr:
    q1 = np.percentile(radii, 25)
    q3 = np.percentile(radii, 75)
    iqr = q3 - q1
    lower = q1 - 1.5 * iqr
    upper = q3 + 1.5 * iqr
    filtered_radii = [r for r in radii if lower <= r <= upper]

    return np.median(filtered_radii), filtered_radii


    I combine this with the center-of-mass from the binary mask to refine the radius range for HoughCircles, but this still lacks robustness because sometimes the centre is different from the true centre or the bounds are not tighter or wider.

    min_r = int(rough_radius*0.9)
    max_r = int(rough_radius*1.5)

    What I’m wondering:

    1. Is there a better preprocessing pipeline to enhance the Earth’s edge for more reliable detection?
    2. Is there a more robust method than HoughCircles(I tried ransac as well but it was very random) for this task, especially when the circle is partial or occluded?
    3. Could a method like disk expansion from a center be used to estimate the edge?

    [​IMG][​IMG][​IMG] [​IMG]

    Continue reading...

Compartilhe esta Página