Home > Back-end >  Perspective transformation using coordinates of a 2D image
Perspective transformation using coordinates of a 2D image

Time:08-05

Given a 2D image, I want to transform it to a given plane using a function() to transform the original coordinates to new coordinates on the same screen, with correct proportion.

An example of what I mean: Perspective Transformation

Now, translating the x coordinates I've been able to do, the problem is the translation of 'y' coordinates. I've been able to translate them linearly, but that's not what I want to achieve, because there is no perspective when transforming the coordinate linearly.

I've tried searching for solutions for quite a while now, and I haven't been able to get one. I have come across plenty of examples using openCV and using matrices, but that isn't exactly what I want.

What I'm looking for is a function, given (x, y) coordinates of an image, return (x', y') coordinates which corresponds to the perspective projection (see example).

This is my current C code:

struct Coor {
    Coor(float x, float y) : x(x), y(y) {};

    float x;
    float y;
};

const float WINDOW_SIZE = 100.0f;
const Coor PERSPECTIVE_POINT = {
    WINDOW_SIZE * 0.5f,
    WINDOW_SIZE * 0.3f
};

Coor transform(float x, float y) {
    float perspectiveHeight = WINDOW_SIZE - PERSPECTIVE_POINT.y;
    float linearProportionY = y / WINDOW_SIZE;

    float transformedX = PERSPECTIVE_POINT.x   ((x - PERSPECTIVE_POINT.x) * linearProportionY);

    // This is what I can't compute correctly (I know the proportion is not linearProportionY, it's a placeholder)
    float transformedY = PERSPECTIVE_POINT.y   (perspectiveHeight * linearProportionY);

    return Coor(transformedX, transformedY);
}

Any help would be gladly appreciated!

CodePudding user response:

Your image doesn’t seem right. In actual perspective transformation, only infinitely far points would merge on the horizon.

One possible way to apply the transform is in several steps:

  1. With an affine (linear offset) transform, place the plane into 3D space
  2. Divide x and y by z
  3. With another affine transform, move the result to the desired location.

UPDATE: sample code

// 1. making a small horizontal plane
float X = x/WINDOW_SIZE - 0.5f; // X∈[-0.5, 0.5]
float Y = -0.5f;
float Z = 2.0f - y/WINDOW_SIZE; // Z∈[1.0, 2.0]

// 2. perspective transform
float u = X / Z; // u∈[-0.5, 0.5]
float v = Y / Z; // v∈[-0.5, -0.25]

// 3. scaling the result to fill the window
x = 0.5f * WINDOW_SIZE.x   WINDOW_SIZE * u;
y = 0.5f * WINDOW_SIZE.y - WINDOW_SIZE * v;

You may need to adjust coefficients to make it look more to your taste.

And remember, only artists think in terms of perspective points. In 3D graphics, camera orientation and field of view are the correct things. (and, matrices to handle that easier)

  • Related