0

I am trying to build a document scanner application from scratch using OpenCV and python. Till now i have done the following:

  1. re-scaled the image
  2. preprocessed the image, that is converted to greyscale, applied the Gaussian blur, applied adaptive threshold and finally used canny edge detection.
  3. I then found the largest contour and drew it
  4. Detected the edges of the contour and drew them

step 4 is where the problem is, I'm getting two of the points in the correct location however two seem to be slightly offset.

I can't seem to understand what I'm doing wrong, additionally could this problem potentially be due to the way i have preprocessed the image?

import cv2
import numpy as np

# Function to resize the image
def Re_scaleImg(img):
    scale_percent = 50
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)

    # resize the image
    resized = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
    return resized


# Function to process the image
def process(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (3,3), 0)
    thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
    edged = cv2.Canny(thresh, 75, 200)
    #cv2.imshow("blur", blur)
    #cv2.imshow("edged", thresh)
    return edged

# Function to find the areas of contours
def find_contourArea(contours):
    areas = []
    for cnt in contours:
        cont_area = cv2.contourArea(cnt)
        areas.append(cont_area)
    return areas


image = cv2.imread("receipt.jpeg")
resized = Re_scaleImg(image)
processed_img = process(resized)

# finding the contours
contours, hierarchy = cv2.findContours(processed_img.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
resized_copy1 = resized.copy()

# sorting the contours
sorted_contours = sorted(contours, key=cv2.contourArea, reverse=True)

largest_contour = sorted_contours[0]
epsilon = 0.01*cv2.arcLength(largest_contour, True)
approximation = cv2.approxPolyDP(largest_contour, epsilon, True)

cv2.drawContours(resized_copy1, [approximation], -1, (0, 255, 0), 3)

# Obtaining the corners of the rectangle
rot_rect = cv2.minAreaRect(largest_contour)
box = cv2.boxPoints(rot_rect)
box = np.int0(box)
for p in box:
    pt = (p[0], p[1])
    cv2.circle(resized_copy1, pt, 10, (255, 0, 0), -1)
    print(pt)

cv2.imshow("contours", resized_copy1)

cv2.waitKey(0)

Both the images are shown below:

the original image:

the original image

output image:

the output image

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • 1
    Checkout this great answer of @fmw42. I think similar methods may help you https://stackoverflow.com/a/67442660/2227070 – Shamshirsaz.Navid Aug 23 '21 at 11:38
  • minAreaRect gives you a **rectangle**, i.e. with **right angles**. you **don't want** that. you want a general quadrilateral. which you already have (maybe), from approxPolyDP – Christoph Rackwitz Aug 24 '21 at 18:26

1 Answers1

0

Instead of finding the full contour are you could try to find the lines on the edge of the document instead.
With the Hough Line Transform you can find the four most prominent lines (with the most votes).
From these lines you can then calculate the intersection points and use the four points closes to the center of the full shape as corner points.

Andi R
  • 164
  • 5