2010-08-22 27 views
6

Làm cách nào để áp dụng phép biến đổi phối cảnh trên hình ảnh chỉ sử dụng thư viện GD GD?Chuyển đổi phối cảnh với GD

Tôi không muốn sử dụng một hàm người khác làm tôi muốn HIỂU gì đang xảy ra

+0

Điều này đã được trả lời [ở đây] [1]. [1]: http://stackoverflow.com/a/2536847/577306 – Jarrod

Trả lời

9

Thực sự tôi không biết làm thế nào để mô tả toán học một bóp méo quan điểm. Bạn có thể thử tìm kiếm tài liệu cho điều đó (ví dụ: Google Scholar). Xem thêm trong tài liệu OpenGL, glFrustum.


EDIT: Điều thú vị là, bắt đầu với phiên bản 8, Mathematica có ImagePerspectiveTransformation. Trong phần liên quan, nó nói:

Đối với ma trận 3 * 3 m, ImagePerspectiveTransformation[image,m] áp dụng LinearFractionalTransform[m] cho hình ảnh.

Đây là một sự chuyển đổi đó, đối với một số a (ma trận), b (vector), c (vector) và d (vô hướng), biến đổi vector r để (a.r+b)/(c.r+d). Trong một tình huống 2D, điều này mang đến cho các homogeneous matrix:

a_11 a_12 b_1 
a_21 a_22 b_2 
c_1 c_2 d 

Để áp dụng việc chuyển đổi, bạn nhân ma trận này bằng các vector cột mở rộng với z=1 và sau đó lấy hai yếu tố đầu tiên của kết quả và phân chia chúng bằng cách thứ ba:

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

mang đến cho:

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

với ví dụ:

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

Bạn nhận được chuyển đổi này:

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 
] 

Transformation result


Một khi bạn có một bản đồ mô tả vị trí của một điểm của hình ảnh cuối cùng về một điểm trong bản gốc hình ảnh, nó chỉ là vấn đề tìm giá trị của nó cho mỗi điểm trong hình ảnh mới.

Có thêm một khó khăn nữa. Vì hình ảnh là rời rạc, tức là, có pixel thay vì giá trị liên tục, bạn phải làm cho nó liên tục.

Giả sử bạn có một phép biến đổi tăng gấp đôi kích thước của hình ảnh. Hàm để tính điểm {x,y} trong hình ảnh cuối cùng sẽ tìm kiếm điểm {x/2, y/2} trong ảnh gốc. Điểm này không tồn tại, bởi vì hình ảnh là rời rạc. Vì vậy, bạn phải nội suy điểm này. Có một số chiến lược có thể cho việc này.

Trong ví dụ Mathematica này, tôi làm một vòng quay 2D đơn giản và sử dụng một hàm spline độ-1 để suy:

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}}] 

Điều này cho phép:

alt text

PHP:

Đối với nội suy, google cho "B-spline". Phần còn lại là như sau.

Trước tiên hãy chọn tham chiếu cho hình ảnh gốc, giả sử nếu hình ảnh là bản đồ 200x200, pixel (1,1) bản đồ (0,0) và pixel (200,200) đến (1,1).

Sau đó, bạn phải đoán nơi hình ảnh cuối cùng của bạn sẽ hạ cánh khi chuyển đổi được áp dụng. Điều này phụ thuộc vào việc chuyển đổi, bạn có thể, ví dụ: áp dụng nó vào các góc của hình ảnh hoặc chỉ đoán.

Giả sử bạn xem xét ánh xạ giữa (-5,0) và (1, 1,5) như tôi đã làm và hình ảnh cuối cùng của bạn cũng phải là 200x200. Sau đó:

$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 */ 
    } 
} 
+0

Thú vị nhưng điều đó dường như không có mã PHP (Is nó?) –

+0

@ Mark Không, nó không phải. Đó là Mathematica. Trong PHP, bạn phải tự thực hiện spline và sử dụng hai vòng lặp (lồng nhau) để xây dựng cốt truyện tham số. Nhưng nguyên tắc thì giống nhau. – Artefacto

+0

Bạn sẽ thực hiện điều đó với PHP bằng các vòng lặp như thế nào? –

Các vấn đề liên quan