4 point persective transform failure
Clash Royale CLAN TAG#URR8PPP
4 point persective transform failure
I've been trying to do a 4 point perspective transform in order to start doing some OCR.
Starting with the following image I can detect the number plate
and crop it out with the green box being the bounding box and the red dots being the corners of the rectangle I want to square up.
This is the output of the transform.
At a first look it seams to have done the transform inside out (taking the parts either side rather than between the points).
I'm using the imutils package to do the transform and working from this and this as a guide. I'm sure it's something relatively simple I'm missing.
#!/usr/bin/python
import numpy as np
import cv2
import imutils
from imutils import contours
from imutils.perspective import four_point_transform
img = cv2.imread("sample7-smaller.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.bilateralFilter(gray,15,75,75)
v = np.median(blurred)
lower = int(max(0, (1.0 - 0.33) * v))
upper = int(min(255, (1.0 + 0.33) * v))
edged = cv2.Canny(blurred, lower, upper, 255)
conts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
conts = conts[0] if imutils.is_cv2() else conts[1]
conts = sorted(conts, key=cv2.contourArea, reverse=True)
for cnt in conts:
approx = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)
if len(approx) == 4:
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
for i in approx:
cv2.circle(img,(i[0][0], i[0][1]),2,(0,0,255), thickness=4)
warped = four_point_transform(img, approx.reshape(4,2))
cv2.imshow("crop",img[y:y+h,x:x+w])
cv2.imshow("warped", warped)
cv2.waitKey(0)
1 Answer
1
I would recommend you to use the OpenCV Perspective Transform method, to get the desired results, as per the given image:
First mark the position of src points:
src_pts = np.array([[8, 136], [415, 52], [420, 152], [14, 244]], dtype=np.float32)
And suppose you want to fit this number plate in a matrix of shape 50x200, so destination points would be:
dst_pts = np.array([[0, 0], [200, 0], [200, 50], [0, 50]], dtype=np.float32)
Find the perspective Transform Matrix as :
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warp = cv2.warpPerspective(img, M, (200, 50))
EDIT: As you didn't wanted to hard code the final width, height of plate, So in order to make the calculations more flexible you can calculate the width and height of the plate from the 4 marker points as:
def get_euler_distance(pt1, pt2):
return ((pt1[0] - pt2[0])**2 + (pt1[1] - pt2[1])**2)**0.5
src_pts = np.array([[8, 136], [415, 52], [420, 152], [14, 244]], dtype=np.float32)
width = get_euler_distance(src_pts[0][0], src_pts[0][1])
height = get_euler_distance(src_pts[0][0], src_pts[0][3])
dst_pts = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32)
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warp = cv2.warpPerspective(img, M, (width, height))
So you want your output dimension to be be calculated on the fly @hardillb ?
– ZdaR
Feb 16 '17 at 10:19
I'd like to keep it at the same scale to start with, then I can rescale it later
– hardillb
Feb 16 '17 at 10:44
ok Edited @hardillb
– ZdaR
Feb 16 '17 at 15:48
unfortunately that's still giving the same output (and the values you're passing into the
get_euler_distance
need to be pairs not single values). I've zipped up all my code and the original image here if you want another look.– hardillb
Feb 17 '17 at 20:06
get_euler_distance
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
That's what the imutils code is supposed to be doing (pyimagesearch.com/2014/08/25/…), it looks to be doing the same thing, just calculating the dimensions of the output on the fly
– hardillb
Feb 16 '17 at 10:09