我想要做的事情听起来很简单,但到目前为止我没有在互联网上找到一种在DotNet中做到这一点的方法,也没有找到第三方组件来做到这一点(没有花费数千个完全不必要的功能) 。 这是:
我有一个地砖(实际照片)的jpeg,我用它创建了一个棋盘图案。 在dotnet中,可以轻松旋转和拼接照片,并将最终图像保存为jpeg。
接下来,我想拍摄最后一张照片,让它看起来好像“瓷砖”正在铺设在一个普通的“房间场景”的地板上。基本上添加一个3D透视图,使其看起来好像它实际上是在房间场景中。
这是一个与地毯类似的网站,但我需要在WinForms应用程序中执行此操作: Flor Website
基本上,我需要创建一个jpeg的3D透视图,然后将其保存为新的jpeg(然后我可以放置一般房间场景的叠加层)。
任何人都知道在哪里可以获得第三方DotNet图像处理模块,可以完成这项看似简单的任务?
答案 0 :(得分:4)
这并不是那么简单,因为你需要一个3D转换,它比简单的2D转换(如旋转,缩放或剪切)更复杂,计算成本更高。为了让您了解数学上的差异,2D变换需要2乘2矩阵,而投影变换(比其他3D变换更复杂)需要4乘4矩阵......
你需要的是一些3D渲染引擎,你可以在其中绘制多边形(在透视图中),并用纹理(如地毯)覆盖它们。对于.Net 2.0,我建议使用SlimDX,它是DirectX的一个端口,允许你渲染多边形,但有一些学习曲线。如果您使用的是WPF(.Net 3.0及更高版本),则内置的3D画布允许您以透视方式绘制纹理多边形。对于您的目的,这可能比SlimDX更容易/更好学习。我确信有一种方法可以将3D画布的输出重定向到jpeg ...
如果您不需要很好的性能并且限制纹理的方向(例如,始终是水平地板或始终是垂直墙),您可以大大简化问题。如果是这样,您可以使用.Net 2.0中的简单绘图循环自行渲染。
答案 1 :(得分: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);
}
}
}