Opencv and python get document correct contur and draw on image

Question:

Using opencv with python here is the output of document conture enter image description here

I’m using opencv_python-4.2.0.34 the bottom left corner is not sharp as the other corners. How to make it right? (edit the bottom left corner automatically to look sharp, as off the others as arise)

here are the code to draw the contour:

img = cv2.imread(imagePath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
invGamma = 1.0 / 0.3
table = np.array([((i / 255.0) ** invGamma) * 255
                  for i in np.arange(0, 256)]).astype("uint8")

# apply gamma correction using the lookup table
gray = cv2.LUT(gray, table)

ret, thresh1 = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY)

contours, hierachy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# except:
#     print('exception occurred')

def biggestRectangle(conts):
    biggest = None
    max_area = 0
    indexReturn = -1
    for index in range(len(conts)):
        i = conts[index]
        area = cv2.contourArea(i)
        if area > 100:
            peri = cv2.arcLength(i, True)
            approx = cv2.approxPolyDP(i, 0.1 * peri, True)
            if area > max_area and len(approx) == 4:
                biggest = approx
                max_area = area
                indexReturn = index
    return indexReturn

indexReturn = biggestRectangle(contours)
hull = cv2.convexHull(contours[indexReturn])

print(indexReturn)
print(contours[indexReturn])
print(hull)

# copyImg = img.copy()

cv2.imwrite(os.path.join('path_to_save', imageName),
            cv2.drawContours(img, [hull], 0, (0, 255, 0), 3))

How to make it right. I tried with another approach:

x, y, w, h = cv2.boundingRect(hull)

    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
    newImageName = imageName.split('.')
    newImageName = newImageName[0] + '_rect.' + newImageName[1]
    print(newImageName)
    cv2.imwrite(os.path.join('path_to_save', newImageName), img)

but it’s giving me this (the blue outline):
enter image description here

Which is also wrong. How to correct it?

Asked By: Asif

||

Answers:

Since you know that the contour you are interested in is a piece of paper, maybe you can use a more systematic approach to find the largest rotated rectangle using OpenCV’s cv2.minAreaRect (link). It will return the center, size, and rotation of the rectangle that most tightly encloses your contour. Since your image has a pretty difficult background, I had to apply a few more processing steps using OpenCV’s morphologyEx function before grabbing the contours, but this this code I could see a better output (shown below).

# first, do some processing
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (27, 27))
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13))
thresh1 = cv2.morphologyEx(thresh1, cv2.MORPH_ERODE, kernel1)
thresh1 = cv2.morphologyEx(thresh1, cv2.MORPH_DILATE, kernel2)

# find all contours
contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_LIST, 
                                       cv2.CHAIN_APPROX_SIMPLE)
# Find the largest ('max' using the key of the contour area)
biggest_contour = max(contours, key=cv2.contourArea)

# Calculate the minimum enclosing rectangle: format ((x, y), (length, width), angle)
rectangle = cv2.minAreaRect(biggest_contour)

# conver the minAreaRect output to points
pts = cv2.boxPoints(rectangle)
# contours must be of shape (n, 1, 2) and dtype integer
pts = pts.reshape(-1, 1, 2)
pts = pts.astype(int)

# draw contours and display
cv2.drawContours(img, [pts], -1, (255, 0, 0), 2)
cv2.imshow('img', img)
k = cv2.waitKey(0)    

output:
enter image description here

Answered By: tiberius
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.