图像处理算法之鱼眼镜头特效模拟

       鱼眼镜头拍摄的图像还是挺好玩的,当时做这个特效时,下载了很多应用一一体验,但是发现苹果应用商店或者安卓应用市场上很多鱼眼镜头相关应用,很多都是按照图像变形做的,与真正鱼眼镜头拍摄的效果相差较远。图像变形相关算法可以参考这个链接,上面有公式及源码: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;
}
       下面是一些效果图:
                 
                                           
                 
                                           
                 
                                          
                 
                                           

       参考资料:
       鱼眼特效算法:

       鱼眼镜头图片:


  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值