I'm rotating an image at 45 degrees along the y axis.
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.
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.