Search code examples
pythonopencvcomputer-visioncontouredge-detection

OpenCV Contouring hierarchy


How do I return the contours of the the inner square. Here is my code: I need the contours of the inner square so that I can use the corner points to image warp that area.I have used black tape to help detects the edges. enter image description here

def getBase(img, minarea=100, filter=0, draw=False):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    mask = cv2.inRange(gray, 0, 50)
    result = cv2.bitwise_not(gray, gray, mask=mask)
    cv2.imshow("result", result)
    _, contours, hierarchy = cv2.findContours(
        mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
    )

    finalContours = []

    for i in contours:
        area = cv2.contourArea(i)
        if area > minarea:
            peri = cv2.arcLength(i, True)
            approx = cv2.approxPolyDP(i, 0.02 * peri, True)
            bbox = cv2.boundingRect(approx)

            if filter > 0:
                if len(approx) == filter:
                    finalContours.append((len(approx), area, approx, bbox, i))
            else:
                finalContours.append((len(approx), area, approx, bbox, i))
    finalContours = sorted(finalContours, key=lambda x: x[1], reverse=True)
    if draw:
        for con in finalContours:
            cv2.drawContours(img, con[4], -1, (0, 0, 255), 3)

    return img, finalContours

Solution

  • Here is the solution to detect inner rectangle and extract its left corner point, height and width.

    import cv2
    import numpy as np
    
    def is_rect_contour(contour):
        peri = cv2.arcLength(contour, True)
        approx = cv2.approxPolyDP(contour, 0.01 * peri, True)
        if len(approx) == 4:
            return True
        else:
            return False
        
    image = cv2.imread("./rect.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (7, 7), 0)
    thresh = cv2.threshold(blurred, 40, 255, cv2.THRESH_BINARY_INV)[1]
        
    cnts = cv2.findContours(thresh.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0]
    refined_contours = []
    for cnt in cnts:
        if is_rect_contour(cnt):
            refined_contours.append(cnt)
    inner_rect_cnt = min(refined_contours, key=cv2.contourArea)
    (x, y, w, h) = cv2.boundingRect(inner_rect_cnt)
    print("x: {}, y:{}, widhth:{}, height:{}".format(x, y, w, h))
    cv2.drawContours(image, [inner_rect_cnt], -1, (0, 255, 0), 2)
            
    cv2.imshow('Contours', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    Output:

    x: 425, y:126, widhth:1104, height:720
    

    Result image