微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

php – 使用GD进行透视转换

如何在图像上应用透视变换
仅使用 PHP GD库?

我不想使用其他人制作的功能,我想要了解正在发生的事情

老实说,我不知道如何用数学方式描述透视失真.您可以尝试搜索文献(例如 Google Scholar).另请参见OpenGL文档 glFrustum.

编辑:有趣的是,从版本8开始,Mathematica有一个ImagePerspectiveTransformation.在相关部分,它说:

For a 3*3 matrix m,ImagePerspectiveTransformation[image,m] applies LinearFractionalTransform[m] to image.

这是一种变换,对于某些(矩阵),b(向量),c(向量)和d(标量),将向量r变换为(a.r b)/(c.r d).在2D情况下,这给出了homogeneous matrix

a_11 a_12 b_1
a_21 a_22 b_2
c_1  c_2  d

要应用变换,将此矩阵乘以用z = 1扩展的列向量,然后取结果的前两个元素并将它们除以第三个:

{{a11,a12,b1},{a21,a22,b2},{c1,c2,d}}.{{x},{y},{1}} // #[[
     1 ;; 2,All]]/#[[3,1]] & // First /@ # &

这使:

{(b1 + a11 x + a12 y)/(d + c1 x + c2 y),(b2 + a21 x + a22 y)/(d + c1 x + c2 y)}

通过示例:

a = {{0.9,0.1},{0.3,0.9}}
b = {0,-0.1}
c = {0,0.1}
d = 1

你得到了这种转变:

im = Import["/home/cataphract/Downloads/so_q.png"];
orfun = BSplineFunction[ImageData[im],SplineDegree -> 1];

(*transf=TransformationFunction[{{0.9,0.1,0.},0.9,-0.1},{0.,1.}}] -- let's expand this:*)

transf = {(0.9 x + 0.1 y)/(1.+ 0.1 y),(-0.1 + 0.3 x + 0.9 y)/(
     1. + 0.1 y)} /. {x -> #[[1]],y -> #[[2]]} &;

ParametricPlot[transf[{x,y}],{x,1},{y,ColorFunction -> (orfun[1 - #4,#3] &),Mesh -> None,FrameTicks -> None,Axes -> False,ImageSize -> 200,PlotRange -> All,Frame -> False
 ]

一旦你有一张地图用原始图像中的一个点来描述最终图像的一个点的位置,那么只需要为新图像中的每个点找到它的值.

还有一个难点.由于图像是离散的,即具有像素而不是连续值,因此必须使其连续.

假设您有一个使图像大小加倍的转换.计算最终图像中的点{x,y}的函数将在原始图像中查找点{x / 2,y / 2}.这一点不存在,因为图像是离散的.所以你必须插入这一点.有几种可能的策略.

在这个Mathematica示例中,我进行了简单的2D旋转并使用1度样条函数进行插值:

im = Import["d:\\users\\cataphract\\desktop\\img.png"]
orfun = BSplineFunction[ImageData[im],SplineDegree -> 1];
transf = Function[{coord},RotationMatrix[20. Degree].coord];
ParametricPlot[transf[{x,Axes -> None,PlotRange -> {{-0.5,{0,1.5}}]

这给出了:

PHP

对于插值,google为“B-spline”.其余如下.

首先选择原始图像的参考,例如图像是200×200,像素(1,1)贴图(0,0)和像素(200,200)映射到(1,1).

然后,您必须猜测在应用变换时最终图像将落在何处.这取决于转换,您可以例如将它应用到图像的角落或只是猜测.

假设你像我一样考虑(-.5,0)和(1,1.5)之间的映射,并且你的最终图像也应该是200×200.然后:

$sizex = 200;
$sizey = 200;
$x = array("min"=>-.5,"max" => 1);
$y = array("min"=>0,"max" => 1.5);
// keep $sizex/$sizey == $rangex/$rangey
$rangex = $x["max"] - $x["min"];
$rangey = $y["max"] - $y["min"];
for ($xp = 1; $xp <= $sizex; $xp++) {
    for ($yp = 1; $yp <= $sizey; $yp++) {
        $value = transf(
             (($xp-1)/($sizex-1)) * $rangex + $x["min"],(($yp-1)/($sizey-1)) * $rangey + $y["min"]);
        /* $value should be in the form array(r,g,b),for instance */
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐