19

我想在 C++ 中实现上述两种图像重采样算法(双三次和 Lanczos)。我知道那里有几十个现有的实现,但我仍然想自己做。我想做到这一点,部分是因为我想了解它们是如何工作的,部分是因为我想给他们一些主流实现中没有的功能(比如可配置的多 CPU 支持和进度报告)。

我尝试阅读维基百科,但这些东西对我来说有点太干了。也许对这些算法有更好的解释?我在 SO 或 Google 上都找不到任何东西。

补充:似乎没有人能给我一个关于这些主题的好链接。至少有人可以在这里解释一下吗?

4

3 回答 3

12

虽然 Ants Aasma 所说的大致描述了差异,但我认为它并不能特别说明你为什么会做这样的事情。

就链接而言,您在图像处理中提出了一个非常基本的问题,任何关于该主题的体面的入门教科书都会对此进行描述。如果我没记错的话,冈萨雷斯和伍兹在这方面做得不错,但我不在我的书本上,无法检查。

现在谈谈细节,从根本上考虑你在做什么应该会有所帮助。您有一个要为其插入新值的测量方格。在上采样的简单情况下,假设您想要在您已经拥有的每个测量之间进行新的测量(例如,分辨率加倍)。

现在您将无法获得“正确”的值,因为通常您没有该信息。所以你必须估计它。这个怎么做?一种非常简单的方法是线性插值。每个人都知道如何用两个点来执行此操作,您只需在它们之间画一条线,然后读取线外的新值(在这种情况下,在中间点)。

现在图像是二维的,所以你真的想在左右和上下方向上都这样做。将结果用于您的估计,瞧,您有“双线性”插值。

这样做的主要问题是它不是很准确,尽管它比“最近邻”方法更好(并且更慢),后者也非常本地和快速。

为了解决第一个问题,您需要比两点的线性拟合更好的东西,您想要将某些东西拟合到更多的数据点(像素),以及可以是非线性的东西。精度和计算成本的良好权衡称为三次样条。因此,这将为您提供一条平滑的拟合线,并再次通过中间值来近似您的新“测量值”。在两个方向上都这样做,你就有了“双三次”插值。

所以这更准确,但仍然很重。解决速度问题的一种方法是使用卷积,它具有很好的特性,在傅立叶域中,它只是一个乘法,所以我们可以很快地实现它。但是您无需担心实现,以了解任何时候的卷积结果都是一个函数(您的图像)被集成到另一个产品中,通常支持更小的支持(非零部分)称为内核的函数),在该内核以该特定点为中心之后。在离散世界中,这些只是产品的总和。

事实证明,您可以设计一个具有与三次样条非常相似的属性的卷积核,并使用它来获得快速的“双三次”

Lancsoz 重采样是类似的事情,内核中的属性略有不同,这主要意味着它们将具有不同的特征工件。您可以很容易地查找这些内核函数的详细信息(我相信维基百科有它们,或任何介绍文本)。图形程序中使用的实现往往是高度优化的,有时有专门的假设,使它们更有效但不太通用。

于 2009-06-03T21:02:30.513 回答
12

两种算法的基本操作原理都非常简单。它们都是卷积滤波器。一个卷积滤波器,它针对每个输出值将卷积函数的原点移动到以输出为中心,然后将输入中的所有值与该位置的卷积函数的值相乘,然后将它们相加。

卷积的一个特性是输出的积分是两个输入函数的积分的乘积。如果考虑输入和输出图像,则积分表示平均亮度,如果您希望亮度保持不变,则卷积函数的积分需要加起来为 1。

如何理解它们的一种方法是将卷积函数视为显示输入像素根据距离影响输出像素的程度。

卷积函数通常被定义为当距离大于某个值时它们为零,这样您就不必考虑每个输出值的每个输入值。

对于 lanczos 插值,卷积函数基于sinc(x) = sin(x*pi)/x函数,但仅采用前几个波瓣。通常为 3:

lanczos(x) = {
    0 if abs(x) > 3,
    1 if x == 0,
    else sin(x*pi)/x
}

这个函数称为过滤器内核。

要使用 lanczos 重新采样,假设您将输出和输入相互叠加,点表示像素位置的位置。对于每个输出像素位置,您从该点取一个框 +- 3 个输出像素。对于位于该框中的每个输入像素,计算该位置的 lanczos 函数的值,并将输出像素坐标中与输出位置的距离作为参数。然后,您需要通过缩放计算值来归一化计算值,使它们加起来为 1。然后将每个输入像素值与相应的缩放值相乘,并将结果加在一起以获得输出像素的值。

因为 lanzos 函数具有可分离性,并且如果您正在调整大小,网格是规则的,您可以通过分别进行水平和垂直卷积并预先计算每行的垂直过滤器和每列的水平过滤器来优化它。

双三次卷积基本相同,只是滤波器核函数不同。

要获得更多详细信息,请参阅《数字图像处理》第 16.3 节中的非常好的和彻底的解释。

此外, skia 中的image_operations.ccconvolver.cc对 lanczos 插值的实现进行了很好的评论。

于 2009-06-03T20:12:38.913 回答
5

我想推荐以下文章,以基本了解通过卷积进行图像插值的不同图像插值方法。如果你想尝试更多的插值方法,imageresampler是一个不错的开源项目。

我认为图像插值可以从两个方面来理解,一个是从函数拟合的角度,一个是从卷积的角度。例如,通过卷积在图像插值中解释的样条插值在三次插值中从函数拟合的角度得到了很好的解释。

此外,图像插值总是与特定应用相关,例如图像缩放、图像旋转等。事实上,对于特定的应用程序,图像插值可以以一种智能的方式实现。例如,图像旋转可以通过三剪切方法实现,并且在每次剪切操作期间可以实现不同的一维插值算法。

于 2013-01-17T17:20:58.277 回答