image.png

  • Step 1: Detect edges.
  • Step 2: Use the edges in the image to find the contour (outline) representing the piece of paper being scanned.
  • Step 3: Apply a perspective transform to obtain the top-down view of the document.

Perspective Transform

image.png

Edge Detection

Image_screenshot_02.12.2020.pngEdged_screenshot_02.12.2020.png

Finding Contours

Outline_screenshot_02.12.2020.png

Perspective Transform & Threshold

Scanned_screenshot_02.12.2020.png

  1. # import the necessary packages
  2. from transform import four_point_transform
  3. from skimage.filters import threshold_local
  4. import numpy as np
  5. import argparse
  6. import cv2
  7. import imutils
  8. # construct the argument parser and parse the arguments
  9. ap = argparse.ArgumentParser()
  10. ap.add_argument("-i", "--image", required = False, default='test.jpg', help = "Path to the image to be scanned")
  11. args = vars(ap.parse_args())
  12. # load the image and compute the ratio of the old height
  13. # to the new height, clone it, and resize it
  14. image = cv2.imread(args["image"])
  15. ratio = image.shape[0] / 1024.0
  16. orig = image.copy()
  17. image = imutils.resize(image, height = 1024)
  18. # convert the image to grayscale, blur it, and find edges
  19. # in the image
  20. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  21. gray = cv2.GaussianBlur(gray, (5, 5), 0)
  22. edged = cv2.Canny(gray, 75, 200)
  23. # show the original image and the edge detected image
  24. print("STEP 1: Edge Detection")
  25. cv2.imshow("Image", image)
  26. cv2.waitKey(0)
  27. cv2.imshow("Edged", edged)
  28. cv2.waitKey(0)
  29. #cv2.destroyAllWindows()
  30. # find the contours in the edged image, keeping only the
  31. # largest ones, and initialize the screen contour
  32. cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
  33. cnts = imutils.grab_contours(cnts)
  34. cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
  35. # loop over the contours
  36. for c in cnts:
  37. # approximate the contour
  38. peri = cv2.arcLength(c, True)
  39. approx = cv2.approxPolyDP(c, 0.02 * peri, True)
  40. # if our approximated contour has four points, then we
  41. # can assume that we have found our screen
  42. if len(approx) == 4:
  43. screenCnt = approx
  44. break
  45. pass
  46. # show the contour (outline) of the piece of paper
  47. print("STEP 2: Find contours of paper")
  48. cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
  49. cv2.imshow("Outline", image)
  50. cv2.waitKey(0)
  51. # apply the four point transform to obtain a top-down
  52. # view of the original image
  53. warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
  54. # convert the warped image to grayscale, then threshold it
  55. # to give it that 'black and white' paper effect
  56. warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
  57. T = threshold_local(warped, 11, offset = 10, method = "gaussian")
  58. warped = (warped > T).astype("uint8") * 255
  59. # show the original and scanned images
  60. print("STEP 3: Apply perspective transform")
  61. cv2.imshow("Original", imutils.resize(orig, height = 1024))
  62. cv2.waitKey(0)
  63. cv2.imshow("Scanned", imutils.resize(warped, width = 360))
  64. cv2.waitKey(0)
  65. cv2.destroyAllWindows()