2011-09-07 53 views
0

我期望做的事聽起來很簡單,但是到目前爲止,在互聯網上沒有找到一種方法可以在DotNet中做到這一點,也沒有發現第三方組件可以做到這一點(無需花費數千個完全不必要的功能)。 這裏有:如何在C#或VB.Net中進行3D變換(透視圖)?

我有一個地板瓷磚(實際照片),我創建了棋盤格局的jpeg。 在dotnet中,很容易旋轉和拼接照片,並將最終圖像保存爲jpeg。

接下來,我想拍攝最終的照片,並使其看起來好像「瓷磚」鋪設在通用「房間場景」的地板上。基本上增加一個3D透視圖,使其看起來好像它實際上在房間場景中。

繼承人一個網站,做與地毯類似的東西,但我必須這樣做的WinForms應用程序:基本上 Flor Website

,我需要創建一個JPEG的3D透視圖,然後保存爲一個新的jpeg(然後我可以放置一般的房間場景)。

任何人都知道在哪裏可以獲得第三方DotNet圖像處理模塊,可以做這看似簡單的任務?

回答

4

這並不是那麼簡單,因爲您需要一個3D轉換,它比簡單的2D轉換(如旋轉,縮放或剪切)更復雜且計算更昂貴。爲了讓您對數學的差異有所瞭解,2D變換需要2 x 2矩陣,而投影變換(比其他3D變換更復雜)需要4 x 4矩陣...

你需要的是一些3D渲染引擎,您可以在其中繪製多邊形(在透視圖中),並用紋理(如地毯)覆蓋它們。對於.Net 2.0,我推薦使用SlimDX,它是DirectX的一個端口,可以讓你渲染多邊形,但是有一些學習曲線。如果您使用的是WPF(.Net 3.0及更高版本),則可以使用內置的3D畫布,讓您以透視的方式繪製紋理多邊形。爲了您的目的,這可能比SlimDX更容易/更好地學習。我相信有一種方法可以將3D畫布的輸出重定向到jpeg ...

如果您不需要很好的性能,並且如果限制紋理(例如,總是一個水平的地板或總是一個垂直的牆壁)。如果是這樣,你可以使用.Net 2.0中的簡單繪圖循環自己渲染它。

+0

+1。 ,使用Direct3D或OpenGL幾乎肯定會比試圖手動編寫自己的透視投影紋理渲染更容易(並給出更好的結果),這也使您可以選擇稍後添加諸如照明和凹凸映射之類的東西t的感覺exture)。 –

3

如果你只是想要一個普通的地板,你的代碼應該是這樣的。警告:獲得理想的結果需要花費大量的時間和精力,特別是如果你不太瞭解數學。但在另一方面,它總是充滿樂趣與這種類型的代碼打...(:

下面的一些樣本圖像

using System; 
using System.Collections.Generic; 
using System.Drawing; 
using System.Windows.Forms; 

namespace floorDrawer 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     ResizeRedraw = DoubleBuffered = true; 

     Width = 800; 
     Height = 600; 

     Paint += new PaintEventHandler(Form1_Paint); 

    } 

    void Form1_Paint(object sender, PaintEventArgs e) 
    { 

     // a few parameters that control the projection transform 
     // these are the parameters that you can modify to change 
     // the output 

     double cz = 10; // distortion 
     double m = 1000; // magnification, usually around 1000 (the pixel width of the monitor) 

     double y0 = -100; // floor height 

     string texturePath = @"c:\pj\Hydrangeas.jpg";//@"c:\pj\Chrysanthemum.jpg"; 


     // screen size 
     int height = ClientSize.Height; 
     int width = ClientSize.Width; 

     // center of screen 
     double cx = width/2; 
     double cy = height/2; 



     // render destination 
     var dst = new Bitmap(width, height); 

     // source texture 

     var src = Bitmap.FromFile(texturePath) as Bitmap; 

     // texture dimensions 
     int tw = src.Width; 
     int th = src.Height; 

     for (int y = 0; y < height; y++) 
      for (int x = 0; x < width; x++) 
      { 
       double v = m * y0/(y - cy) - cz; 
       double u = (x - cx) * (v + cz)/m; 

       int uu = ((int)u % tw + tw) % tw; 
       int vv = ((int)v % th + th) % th; 
       // The following .SetPixel() and .GetPixel() are painfully slow 
       // You can replace this whole loop with an equivalent implementation 
       // using pointers inside unsafe{} code to make it much faster. 
       // Note that by casting u and v into integers, we are performing 
       // a nearest pixel interpolation... It's sloppy but effective. 

       dst.SetPixel(x, y, src.GetPixel(uu, vv)); 
      } 

     // draw result on the form 
     e.Graphics.DrawImage(dst, 0, 0); 
    } 

} 
} 

This is a sample output using one of Windows 7 sample images.

Another example using another Windows 7 sample picture.

+0

而不是逐像素地做這個像素,你只需要計算角點,然後計算適當的2D矩陣並設置'Graphics.transform'來完成它並執行DrawImage()。甚至可能會有一個DrawImage()調用繪製成傾斜的矩形。對不起我的3D數學是20歲,我的Windows編程10. – NPAssoc

+0

@NPAssoc我在幾年前寫了這個解決方案,我想我只是炫耀我的「像素逐像素3D技能」。爲了渲染一個3d投影,據我所知,你需要一個4乘4的仿射矩陣。我同意設置渲染矩陣是一般的方法,但我不認爲System.Drawing.Graphics支持4x4變換矩陣。較新的WPF框架確實可以做到這一點。 –

+0

@NPAssoc我剛剛注意到「歪斜的矩形」的評論。對於傾斜的矩形,您可以使用「剪切」轉換。剪切操作可以用2x2矩陣完成,並且可以通過System.Drawing.Graphics輕鬆處理。請注意,剪切操作與透視仿射投影不同,後者需要我上面的註釋以及其他解決方案中提到的4x4變換。 –