Php 用GD实现透视变换

Php 用GD实现透视变换,php,image,gd,transformation,perspective,Php,Image,Gd,Transformation,Perspective,如何在图像上应用透视变换 仅使用PHP GD库 我不想使用别人做的函数,我想理解发生了什么我真的不知道如何从数学上描述透视失真。你可以试着在文献中查找(例如)。另请参见OpenGL文档中的 编辑:有趣的是,从版本8开始,Mathematica有一个。在相关部分,它说: 对于3*3矩阵m,ImagePerspectiveTransformation[image,m]将线性分数变换[m]应用于图像 这是一种转换,对于某些a(矩阵)、b(向量)、c(向量)和d(标量),将向量r转换为(a.r+b)/

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


我不想使用别人做的函数,我想理解发生了什么我真的不知道如何从数学上描述透视失真。你可以试着在文献中查找(例如)。另请参见OpenGL文档中的


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

对于3*3矩阵
m
ImagePerspectiveTransformation[image,m]
线性分数变换[m]
应用于图像

这是一种转换,对于某些
a
(矩阵)、
b
(向量)、
c
(向量)和
d
(标量),将向量
r
转换为
(a.r+b)/(c.r+d)
。在2D情况下,这将提供:

要应用转换,请将该矩阵乘以扩展为
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.3, 
   0.9, -0.1}, {0., 0.1, 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, 0, 1}, {y, 0, 1},
 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, y}], {x, 0, 1}, {y, 0, 1}, 
 ColorFunction -> (orfun[1 - #4, #3] &), Mesh -> None, 
 FrameTicks -> None, Axes -> None, ImageSize -> 200, 
 PlotRange -> {{-0.5, 1}, {0, 1.5}}]
这使得:

PHP:

对于插值,谷歌搜索“B样条曲线”。其余情况如下

首先为原始图像选择一个参考,例如,如果图像为200x200,则像素(1,1)映射为(0,0),像素(200200)映射为(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 */
    }
}
$sizex=200;
$sizey=200;
$x=数组(“最小值”=>0.5,“最大值”=>1);
$y=阵列(“最小值”=>0,“最大值”=>1.5);
//保持$sizex/$sizey==$rangex/$rangey
$rangex=$x[“最大”]-$x[“最小”];
$rangey=$y[“最大”]-$y[“最小”];

对于($xp=1;$xp@Mark No,它不是。它是Mathematica。在PHP中,您必须自己实现样条曲线,并使用两个循环(嵌套)来构建参数化绘图。但原理是一样的。您将如何使用循环将其实现到PHP中?@geon这是短语所说的。its指的是映射(将新功能转换为旧功能)。此问题已得到回答[此处][1]。[1]:
$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 */
    }
}