Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

4 point persective transform failure

Tags:

python

opencv

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

enter image description here

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.

enter image description here

This is the output of the transform.

enter image description here

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)
like image 577
hardillb Avatar asked Mar 10 '23 20:03

hardillb


1 Answers

I would recommend you to use the OpenCV Perspective Transform method, to get the desired results, as per the given image:

enter image description here

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))

enter image description here

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))
like image 192
ZdaR Avatar answered Mar 21 '23 01:03

ZdaR