如何使用GDI将正方形位图渲染成任意四边形?

15

我需要绘制一个正方形的图像,映射或变换成一个在编译时不知道的四边形。如何做到这一点?

更长的解释

具体问题是使用非矩形地图投影渲染地图瓦片。假设我有以下瓦片:

Square tile

我知道这四个角点需要在这里:

Four distorted corners

鉴于此,我希望获得以下输出:

Distorted, image-mapped polygon

方形瓷砖可能会:

  • 旋转; 和/或者
  • 一端比另一端更窄。

我认为第二项意味着这需要进行非仿射变换。

随机额外笔记

四边形? 可能为了完全正确,瓷砖应该被映射到具有多于四个点的多边形上,但对于我们的目的并且在绘制的比例下,一个正方形 -> 其他四角多边形转换应该足够了。

为什么最好只使用GDI? 到目前为止,所有渲染都是使用GDI完成的,并且我想保持代码(a)快速和(b)需要尽可能少的额外库。我知道GDI中有一些支持变换的支持,今天我一直在尝试它们,但即使在尝试它们之后,我也不确定它们是否足够灵活以适应此目的。如果可以,我还没有设法弄清楚,因此我真的很需要一些示例代码。

GDI+也可以,因为我们在其他地方使用它,但我知道它可能会很慢,速度在这里很重要。

另一种选择是任何Delphi- / C++Builder-特定的内容;这个程序主要是使用C++编写的,使用VCL,并且目前正在使用TCanvas方法和原始的WinAPI / GDI调用绘制图形。

叠加图像:最后一个警告是瓷砖中的一种颜色可能是用于颜色键透明度:也就是说,上面瓷砖中的所有白色(例如)正方形在绘制到任何下面的东西时都应该是透明的。目前,使用TransparentBlt将瓷砖绘制到正方形或轴对齐的矩形目标上。

对于使这个问题比“我应该使用什么算法?”更复杂的所有额外警告,我感到很抱歉。但是,我也会欣然接受只包含算法信息的答案。


1
@NGLN:看起来完美。我可能忘记了或从未知道那个函数!我明天会试验一下它(现在太晚了)。同时,您能否将其添加为答案? - David
1
抱歉:PlgBlt 只能产生平行四边形。 - NGLN
@AndreasRejbrand,这只是一个填充词。每个人都希望它能够事先快速 :-) - OnTheFly
2
@DavidM,我真的不明白你还想要什么……你已经拥有了完整的源代码、项目名称和期望的输出。看看Graphics32的出色演示:这难道不是“一个特定库如何解决问题的具体示例”吗? - kobik
@kobik:详细的回答更好。 (目前得票最高的答案是一个向量库,甚至不适用于转换光栅图像...)对于Graphics32而言,演示很简单且效果良好,但在较大的应用程序中,它集成得不太好-例如出现奇怪的异常。此外,它的大部分部分(包括主类“TBitmap32”)都没有文档。因此,我寻求一个具体的答案,而不是库推荐,逻辑是我必须花费很长时间调查才能使其在非平凡应用程序中正常工作的答案可以得到改进。赏金赞助改进。 - David
显示剩余4条评论
3个回答

6
您可能还想了解Graphics32。下面的截图展示了GR32中的转换演示效果:

1
这在演示应用程序中运行良好,但在集成到更大的预先存在的应用程序中遇到问题(我在GR32论坛上发布了帖子,不需要混乱,但主要问题是TBitmap32类上的一些方法未被链接器找到,尽管它们在生成的.hpp文件中,并且我无法发现任何错误。)您是否已经在C++ Builder中使用过它,并且知道必须执行什么操作才能使除演示以外的任何内容正常工作? - David
1
@David,抱歉,我只会Delphi。但是请看一下我在GR32论坛上的回复。 - iamjoosy
1
@David :) 谢谢。在你的评论中,你提到了缺乏文档的问题。这并不是真的,只是有点难找。请看这里 - iamjoosy

6
请查看3D实验室矢量图形(特别是演示中的“足球场”)。
另一个很酷的资源是包含完整源代码的AggPas下载)。

AggPas是一种免费的开源2D矢量图形库。它是由Maxim Shemanarev在C++中编写的Anti-Grain Geometry库的Object Pascal本地移植。AggPas不依赖任何图形API或技术。基本上,您可以将AggPas视为从某些矢量数据生成内存中的像素图像的渲染引擎。

这是perspective演示的样子:

enter image description here

变换后:

enter image description here


看起来很酷。但它只支持矢量图吗?我正在处理位图 - 一种光栅图像。 - David
@DavidM,我只是简单地看了一下。我不确定。 - kobik

5
一般的技术描述在George Wolberg的"Digital Image Warping"中。看起来这个摘要包含了相关的数学知识,这篇论文也是如此。你需要创建一个透视矩阵,将一个四边形映射到另一个四边形。上面的链接展示了如何创建矩阵。一旦你有了矩阵,你可以扫描输出缓冲区,执行变换(或可能是反向的-取决于它们给你的是哪个),这将给你原始图像中可以复制的点。

使用OpenGL在4个点之间绘制纹理四边形可能更容易,但这不像你想要的那样使用GDI。


那么你实现了一个扫描线算法,类似于渲染3D多边形,使用矩阵查找原始图像中的像素值? - David
我将赏金授予了上面的Graphics32答案——它是一个有用且快速的库。但这也是一个好答案,我很感激了解算法,如果可以的话,我会给你多个赞的。 - David

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接