如何基于简单的多边形绘制图像?

我想将一个大致矩形的区域复制到一个矩形区域。 例:

两个区域都由角点定义。 总体方向保持不变(没有翻转等)。

简单地旋转源图像不起作用,因为相对的侧面可能具有不同的长度。

到目前为止,我发现在纯C#中没有办法做到这一点(手动像素复制除外),所以我想我必须求助于Windows API或某些第三方库?

一般来说,您要做的是通过转换函数将目标坐标映射到源坐标:

for (int y = 0; y < destHeight; y++) { for (x=0; x < destWidth; x++) { Color c = Transform(x, y, sourceImage, sourceTransform); SetPixel(destImage, x, y, c); } } 

让我们假设sourceTransform是一个封装从源到dest坐标的转换的对象(反之亦然)。

在dest坐标中工作将更容易避免重新转换的源图像中的曲线,并允许您更好的抗锯齿,因为您可以将dest像素的角映射到源图像并在其中进行采样并插值/外推。

在你的情况下,你将有一组线性方程式进行映射 - 在这种情况下,这被称为四边形翘曲 - 请参阅前一个问题 。

由于我找不到答案,我自己写了一个天真的实现。 它运作得相当好。

例子

我在Paint中手动绘制了所有示例,因此它们不是很精确 – 它足以测试一些基础知识。

a)轻微旋转。

资源:

源图像

结果:

结果图像

b)各方面

资源:

来源2

结果:

结果2

c)观点

资源:

来源3

结果:

结果3

(它专门用于我的用例,但应该很容易适应):

 // _Corners are, well, the 4 corners in the source image // _Px is an array of pixels extracted from the source image public void Rescale () { RescaleImage ( _Corners[0], _Corners[1], _Corners[3], _Corners[2], 100, 100); } private void RescaleImage (PointF TL, PointF TR, PointF LL, PointF LR, int sx, int sy) { var bmpOut = new Bitmap (sx, sy); for (int x = 0; x < sx; x++) { for (int y = 0; y < sy; y++) { /* * relative position */ double rx = (double) x / sx; double ry = (double) y / sy; /* * get top and bottom position */ double topX = TL.X + rx * (TR.X - TL.X); double topY = TL.Y + rx * (TR.Y - TL.Y); double bottomX = LL.X + rx * (LR.X - LL.X); double bottomY = LL.Y + rx * (LR.Y - LL.Y); /* * select center between top and bottom point */ double centerX = topX + ry * (bottomX - topX); double centerY = topY + ry * (bottomY - topY); /* * store result */ var c = PolyColor (centerX, centerY); bmpOut.SetPixel (x, y, c); } } bmpOut.Save (_Path + "out5 rescale out.bmp"); } private Color PolyColor (double x, double y) { // get fractions double xf = x - (int) x; double yf = y - (int) y; // 4 colors - we're flipping sides so we can use the distance instead of inverting it later Color cTL = _Px[(int) y + 1, (int) x + 1]; Color cTR = _Px[(int) y + 1, (int) x + 0]; Color cLL = _Px[(int) y + 0, (int) x + 1]; Color cLR = _Px[(int) y + 0, (int) x + 0]; // 4 distances double dTL = Math.Sqrt (xf * xf + yf * yf); double dTR = Math.Sqrt ((1 - xf) * (1 - xf) + yf * yf); double dLL = Math.Sqrt (xf * xf + (1 - yf) * (1 - yf)); double dLR = Math.Sqrt ((1 - xf) * (1 - xf) + (1 - yf) * (1 - yf)); // 4 parts double factor = 1.0 / (dTL + dTR + dLL + dLR); dTL *= factor; dTR *= factor; dLL *= factor; dLR *= factor; // accumulate parts double r = dTL * cTL.R + dTR * cTR.R + dLL * cLL.R + dLR * cLR.R; double g = dTL * cTL.G + dTR * cTR.G + dLL * cLL.G + dLR * cLR.G; double b = dTL * cTL.B + dTR * cTR.B + dLL * cLL.B + dLR * cLR.B; Color c = Color.FromArgb ((int) (r + 0.5), (int) (g + 0.5), (int) (b + 0.5)); return c; }