0

我想做的事情听起来很简单,但到目前为止,我在 Internet 上的任何地方都没有找到在 DotNet 中执行此操作的方法,也没有找到可以执行此操作的第 3 方组件(无需花费数千美元购买完全不必要的功能)。开始:

我有一个地砖的 jpeg(实际照片),我用它创建了一个棋盘图案。在 dotnet 中,很容易将照片旋转和拼接在一起,并将最终图像保存为 jpeg。

接下来,我想拍下最后一张照片,让它看起来好像“瓷砖”铺设在地板上,以形成一个通用的“房间场景”。基本上是添加一个 3D 透视图,让它看起来好像真的在房间场景中一样。

这是一个与地毯类似的网站,但是我需要在 WinForms 应用程序中执行此操作: Flor 网站

基本上,我需要创建一个 jpeg 的 3D 透视图,然后将其保存为一个新的 jpeg(然后我可以放置一个通用房间场景的叠加层)。

任何人都知道在哪里可以获得可以完成这个看似简单的任务的第 3 方 DotNet 图像处理模块?

4

2 回答 2

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 中的简单绘图循环自己渲染它。

于 2011-09-07T18:23:44.600 回答
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);
    }

}
}

这是使用 Windows 7 示例图像之一的示例输出。

另一个使用另一个 Windows 7 示例图片的示例。

于 2011-09-07T19:07:07.387 回答