Mic*_*ner 12 graphics image-processing
给定两个图像缓冲区(假设它是一个大小宽度为*的整数数组,每个元素都有一个颜色值),如何将一个四边形定义的区域从一个图像缓冲区映射到另一个(总是方形)图像缓冲区?我被理解这被称为"投射变换".
我也在寻找一种通用的(不是语言或库特定的)方式,这样它可以合理地应用于任何语言而不依赖于"为我完成所有工作的魔术功能X".
一个例子:我用Java编写了一个简短的程序,使用处理库(processing.org)从相机中捕获视频.在初始"校准"步骤期间,捕获的视频直接输出到窗口中.然后,用户点击四个点来定义将被变换的视频区域,然后在程序的后续操作期间映射到方形窗口.如果用户单击定义在相机输出中以一定角度可见的门角的四个点,则此变换将导致后续视频将门的变换图像映射到窗口的整个区域,尽管有点扭曲.
使用线性代数比所有几何都容易得多!此外,您不需要使用正弦,余弦等,因此您可以将每个数字存储为有理分数,并在需要时获得精确的数值结果.
您想要的是从旧的(x,y)坐标到新的(x',y')坐标的映射.你可以用矩阵来做.你需要找到2乘4的投影矩阵P,使P乘以旧坐标等于新的坐标.我们假设您将线条映射到线条(例如,不是直线到抛物线).因为你有一个投影(平行线不保持平行)和平移(滑动),你也需要一个因子(xy)和(1).绘制为矩阵:
[x ]
[a b c d]*[y ] = [x']
[e f g h] [x*y] [y']
[1 ]
Run Code Online (Sandbox Code Playgroud)
你需要知道一个通过h,所以解决这些方程式:
a*x_0 + b*y_0 + c*x_0*y_0 + d = i_0
a*x_1 + b*y_1 + c*x_1*y_1 + d = i_1
a*x_2 + b*y_2 + c*x_2*y_2 + d = i_2
a*x_3 + b*y_3 + c*x_3*y_3 + d = i_3
e*x_0 + f*y_0 + g*x_0*y_0 + h = j_0
e*x_1 + f*y_1 + g*x_1*y_1 + h = j_1
e*x_2 + f*y_2 + g*x_2*y_2 + h = j_2
e*x_3 + f*y_3 + g*x_3*y_3 + h = j_3
Run Code Online (Sandbox Code Playgroud)
同样,您可以使用线性代数:
[x_0 y_0 x_0*y_0 1] [a e] [i_0 j_0]
[x_1 y_1 x_1*y_1 1] * [b f] = [i_1 j_1]
[x_2 y_2 x_2*y_2 1] [c g] [i_2 j_2]
[x_3 y_3 x_3*y_3 1] [d h] [i_3 j_3]
Run Code Online (Sandbox Code Playgroud)
插入你的角落x_n,y_n,i_n,j_n.(Corners工作得最好,因为如果你从用户点击中选择点数,它们相距很远就能减少误差.)取4x4矩阵的倒数并乘以等式的右边.该矩阵的转置是P.您应该能够找到计算矩阵逆和在线乘法的函数.
你可能会有错误的地方:
编辑
以下关于角度比不变性的假设是不正确的.投射变换反而保留了交叉比率和发生率.那么解决方案是:
嗯......我会捅这个.该解决方案依赖于在变换中保持角度比率的假设.请参阅图像以获得指导(抱歉图像质量不佳......真的很晚).该算法仅提供四边形中的点到方形中的点的映射.您仍然需要实现处理映射到同一个方点的多个四点.
设ABCD为四边形,其中A是左上顶点,B是右上顶点,C是右下顶点,D是左下顶点.该对(xA,yA)表示顶点A的x和y坐标.我们将该四边形中的点映射到其边长等于m的方形EFGH.
计算长度AD,CD,AC,BD和BC:
AD = sqrt((xA-xD)^2 + (yA-yD)^2)
CD = sqrt((xC-xD)^2 + (yC-yD)^2)
AC = sqrt((xA-xC)^2 + (yA-yC)^2)
BD = sqrt((xB-xD)^2 + (yB-yD)^2)
BC = sqrt((xB-xC)^2 + (yB-yC)^2)
Run Code Online (Sandbox Code Playgroud)
设θtaD是顶点D处的角度,θC是顶点C处的角度.使用余弦定律计算这些角度:
thetaD = arccos((AD^2 + CD^2 - AC^2) / (2*AD*CD))
thetaC = arccos((BC^2 + CD^2 - BD^2) / (2*BC*CD))
Run Code Online (Sandbox Code Playgroud)
我们将四边形中的每个点P映射到正方形中的点Q. 对于四边形中的每个点P,请执行以下操作:
找到距离DP:
DP = sqrt((xP-xD)^2 + (yP-yD)^2)
Run Code Online (Sandbox Code Playgroud)找到距离CP:
CP = sqrt((xP-xC)^2 + (yP-yC)^2)
Run Code Online (Sandbox Code Playgroud)找到CD和DP之间的角度thetaP1:
thetaP1 = arccos((DP^2 + CD^2 - CP^2) / (2*DP*CD))
Run Code Online (Sandbox Code Playgroud)找到CD和CP之间的角度thetaP2:
thetaP2 = arccos((CP^2 + CD^2 - DP^2) / (2*CP*CD))
Run Code Online (Sandbox Code Playgroud)thetaP1与thetaD的比值应为thetaQ1与90的比值.因此,计算thetaQ1:
thetaQ1 = thetaP1 * 90 / thetaD
Run Code Online (Sandbox Code Playgroud)同样,计算thetaQ2:
thetaQ2 = thetaP2 * 90 / thetaC
Run Code Online (Sandbox Code Playgroud)找到距离HQ:
HQ = m * sin(thetaQ2) / sin(180-thetaQ1-thetaQ2)
Run Code Online (Sandbox Code Playgroud)最后,Q相对于EFGH左下角的x和y位置是:
x = HQ * cos(thetaQ1)
y = HQ * sin(thetaQ1)
Run Code Online (Sandbox Code Playgroud)您必须跟踪有多少颜色值映射到方形中的每个点,以便您可以计算每个点的平均颜色.
归档时间: |
|
查看次数: |
9924 次 |
最近记录: |