I want to detect the quadrilateral area (i.e. find 4 points best describing the border of the area) corresponding to the projected presentation slide, in order to correct the skewed perspective:
I'm using the approach which is described in many sources: detect areas by using grayscale -> blur -> bin threshold -> findContours(), then take the largest area and call
approxPolyDP()
:
#!/usr/bin/env python3
import cv2
def maxl(l): return l.index(max(l))
def find_rect(i_inp):
i_gray = cv2.cvtColor(i_inp, cv2.COLOR_BGR2GRAY)
i_blur = cv2.GaussianBlur(i_gray, (11, 11), 0)
i_bin = cv2.threshold(i_blur, 60, 255, cv2.THRESH_BINARY)[1]
i_2, contours, hierarchy = cv2.findContours(i_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt_largest_i = maxl(list(cv2.contourArea(c) for c in contours))
cnt_largest = contours[cnt_largest_i]
cv2.polylines(i_inp, pts=[cnt_largest], isClosed=False, color=(255, 0, 0), thickness=3)
epsilon = 0.02 * cv2.arcLength(cnt_largest, True)
approx = cv2.approxPolyDP(cnt_largest, epsilon, True)
cv2.polylines(i_inp, pts=[approx], isClosed=False, color=(0, 255, 0), thickness=1)
cv2.imshow('img', i_inp)
cv2.waitKey(0)
return approx
img = cv2.imread('test.jpg')
quad = find_rect(img)
Most typical problem is shown below:
(thick blue line shows the largest area before applying approxPolyDP()
, and thin green line is what approxPolyDP()
gives)
As you can see, with default parameters (multiplier of epsilon
= 0.02) upper border is not detected correctly. I tried to play with the multiplier of epsilon
, here is the result with 0.01:
in this case upper border is correct but left and lower borders are not. What would you recommend to do here? give up this approach and try Hough Tranform instead?