Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Direct formula for 3D rotation done by warpPerspective or remap

I'm rotating an image at 45 degrees along the y axis.

image description

Based on this link, I do:

Mat rotate3D(Mat in, Mat *out, float rotx, float roty, float rotz) {
    int f = DEFAULT_F;

    int h = in.rows;
    int w = in.cols;

    float cx = cosf(rotx / R2D), sx = sinf(rotx / R2D);
    float cy = cosf(roty / R2D), sy = sinf(roty / R2D);
    float cz = cosf(rotz / R2D), sz = sinf(rotz / R2D);

    float roto[3][2] = {
    { cz * cy, cz * sy * sx - sz * cx },
    { sz * cy, sz * sy * sx + cz * cx },
    { -sy, cy * sx }
    };

    float pt[4][2] = {{ -w / 2, -h / 2 }, { w / 2, -h / 2 }, { w / 2, h / 2 }, { -w / 2, h / 2 }};
    float ptt[4][2];
    for (int i = 0; i < 4; i++) {
        float pz = pt[i][0] * roto[2][0] + pt[i][1] * roto[2][1];
        ptt[i][0] = w / 2 + (pt[i][0] * roto[0][0] + pt[i][1] * roto[0][1]) * f * h / (f * h + pz);
        ptt[i][1] = h / 2 + (pt[i][0] * roto[1][0] + pt[i][1] * roto[1][1]) * f * h / (f * h + pz);
    }

    Mat in_pt = (Mat_<float>(4, 2) << 0, 0, w, 0, w, h, 0, h);
    Mat out_pt = (Mat_<float>(4, 2) << ptt[0][0], ptt[0][1],
    ptt[1][0], ptt[1][1], ptt[2][0], ptt[2][1], ptt[3][0], ptt[3][1]);

    Mat transform = getPerspectiveTransform(in_pt, out_pt);

    warpPerspective(in, *out, transform, in.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    return transform;
}

I prefer to remap instead of warpPerspective. So I used this link to convert the getPerspectiveTransform into a remap. Basically, it's replacing a warpPerspective by a remap.

void perspective2Maps(Mat perspective_mat, Size img_size, Mat* remaps) { Mat inv_perspective(perspective_mat.inv()); inv_perspective.convertTo(inv_perspective, CV_32FC1);

    Mat xy(img_size, CV_32FC2);
    float *pxy = (float*)xy.data;
    for (int y = 0; y < img_size.height; y++)
        for (int x = 0; x < img_size.width; x++) {
            *pxy++ = x;
            *pxy++ = y;
        }

    Mat xy_transformed;
    perspectiveTransform(xy, xy_transformed, inv_perspective);
    split(xy_transformed, remaps);
}

Then, I can do:

remap(in, out, remaps[0], remaps[1], INTER_LINEAR, BORDER_CONSTANT);

It's working well, both with warpPerspective or remap.

image description

Now, I wish to have the direct formula of the remap matrices. I thought it would be:

void rotate3DPoint(Point2f in, Point2f *out, int w, int h, float rotx, float roty, float rotz) {
    int f = DEFAULT_F;

    float cx = cosf(rotx / R2D), sx = sinf(rotx / R2D);
    float cy = cosf(roty / R2D), sy = sinf(roty / R2D);
    float cz = cosf(rotz / R2D), sz = sinf(rotz / R2D);

    float roto[3][2] = {
    { cz * cy, cz * sy * sx - sz * cx },
    { sz * cy, sz * sy * sx + cz * cx },
    { -sy, cy * sx }
    };

    float pz = in.x * roto[2][0] + in.y * roto[2][1];
    out->x = w / 2 + (in.x * roto[0][0] + in.y * roto[0][1]) * f * h / (f * h + pz);
    out->y = h / 2 + (in.x * roto[1][0] + in.y * roto[1][1]) * f * h / (f * h + pz);
}

But it's not similar. Note that I'm in the case of rotx = 0.0f, roty = 45.0f, rotz = 0.0f.

Direct formula for 3D rotation done by warpPerspective or remap

I'm rotating an image at 45 degrees along the y axis.

image description

Based on this link, I do:

Mat rotate3D(Mat in, Mat *out, float rotx, float roty, float rotz) {
    int f = DEFAULT_F;
2;

    int h = in.rows;
    int w = in.cols;

    float cx = cosf(rotx / R2D), sx = sinf(rotx / R2D);
    float cy = cosf(roty / R2D), sy = sinf(roty / R2D);
    float cz = cosf(rotz / R2D), sz = sinf(rotz / R2D);

    float roto[3][2] = {
    { cz * cy, cz * sy * sx - sz * cx },
    { sz * cy, sz * sy * sx + cz * cx },
    { -sy, cy * sx }
    };

    float pt[4][2] = {{ -w / 2, -h / 2 }, { w / 2, -h / 2 }, { w / 2, h / 2 }, { -w / 2, h / 2 }};
    float ptt[4][2];
    for (int i = 0; i < 4; i++) {
        float pz = pt[i][0] * roto[2][0] + pt[i][1] * roto[2][1];
        ptt[i][0] = w / 2 + (pt[i][0] * roto[0][0] + pt[i][1] * roto[0][1]) * f * h / (f * h + pz);
        ptt[i][1] = h / 2 + (pt[i][0] * roto[1][0] + pt[i][1] * roto[1][1]) * f * h / (f * h + pz);
    }

    Mat in_pt = (Mat_<float>(4, 2) << 0, 0, w, 0, w, h, 0, h);
    Mat out_pt = (Mat_<float>(4, 2) << ptt[0][0], ptt[0][1],
    ptt[1][0], ptt[1][1], ptt[2][0], ptt[2][1], ptt[3][0], ptt[3][1]);

    Mat transform = getPerspectiveTransform(in_pt, out_pt);

    warpPerspective(in, *out, transform, in.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    return transform;
}

I prefer to remap instead of warpPerspective. So I used this link to convert the getPerspectiveTransform into a remap. Basically, it's replacing a warpPerspective by a remap.

void perspective2Maps(Mat perspective_mat, Size img_size, Mat* remaps) {
 Mat inv_perspective(perspective_mat.inv());
 inv_perspective.convertTo(inv_perspective, CV_32FC1);

CV_32FC1);
 Mat xy(img_size, CV_32FC2);
float *pxy = (float*)xy.data;
for (int y = 0; y < img_size.height; y++)
for (int x = 0; x < img_size.width; x++) {
*pxy++ = x;
*pxy++ = y;
}
Mat xy_transformed;
perspectiveTransform(xy, xy_transformed, inv_perspective);
split(xy_transformed, remaps);
}

Then, I can do:

remap(in, out, remaps[0], remaps[1], INTER_LINEAR, BORDER_CONSTANT);

It's working well, both with warpPerspective or remap.

image description

Now, I wish to have the direct formula of the remap matrices. I thought it would be:

void rotate3DPoint(Point2f in, Point2f *out, int w, int h, float rotx, float roty, float rotz) {
    int f = DEFAULT_F;
2;

    float cx = cosf(rotx / R2D), sx = sinf(rotx / R2D);
    float cy = cosf(roty / R2D), sy = sinf(roty / R2D);
    float cz = cosf(rotz / R2D), sz = sinf(rotz / R2D);

    float roto[3][2] = {
    { cz * cy, cz * sy * sx - sz * cx },
    { sz * cy, sz * sy * sx + cz * cx },
    { -sy, cy * sx }
    };

    float pz = in.x * roto[2][0] + in.y * roto[2][1];
    out->x = w / 2 + (in.x * roto[0][0] + in.y * roto[0][1]) * f * h / (f * h + pz);
    out->y = h / 2 + (in.x * roto[1][0] + in.y * roto[1][1]) * f * h / (f * h + pz);
}

But it's not similar. Note that I'm in the case of rotx = 0.0f, roty = 45.0f, rotz = 0.0f.0.0f. So it simplifies to the following:

void rotate3DPoint(Point2f in, Point2f *out, float w, float h) {
    float f = 2;
    float cy = cosf(45.0f / R2D);
    float sy = sinf(45.0f / R2D);

    out->x = w / 2 + (in.x * cy) * f * h / (f * h - in.x * sy);
    out->y = h / 2 + in.y * f * h / (f * h - in.x * sy);
}

But it's still not working. I also tried to invert the formula in this last function, but nothing better. What am I missing?