Ask Your Question

Detect page corners in a photo

asked 2017-09-12 08:25:13 -0600

gurankas gravatar image

updated 2017-09-15 06:22:17 -0600

I have tried 2 methodologies as follows:-

  1. conversion of image to Mat
  2. apply gaussian blur
  3. then canny edge detection
  4. find contours

the problem with this method is: 1. too many contours are detected 2. mostly open contours 3. doesn't detect what I want to detect

Then I changed my approach and tried adaptive thresholding after gaussian blur it is much better and I am able to detect the corners in 50% cases

The current problem I am facing is that the page detection requires contrasting and plain background without any reflections. I think it's too idealistic for real world use.

This is where I would like some help. Even a direction towards the solution is highly appreciated especially in java. Thanks in anticipation

Update: median blur did not help much so I traced the cause and found that the page boundary was detected in bits and pieces and not a single contour so it detected the biggest contour as a part of the page boundary Therefore performed some morphological operations to close relatively small gaps and the resultant largest contour is definitely improved but its its not optimum. Any ideas how I can improve the big gaps?

Update 2: <--new Image <-- canny result after matching the results of median and adaptive from your answer

Update 3: <-- Image before canny edge

edit retag flag offensive close merge delete


this is not an easy task because of the high variability of the background. Instead of the gaussian blur you can try a median filter with a big kernel (is much mir stronger than gaussian) of your can try an edge detection method based on image pyramid which enhances strong long edges but ignores short and weak ones an example image would be helpful

VxW gravatar imageVxW ( 2017-09-12 09:19:31 -0600 )edit

Can you shed some light on how can I do "edge detection method based on image pyramid which enhances strong long edges but ignores short and weak ones?" I've added sample images. 1 with correct corner detection because of the obvious contrasting background and the other with a bit of similar background where largest contour in the image was wrongly detected.

gurankas gravatar imagegurankas ( 2017-09-12 23:57:16 -0600 )edit

@gurankas can you insert images in your post and not only a link?

LBerger gravatar imageLBerger ( 2017-09-15 01:19:39 -0600 )edit

@LBerger I tried a lot but they just won't upload. So I had to upload elsewhere and post their links

gurankas gravatar imagegurankas ( 2017-09-15 05:43:44 -0600 )edit

1 answer

Sort by » oldest newest most voted

answered 2017-09-13 02:58:32 -0600

VxW gravatar image

updated 2017-09-18 06:51:05 -0600

ok, for this task you can try hough line detection

result1 result2

if you have detected the lines you can check some geometrical behavior (e.g. if lines forms a rectangle, which histogram or mean value has the area of the ractangle, and so on..)

try it out:

import cv2
import numpy as np

#img = cv2.imread('C:\Users\wieser\Pictures\IMG_20170912_111444516.jpg')
img = cv2.imread('C:\Users\wieser\Pictures\IMG_20170912_153011325.jpg')

# downscale the image, not the entire information is necessary
img = cv2.resize(img, None, fx=0.3, fy=0.15)

# Convert the img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# remove noise
med = cv2.medianBlur(gray, 21)

# get adaptive threshold
thr = cv2.adaptiveThreshold(med, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 21, 2)

# thinner lines
kernel = np.ones((5,5),np.uint8)
thr = cv2.dilate(thr, kernel, iterations=1)

# Apply edge detection method on the image
edges = cv2.Canny(thr, 1, 255, apertureSize=3)

# This returns an array of r and theta values
lines = cv2.HoughLines(edges, 1, np.pi / 180, 80)

# The below for loop runs till r and theta values
# are in the range of the 2d array
for line in lines:
    for r, theta in line:
        # Stores the value of cos(theta) in a
        a = np.cos(theta)

        # Stores the value of sin(theta) in b
        b = np.sin(theta)

        # x0 stores the value rcos(theta)
        x0 = a * r

        # y0 stores the value rsin(theta)
        y0 = b * r

        # x1 stores the rounded off value of (rcos(theta)-1000sin(theta))
        x1 = int(x0 + 1000 * (-b))

        # y1 stores the rounded off value of (rsin(theta)+1000cos(theta))
        y1 = int(y0 + 1000 * (a))

        # x2 stores the rounded off value of (rcos(theta)+1000sin(theta))
        x2 = int(x0 - 1000 * (-b))

        # y2 stores the rounded off value of (rsin(theta)-1000cos(theta))
        y2 = int(y0 - 1000 * (a))

        # cv2.line draws a line in img from the point(x1,y1) to (x2,y2).
        # (0,0,255) denotes the colour of the line to be
        # drawn. In this case, it is red.
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)


p.s.: parts of the code are from here (

here are the preresults:











Update 2: result canny

result hough

edit flag offensive delete link more


Well I tried HoughLines but I am not getting the same result as your result images. I am implementing this in java and am getting over 2000 lines if the threshold is 80 which by the way does include the page boundaries. Any help implementing this would be greatly appreciated

gurankas gravatar imagegurankas ( 2017-09-13 08:21:01 -0600 )edit

80 is a threshold value: threshold – Accumulator threshold parameter. Only those lines are returned that get enough votes ( >hreshold ).

... so play around to find an optimal threshold.

VxW gravatar imageVxW ( 2017-09-13 08:44:42 -0600 )edit

I am aware of that. I also know that the lines are arranged in decreasing order according to the number of votes. But even if I set a high threshold value of 200, it returns 14 lines, none of which actually belonging to the page boundary. This is where I am stuck

gurankas gravatar imagegurankas ( 2017-09-13 09:06:59 -0600 )edit

I have no experiences using OpenCV in Java. In the end, if you have a good binarized image with edges of your interest you only have to find suitable parameter for Hough Transformation, which should not be that challange

VxW gravatar imageVxW ( 2017-09-13 10:09:02 -0600 )edit

How do I ensure that I indeed have the correct binarized image with correct edges? Can you post your image before and after canny edge detection?

gurankas gravatar imagegurankas ( 2017-09-13 11:40:01 -0600 )edit

Beautiful. Those images helped a ton!! I have found my error. When I use canny using the same setting as yours, my contour is not continuous as yours. I wonder why? Any idea? Can I ask another favour? Can you perform show these intermediate photos for another sample picture? I updated the url for it in the question. Thanks a lot in advance

gurankas gravatar imagegurankas ( 2017-09-14 03:54:35 -0600 )edit

seems to be a homework because of similar question:

if the background is at least not slightly different from the foreground it is a hard job and would take much more effort to solve. Therefore give attention that the background is slightly different and if you acquire the image that you have enough light to strengthen the image quality (increase contrast and decrease noise)

VxW gravatar imageVxW ( 2017-09-14 07:57:29 -0600 )edit

agreed! it's almost impossible to work with the 3rd Image. I don't get your homework reference. Anyways, I'm just one step away from solving this. I just can't figure out why isn't canny detecting the edges after the adaptive threshold has clear boundaries. Do you have any suggestions?

gurankas gravatar imagegurankas ( 2017-09-15 00:10:06 -0600 )edit

how does the previous picture look like. can you upload it?

VxW gravatar imageVxW ( 2017-09-15 01:06:17 -0600 )edit

Updated a link to it

gurankas gravatar imagegurankas ( 2017-09-15 06:22:37 -0600 )edit

Question Tools



Asked: 2017-09-12 08:25:13 -0600

Seen: 3,213 times

Last updated: Sep 18 '17