[Python] Robustly contour freeform paper in OpenCV under unreliable & variable lighting?

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

  1. Stack

    Stack Membro Participativo

    I'm building a vision system in OpenCV that must robustly detect a sheet of paper under varying lighting and real-world conditions like shadows, curves, wrikles...

    The goal is to create an algorithm that:

    • Detects the full sheet of paper even if curved
    • Rejects spike offshoots (e.g., false edges due to shadows or texture - basically where the contour gets all crazy).
    • Bridges gaps where the contour offshoots

    Basically, to get the contour to close the loop around the paper rather than sprawling out all over the wall.

    My contour code


    def Contour():
    img = cv2.imread("imgage.jpg")
    preprocessed = Preprocess(img)

    # Find contours
    contours = cv2.findContours(preprocessed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPR$
    contours = contours[0] if len(contours) == 2 else contours[1]

    # Take the largest contour only
    if contours:
    largest = max(contours, key=cv2.contourArea)
    cv2.drawContours(img, [largest], -1, (0, 255, 0), 2)
    else:
    print("No contours found.")

    # Show result
    cv2.imshow("Result", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()



    I also tried polygon approximation, but that didn't really solve anything (I tried a lot of values for epsilon):

    epsilon = 0.001 * cv2.arcLength(largest, True)
    poly = cv2.approxPolyDP(largest, epsilon, True)


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

    I could post a ton more pictures but the idea is the same - an algorithm that corrects this is needed not just improvements to the preprocessing code (as shown in bonus) because it gets worse and changes nature with different lighting setups (ideally, if a human can contour it, so should it).

    BONUS


    BONUS 1: Sometimes the top of the paper is occluded by binder clips. The contour goes around them currently. How can I "connect the dots" across these missing sections and replace with one straight line in a plausible way?


    BONUS 2: Is there a better way to preprocess that can help minimize the risk of offshoots from shadows or noise? I still need the algorithm above for robustness, but improved preprocessing could help reinforce it.
    ​

    Please find my preprocessing code below:

    def Preprocess(img):
    # Grayscale image
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Local contrast enhancement
    clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(48, 48))
    clahe_img = clahe.apply(gray)

    # Blur to reduce noise
    blurred = cv2.GaussianBlur(clahe_img, (7, 7), 0)

    # Adaptive threshold to isolate white regions
    thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY, 51, 2)
    return thresh


    Note: We cannot change our hardware/setup and are not looking for any recommendations on that front

    Continue reading...

Compartilhe esta Página