2

I want to apply a transformation matrix to a set of points. So the set of points:

points = np.array([[0 ,20], [0, 575], [0, 460]])

And I want to use the matrix I calculated with cv2.getPerspectiveTransform() which is a 3x3 matrix.

matrix = np.array([
   [  -4.       ,   -3.       , 1920.     ],
   [  -2.25     ,   -1.6875   , 1080.     ],
   [  -0.0020833,   -0.0015625,    1.     ]])

Then I pass the array and a matrix to the following function:

def poly_points_transform(poly_points, matrix):
  poly_points_transformed = np.empty_like(poly_points)
  for i in range(len(poly_points)):
    point = np.array([[poly_points[i]]])
    transformed_point = cv2.perspectiveTransform(point, matrix)
    np.append(poly_points_transformed, transformed_point)

  return poly_points_transformed

Now It doesn't throw an error, but it just copies the src array to the poly_points_transformed. It might be something really rudimentary and stupid. If it is the case, I am sorry, but could someone give me a hint on what is wrong? Thanks in advance

  • Not sure about python, but in c++ cv2.perspectiveTransform takes a list of points as input, maybe that's the problem? So you could try poly_points_transformed=cv2.perspectiveTransform(poly_points, matrix) – Micka Sep 08 '22 at 18:18

1 Answers1

1

We may solve it with one line of code:

transformed_point = cv2.perspectiveTransform(np.array([points], np.float64), matrix)[0]

As Micka commented cv2.perspectiveTransform takes a list of points (and returns a list of points as output).

  • np.array([points]) is used because cv2.perspectiveTransform expects 3D array.
    For details see trouble getting cv.transform to work.
  • np.float64 is used in case the dtype of points is int32 (the method accepts float64 and float32 types).
  • [0] is used for removing the redundant dimension (convert from 3D to 2D).

For fixing the loop, replace np.append(poly_points_transformed, transformed_point) with:
poly_points_transformed[i] = transformed_point[0].

Since the array is initialized to poly_points_transformed = np.empty_like(poly_points), we can't use np.append().


Code sample:

import cv2
import numpy as np

points = np.array([[0.0 ,20.0], [0.0, 575.0], [0.0, 460.0]])

matrix = np.array([
   [  -4.       ,   -3.       , 1920.     ],
   [  -2.25     ,   -1.6875   , 1080.     ],
   [  -0.0020833,   -0.0015625,    1.     ]])

# transformed_point = cv2.perspectiveTransform(np.array([points], np.float64), matrix)[0]

def poly_points_transform(poly_points, matrix):
    poly_points_transformed = np.empty_like(poly_points)
    for i in range(len(poly_points)):
        point = np.array([[poly_points[i]]])
        transformed_point = cv2.perspectiveTransform(point, matrix)
        poly_points_transformed[i] = transformed_point[0] #np.append(poly_points_transformed, transformed_point)

    return poly_points_transformed


poly_points_transformed = poly_points_transform(points, matrix)

The result is:

poly_points_transformed = 
    array([[1920., 1080.],
           [1920., 1080.],
           [1920., 1080.]])

Why are we getting [1920.0, 1080.0] value for all the transformed points?

Lets transform the middle point mathematically:

Multiply matrix by point (with 1 in the third index)

[  -4.       ,   -3.       , 1920.     ]   [  0]
[  -2.25     ,   -1.6875   , 1080.     ] * [575] = 
[  -0.0020833,   -0.0015625,    1.     ]   [  1]

p = matrix @ np.array([[0.0], [575.0], [1.0]]) = 

[1.950000e+02]
[1.096875e+02]
[1.015625e-01]

Now divide the coordinates by the last element (converting homogeneous coordinates to Euclidian coordinates):

[1.950000e+02/1.015625e-01]              [1920]
[1.096875e+02/1.015625e-01] = p / p[2] = [1080]
[1.015625e-01/1.015625e-01]              [   1]

The equivalent Euclidian point is [1920, 1080].

The transformation matrix may be wrong, because it transforms all the input points (with x coordinate equals 0) to the same output point...

Rotem
  • 30,366
  • 4
  • 32
  • 65