Skip to content

Instantly share code, notes, and snippets.

@TheSalarKhan
Created March 23, 2016 22:19
Show Gist options
  • Save TheSalarKhan/9af70004caf2a5ee5ec5 to your computer and use it in GitHub Desktop.
Save TheSalarKhan/9af70004caf2a5ee5ec5 to your computer and use it in GitHub Desktop.
Perspective transformation using Open CV and Python
# This script does a perspective transformation with an A4 paper
# Get an A4 sheet, put it on a table in front of your webcam
# just close enough so that all its corners are visible.
# Run this script, you will be given a frame from the webcam.
# Pick the corners of the A4 sheet for the software, by double clicking on its corners
# one by one in the following order: top left, top right, bottom left, bottom right.
# Just as you select the last corner, a live feed without the perspective distortion
# shows up and now you can write something on it, and have a view of it as if
# the camera was right on top of it. Cheers!
# visit:
import numpy as np
import cv2
# top left, top right, bottom left, bottom right
pts = [(0,0),(0,0),(0,0),(0,0)]
pointIndex = 0
cam = cv2.VideoCapture(1)
_,img = cam.read()
_,img = cam.read()
# Aspect ratio for an A4 sheet. 1:1.414
# 500 * 1.414 = 707, that is why I chose this size.
ASPECT_RATIO = (500,707)
pts2 = np.float32([[0,0],[ASPECT_RATIO[1],0],[0,ASPECT_RATIO[0]],[ASPECT_RATIO[1],ASPECT_RATIO[0]]])
# mouse callback function
def draw_circle(event,x,y,flags,param):
global img
global pointIndex
global pts
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img,(x,y),0,(255,0,0),-1)
pts[pointIndex] = (x,y)
pointIndex = pointIndex + 1
def selectFourPoints():
global img
global pointIndex
print "Please select 4 points, by double clicking on each of them in the order: \n\
top left, top right, bottom left, bottom right."
while(pointIndex != 4):
cv2.imshow('image',img)
key = cv2.waitKey(20) & 0xFF
if key == 27:
return False
return True
# Create a black image, a window and bind the function to window
# img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)
while(1):
if(selectFourPoints()):
# The four points of the A4 paper in the image
pts1 = np.float32([\
[pts[0][0],pts[0][1]],\
[pts[1][0],pts[1][1]],\
[pts[2][0],pts[2][1]],\
[pts[3][0],pts[3][1]] ])
M = cv2.getPerspectiveTransform(pts1,pts2)
while(1):
_,frame = cam.read()
dst = cv2.warpPerspective(frame,M,(707,500))
cv2.imshow("output",dst)
key = cv2.waitKey(10) & 0xFF
if key == 27:
break
else:
print "Exit"
break
# cv2.imshow('image',img)
# if cv2.waitKey(20) & 0xFF == 27:
# break
cam.release()
cv2.destroyAllWindows()
@ambuje
Copy link

ambuje commented Dec 7, 2019

How did you calculated the aspect ratio? How did you came across with 500 value?

@TheSalarKhan
Copy link
Author

How did you calculated the aspect ratio? How did you came across with 500 value?

Its a heuristic. Hit and trial. In my use case this worked best for me so I went with it, although it would be awesome if we can plugin an aspect ratio here.

@asadadams
Copy link

@TheSalarKhan is the aspect ratio that of the paper itself or of the image the paper is in

@TheSalarKhan
Copy link
Author

@asadadams for both if by image you mean the output image. If the aspect ratio of the source and the output are different then it ends up getting malformed and stretchy

@asadadams
Copy link

@TheSalarKhan thanks

@baj-san
Copy link

baj-san commented Jul 30, 2020

good day @TheSalarKhan
How will I make a live video of it. I'm planning to get the points while streaming instead of an image. Thankyou

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment