Damien
Damien

Reputation: 1552

OpenCV find contour of this image to crop and rotate

I'm trying to detect the contour of this image in order to crop it in openCV.

I've come up with working code, however, if there is some slight background on the image, it will fail.

Image processing:

enter image description here

Detect boundaries (blue dots):

enter image description here

Crop/rotate:

enter image description here

However, with an image like this, with some background light, it wouldn't work:

enter image description here

preprocess:

enter image description here

Boundaries detection:

enter image description here

def preProcessing(img):
    imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    adaptive_thresold1 = 31
    adaptive_thresold2 = 7

    blur = cv2.blur(imgGray, (3, 3))
    thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,adaptive_thresold1,adaptive_thresold2)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

    stackedImages = hp.stackImages(0.1,([img,thresh, close],[img,thresh, close]))
    cv2.imshow("WorkFlow", stackedImages)
    cv2.waitKey(0) 
    return thresh


def getContours(img):
    biggest = np.array([])
    maxArea = 0
    img = cv2.bitwise_not(img)
    contours,hierarchy = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
    
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area>5000:
            print (area)
            
            #cv2.drawContours(imgContour, cnt, -1, (255, 0, 0), 3)
            peri = cv2.arcLength(cnt,True)
            approx = cv2.approxPolyDP(cnt,0.02*peri,True)
            
            if area >maxArea and len(approx) == 4:
                biggest = approx
                maxArea = area
                print ("ok")
                
    print (biggest)
    out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    cv2.drawContours(out, biggest, -1, (255, 0, 0), 50)

    stackedImages = hp.stackImages(0.1,([img,out],[img,out]))
    cv2.imshow("WorkFlow", stackedImages)
    cv2.waitKey(0)

    return biggest

Any suggestion to make this code more reliable ?

Upvotes: 0

Views: 356

Answers (1)

Rahul Kedia
Rahul Kedia

Reputation: 1420

Instead of using adaptive thresholding, try using Otsu's thresholding.

Change this line

thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,adaptive_thresold1,adaptive_thresold2)

in your code to -

retval_blue, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

This worked for me in the image.

Upvotes: 1

Related Questions