鱼眼镜头拍摄的图像还是挺好玩的,当时做这个特效时,下载了很多应用一一体验,但是发现苹果应用商店或者安卓应用市场上很多鱼眼镜头相关应用,很多都是按照图像变形做的,与真正鱼眼镜头拍摄的效果相差较远。图像变形相关算法可以参考这个链接,上面有公式及源码:http://paulbourke.net/miscellaneous/imagewarp/,图像变形还是比较简单的,按照公式做个从源图到目标图的映射及插值就可以了。但是鱼眼镜头特效就复杂一些了,鱼眼镜头拍摄的照片主体区域是没有畸变的,看着是正常的成像,而单纯的图像变形会影响整张图像,边界有变形,中间区域亦会变形。理论上讲,普通手机、相机镜头拍摄的图像,成像角度大概70度至90度,也就是把镜头前面70度左右视角空间内的景物成像为一张数码照片。而鱼眼镜头,以180度鱼眼为例,是将上下、左右180度视角空间内的景物成像为一张数码照片,这就是为啥鱼眼镜头都是向外突出的,而我们的普通相机镜头都是平的。所以当180度视角范围的景物成像在一张平面上时,正前方的视角,是不会畸变的,而边缘部分,越靠近镜头边缘,畸变越厉害。所以现在也有很多算法,将鱼眼镜头拍摄的图像展开,就是鱼眼镜头矫正算法。而为了趣味性,本文做的是将普通图像通过算法模拟成鱼眼镜头效果。按照前面所述,将70度视角范围的成像模拟成180度视角,要模拟的一模一样,基本是不可能的,相当于按瓢画葫芦。下面是当时查资料时保存的一些鱼眼镜头成像原理图,现在自己都有点看不懂了。
本文算法核心是坐标转换,即:(1)平面坐标转极坐标,(2)极坐标转球面坐标,(3)球面坐标转纹理坐标。这样经过一系列坐标映射,实现等距180度鱼眼镜头特效模拟。当然,和真实鱼眼镜头差的还是有点远,只能是看着有那么的意思。下面分别是直线与球面交点及部分坐标映射代码:
void RaySphere(CoordXYZ p1, CoordXYZ p2, CoordXYZ sc, float r, float *mu1, float *mu2)
{
float a = 0.0f, b = 0.0f, c = 0.0f, bb4ac = 0.0f;
CoordXYZ dp;
dp.x = p2.x - p1.x;
dp.y = p2.y - p1.y;
dp.z = p2.z - p1.z;
a = dp.x * dp.x + dp.y * dp.y + dp.z * dp.z;
b = 2 * (dp.x * (p1.x - sc.x) + dp.y * (p1.y - sc.y) + dp.z * (p1.z - sc.z));
c = sc.x * sc.x + sc.y * sc.y + sc.z * sc.z;
c += p1.x * p1.x + p1.y * p1.y + p1.z * p1.z;
c -= 2 * (sc.x * p1.x + sc.y * p1.y + sc.z * p1.z);
c -= r * r;
bb4ac = b * b - 4 * a * c;
if (abs(a) < 0.000001f || bb4ac < 0.0f)
{
*mu1 = 0;
*mu2 = 0;
return;
}
*mu1 = (-b + sqrt(bb4ac)) / (2 * a);
*mu2 = (-b - sqrt(bb4ac)) / (2 * a);
}
void ConvertCoordinate(int row_index, int half_height, float x, float y, float r, float fov, float view_pos, float *tex_x, float *tex_y)
{
float phi = atan2(y, x);
float theta = 0.5f*r*fov;
float pos_x = sin(theta) * cos(phi);
float pos_y = sin(theta) * sin(phi);
float pos_z = cos(theta);
CoordXYZ src_pt = { 0.0f, 0.0f, 0.0f };
CoordXYZ pt_1 = { 0.0f, -view_pos, 0.0f };
CoordXYZ pt_2 = { pos_x, pos_y, pos_z };
float mu1 = 0.0f, mu2 = 0.0f;
RaySphere(pt_1, pt_2, src_pt, 5.0f, &mu1, &mu2);
pos_x = pt_1.x + mu1*(pt_2.x - pt_1.x);
pos_y = pt_1.y + mu1*(pt_2.y - pt_1.y);
pos_z = pt_1.z + mu1*(pt_2.z - pt_1.z);
if (pos_z < 0.0f)
{
pos_x = pt_1.x + mu2*(pt_2.x - pt_1.x);
pos_y = pt_1.y + mu2*(pt_2.y - pt_1.y);
pos_z = pt_1.z + mu2*(pt_2.z - pt_1.z);
}
float new_r = sqrt(pos_x*pos_x + pos_z*pos_z);
float new_theta = FILTER_PI*0.5f - atan2(pos_y, new_r);
float new_phi = pos_z < 0.0f ? FILTER_PI - acos(pos_x/new_r) : acos(pos_x/new_r);
*tex_x = 1.0f - new_phi/FILTER_PI;
*tex_y = 1.0f - new_theta/FILTER_PI;
}
下面是一些效果图:
参考资料:
鱼眼特效算法:
鱼眼镜头图片: