:-=++*++=-.
+@@@@@@@@@@@@%+:
=%**##@@@@@@@@@@@@%=
.=#+. :::-+*%@@@@@@@@@@#.
.+#- .-#+=--=++++**#%@@@@=
.*#- .::-+*===+**##%###%@@@+
+%=:::....::----:-*##*+==+**#%@@=
=%+.::---:::::::. .=*##*++=+++*#%@@:
:%+:.::-=======-:. :=*###*+=====+*#@#
+%-.::-=+++++===. .-=*####*+=--==+*#@:
*%::::-=++++=====-:....-+*####**+===++*@*
*%:::::-=++*+=---===-:::-+**###****+++++#@
+#:::::-==+#%%%*=--======++*******#**++++*@-
+%:.:::--==*@@%%%##*+===++++***#####**+==++@=
*%:.:::--===*@@#++*%%%#*+++**###%%%%%*++==++%*
+%...::--====*%@@=...-****#%%%@@@@@@@@*++==+*#%
=@:...:--=====+#%@@+. .. :-::=--+=+%@@%*++==+**@:
.@-...:--======+**%@@#=: . :=#@@@%*++==**#@+
%=....:-======++**##%@@@#*+-::---*%@@@@%**++=**#@#
*#....:-=======+*****#%@@@@@@@@@@@@@@@@@%***+=*##%@.
+%.....:-=======+******%%@@@@@@@@@@%@@@@@%#**+=*##%@=
-@.....:-------==+******##%%***###%%@@@@@@##**+=*#%%@*
.@-.....::-----===++******#%%%%%%%%@@@@@@@%###*++*#%%@*
.%+......:::---====++*******##%%%%%%%@@@@@@%###**+*#%%@*
#*.......::---===+++++***********##%%@@@@%%####***##%%@-
+%.......::----==+++++++******++***#%%%@%%######***#%%@%
:@-......::----===++++++++++******##%%%%%########***#%%@:
##--------=====+++++++++**********##################%%@=
✋😆欧内的手,好汉,今天来点儿大家想看的东西。
这是一个用于得到球面上的
通过改变球的角度,可以得到不同的投影,从而验证
“球极投影是动物园的一次伟大实践与创新,是从欧透到说的道理与栗子头的必由之路,是动物园发展历程中的重大转折点,完成了鬼叫时代到道理时代的深刻变革。”
在 DJGun 发布的视频 《DJGun教你制作栗子头和说的道理》 中,说的道理与栗子头的生成方法得到公开。
得到说的道理和栗子头的具体过程如下:
原始图像来自 @海绵宝宝小风儿 视频片头的古神语部分。
采用一般的球面投影方法得到球面上的
首先是在二维情况下分析得到的球极投影的方法:
将圆心置于坐标系原点
取圆上一点
那么拓展到三维可以得到:
将球心置于坐标系原点
取球上一点
按照这一方法,得到球面上的
在上一步骤中,我们已经得到了说的道理,接下来通过变换球的角度得到栗子头。
至此,已经得到了说的道理和栗子头,并验证了
下面进行程序上的实现。
在进行程序实现前,需要先经过数学推导,得到目标图像上点到原图像上点的映射关系。
在上面D老师的演示中,是正向去得到的,而在程序实现中,需要从目标投影图像上的点开始,去反向推算出在原图像上的点的位置。
如前文所述,将球心置于坐标系原点
根据所设定的目标图像的尺寸,遍历每个像素点。设其中一点为
接下来计算点的坐标,为方便观察,在
所需要求的是
$求P点坐标,即向量 \vec{OP}:$
$\vec{OP} = \vec{OD} + \vec{DP}$
$已知有 \vec{OD} = (0,0,-r),\vec{OQ} = (x',y',0),|\vec{OD}| = |\vec{OP}| = r$
$下面须求 \vec{DP}:$
$\vec{DP} = |\vec{DP}| * \frac{\vec{DQ}}{|\vec{DQ}|}$
$\vec{DQ} = \vec{OQ} - \vec{OD} = (x',y',0) - (0,0,-r) = (x',y',r)$
$则 |\vec{DQ}| = \sqrt{x'^2 + y'^2 + r^2}$
$在等腰 \triangle ODP 中,|\vec{DP}| = 2 r \cos{\theta}$
$在 \triangle ODQ中,\cos{\theta} = \frac{|\vec{OD}|}{|\vec{DQ}|} = \frac{r}{\sqrt{x'^2 + y'^2 + r^2}}$
$|\vec{DP}| = 2 r \frac{r}{\sqrt{x'^2 + y'^2 + r^2}} = \frac{2r^2}{\sqrt{x'^2 + y'^2 + r^2}}$
$得到 \vec{DP} = \frac{2r^2}{\sqrt{x'^2 + y'^2 + r^2}}* \frac{(x',y',r)}{\sqrt{x'^2 + y'^2 + r^2}} = \frac{2r^2}{x'^2 + y'^2 + r^2} (x',y',r)$
$令 k = \frac{2r^2}{x'^2 + y'^2 + r^2}$
$综上,P = \vec{OP} = (0,0,-r) + k (x',y',r) = (kx',ky',(k-1)r)$
至此,得到了目标投影图像上的点
这里为便于计算把前面所述球的旋转转换为坐标系的旋转,设某点
绕
可用矩阵表示为:
绕
可用矩阵表示为:
绕
可用矩阵表示为:
那么,根据矩阵乘法的结合律,可以得到,经过变换后的坐标为:
根据球面投影的坐标变换公式:
写出逆变换公式:
这里
转为整形并做边界检查。
至此,已经完成了从投影图像像素点到原始图像像素点的映射的推导。
参数:
- 原始图像:otto.png
- 图像尺寸:400 * 300
- 垂直方向偏移量:0.4
- 缩放倍数:1.5
- 旋转角度:
$\alpha = \gamma = 0 \degree$ ,$\beta = -5 \degree$
参数:
- 原始图像:otto.png
- 图像尺寸:400 * 300
- 垂直方向偏移量:-0.4
- 缩放倍数:1
- 旋转角度:
$\alpha = \gamma = 0 \degree$ ,$\beta = 155 \degree$
本项目使用 Python 编写,依赖 numpy 库进行主要的数学运算。
点击右上方的绿色 Code
按钮,在下拉菜单中点击 Download ZIP
下载完成后,把它解压到你想要的位置。
略。
pip install numpy
编辑 main.py
文件,按需修改开头部分的相关参数。
参数调整完成后,编译运行,在所设定的输出路径下找到生成的投影图像。
1. 路径(相对、绝对路径均可)
path_img
:原始图像
path_proj
:输出的投影图像
2. 输出的投影图像尺寸(像素)
w_proj
:宽
h_proj
:高
3. 偏移量(百分比)
offset_hor
:水平方向(向右为正)
offset_ver
:垂直方向(向下为正)
输出的投影图像相当于在整个投影平面下取了一个矩形区域,以上两个参数就是调整该矩形在投影平面的位置。
均为 0 时,输出的图像中心与坐标轴原点重合;例如当两个偏移量均为
4. 缩放倍数
scale
:缩放倍数
这里的缩放倍数实际是调整球的半径,在前面的数学推导中可以看到,对于相同尺寸的投影区域,球的半径越大,输出图像中包含的内容越少,相当于放大了图像;相反地,球的半径越小,则相当于缩小了图像。
5. 旋转角度(度)
alpha
:绕
beta
:绕
gamma
:绕
是通过坐标系的旋转等效为球上贴图的旋转来实现的,从而得到
坐标系的旋转除我在前文的推导外,也可以参考 “欧拉角-四元数的转换” ,不再赘述。