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:
Here is what I already tried:
Method 1: (using thresholding)
- Preprocessing the image with image smoothening (guassian blur/bilateral blur)
- 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: Detecting a sheet of paper / Square Detection
I'm able to find the paper sheet for some images, but it fails for images like this:
Method 2: (using sobel gradient operator)
- Preprocessing the image by converting into grayscale, image smoothening (guassian blur/bilateral blur)
- 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: detect paper from background almost same as paper color
Here's how far I got with the image:
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/bilateral blur)
- 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: Detecting a sheet of paper / Square Detection, 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:
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.