Out of an image, I need to extract a sheet of paper, just like camscanner app does, https://www.camscanner.com/
I know that I can do this by detecting the edges of the sheet of paper i want to detect. And later performing perspective transform. I use openCV library in python. This is the image in which I'm trying to find the sheet of paper:
(https://i.imgur.com/0FxnfOe.jpg) Here is what I already tried:
Method 1: (using thresholding)
- Preprocessing the image with image smoothening (guassian blur/bilateralblur)
- splitting image into h,s,v channels
- adaptive thresholding on the saturation channel
- some morphological operations like dilation and erosion
- finding contours, identifying the largest contour and finding the corner points I've implemented this method based on a stackoverflow answer: Link: https://stackoverflow.com/a/47898407/10337002 I'm able to find the paper sheet for some images, but it fails for images like this:
(https://i.imgur.com/S905YGL.jpg)
Method 2: (using sobel gradient operator)
- Preprocessing the image by converting into grayscale, image smoothening (guassian blur/bilateralblur)
- Finding the gradients of the image
- downsampling and upsampling the image
- After this I don't know how to find the appropriate boundary enclosing the image. I've implemented this method based on a stackoverflow answer: Link: https://stackoverflow.com/a/31888883/10337002 Here's how far I got with the image:
(https://i.imgur.com/499bJFN.png)
Method 3: (using canny edge detector)
According to the posts I've read on this community seems that everyone prefers canny edge method to extract the edges, but in my case the results are not satisfactory. Here's what I did:
- Preprocessing the image by converting into grayscale, image smoothening (guassian blur/bilateralblur)
- Finding the edges using canny edge
- some morphological operations like dilation and erosion
- But the edges obtained from canny are really not up to the mark. I've implemented this method based on a stackoverflow answer: Link: https://stackoverflow.com/a/8863060/10337002, also I didn't quite what he does by iterating over multiple channels in this answer. Here's how far I got with the image:
(https://i.imgur.com/alx7qYh.png)
Here's some code on the method1(thresholding):
#READING IMAGE INTO BGR SPACE
image = cv2.imread("./images/sheet3.png")
#BILATERAL FILTERING TO SMOOTHEN THE IMAGE BUT NOT THE EDGES
img = cv2.bilateralFilter(image,20,75,75)
#CONVERTING BGR TO HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
#SPLITTING THE HSV CHANNELS
h,s,v = cv2.split(hsv)
#DOUBLING THE SATURATION CHANNEL
gray_s = cv2.addWeighted(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), 0.0, s, 2.0, 0)
#THRESHOLDING USING ADAPTIVETHRESHOLDING
threshed = cv2.adaptiveThreshold(gray_s, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 109, 10)
#APPLYING MORPHOLOGICAL OPERATIONS OF DILATION AND EROSION
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
morph = cv2.morphologyEx(threshed, cv2.MORPH_OPEN, kernel)
#FINDING ALL THE CONTOURS
cnts = cv2.findContours(morph, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
canvas = img.copy()
#SORTING THE CONTOURS AND TAKING THE LARGEST CONTOUR
cnts = sorted(cnts, key = cv2.contourArea)
cnt = cnts[-1]
#FINDING THE PERIMETER OF THE CONTOUR
arclen = cv2.arcLength(cnt, True)
#FINDING THE END POINTS OF THE CONTOUR BY APPROX POLY DP
approx = cv2.approxPolyDP(cnt, 0.02* arclen, True)
cv2.drawContours(canvas, [cnt], -1, (255,0,0), 1, cv2.LINE_AA)
cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 1, cv2.LINE_AA)
cv2.imwrite("detected.png", canvas)
I'm kind of new to image processing and openCV. Please share some insights on how to take this further and obtain results more accurately. TIA.