Java 2D加权数据插值

16
我正在尝试找到一些Java库、代码示例(或起点),以帮助我弄清楚如何用权重插值生成等高线插值的2D点列表。
通过谷歌搜索,我发现有几种可用的算法可以实现这个目标,并且我找到了一些有趣内容的解释。我想尝试的第一个算法是反距离加权插值。
但是,对于所有这些信息,我有一些基本的疑问:
要生成像下面的图片一样的图片,我需要制作一个像素矩阵(带权重),插值数据,将像素按颜色范围分组,然后连接点以绘制曲线并放置参考文本值,例如this
如果我需要制作这个像素矩阵,对于大量的插值来说会非常昂贵,所以我可以使用更少的点并使用样条来连接它们以创建颜色级别吗?
示例数据:
+-------------------+
|  X  |  Y  | WEIGHT|
+-------------------+
|  2  |  5  |   30  |
|  7  |  3  |   25  |
|  1  |  1  |   10  |
|  5  |  6  |   45  |
|  7  |  9  |   15  |
+-------------------+

示例规则:
  • 00-10之间的值:蓝色
  • 10-20之间的值:绿色
  • 20-30之间的值:黄色
  • 30-40之间的值:红色
示例结果:

Shepard interpolation example

这个例子中的数据、规则和结果不兼容,只是随机示例来解释我的问题。
这是我的最终测试类:http://pastebin.com/nD6MT8eS

你有没有考虑过线性回归?它还可以通过增加问题的维度来获得一个k次多项式,如(x,y,xy,x^2,y^2,...,x^(k-1)y,y^(k-1)x,x^k,y^k)Weka具有LinearRegression功能。你会发现它有用吗?或者你严格地寻找反距离加权?(注意:线性回归试图将预测与给定数据之间的平方误差最小化) - amit
@amit,我需要使用反距离加权Kriging来完成它,因为这两种方法是最常用的行业标准。因此,起点将是反距离加权 - Tiago
你可以使用JHeatChart来进行绘图。你可能需要获取源代码,这样你就可以尝试不同的插值方法。http://www.javaheatmap.com/ - Gilbert Le Blanc
JHeatChart不支持散点插值,它只能处理二维网格输入数据。 - japreiss
下面的回答中是否有任何遗漏?它告诉你如何计算像上面那样的图像。如果这不是你想要的,请让问题更清楚一些。如果你想要一个像你发布的那样的图像,那么无论如何都需要在某个时候创建一个像素数组。如果你将颜色分割成带状,它将隐含地具有轮廓。如果你想要得到表示轮廓线的函数,那就是另一个问题了。此外,你暗示你想要一个算法。如果你更愿意使用一个为你完成这项工作的库,你应该明确说明。 - mo-seph
3个回答

5
假设您有一个可以使用的Point类(例如java.awt.Point),您可以将权重放入Map中:
Map<Point,Double> points = new HashMap<Point,Double>();
points.put( new Point(2,5), 30 )
...

然后,您可以创建一张图片,并针对每个x,y坐标找到最佳得分。我假设得分是表格中点的权重乘以倒数距离。如果是这样,它的公式如下:

image = createBitmap( width, height )
for( int x = 0; x < width; x++ )
    for( int y = 0; y < height; y++ )
    {
         double maxScore = -Double.MAX_VALUE
         for( Point p : points.keySet() ) 
         {
             double score = points.get(p)/p.distance( x, y ) //Inverse distance times point weight
             minDist = Math.max( maxScore, score )
         }
         image.setPixelColour( x, y, getColorForDistance( 1/minDist * points.get(p) )
    }

getColourForDistance( double dist )应该很明显,但您需要正确设置级别。我假设createBitmap(width,height)创建一张图片。您正在制作哪种类型的图像取决于您的应用程序,以及它是否具有setPixelColor方法或类似方法。点类的选择也取决于您的应用程序。

这不是优化的-至少是O(x * y * p),其中p是点数。如果p变大,则可能需要查看更明智的数据结构来存储点。


你有什么优化这段代码的建议吗?我正在使用它,但是在一个3000像素x 3000像素的图像+5个点的情况下,速度很慢,我的最终目标是生成一个包含1000个点的图像。谢谢。 - Tiago
什么在占用时间?你能对其进行分析吗?你所说的“慢”是指多长时间?它将需要处理900万像素,这通常需要一些时间。最好将此优化作为单独的问题发布。如果点数很大,可以尝试使用空间索引,或通过从每个点开始向外工作并反转来创建最小距离图。但实际上,您需要进行分析以查看哪些部分占用了时间。 - mo-seph

2
为了补充@mo-seph和@Xipan-Xiao的答案,您可以查看jFreeChart项目中实现反距离幂算法的NonGridContourDataset类。NonGridContourDataset

1

不知道如何添加评论,所以我在答案区域添加了我的想法。

至少你不需要“按颜色范围将像素分组,然后连接点以绘制曲线”。要生成所需的图片,只需执行以下操作:

picture = createBitmap( width, height );
for( int x = 0; x < width; ++ x ){
    for( int y = 0;y < height; ++ y ){
        double value = interpolate( x, y, inputs );
        Color color = colorRangeOf( value );
        picture.setPixel( x, y, color );
    }
}

因此,在不创建像素矩阵、分组颜色的情况下,可以创建一幅图像。在指定图片的每个像素值后,边界“曲线”将自动出现。


2
@JesseJ - 你不能仅凭1个声望点数对他人的帖子进行评论。要进行评论,至少需要50个声望点数。 - beaker
@xipan-xiao,我生成位图没有问题,但我需要弄清楚如何生成带有文本标记和曲线的插值数据。 - Tiago
Tiago,使用@mo-seph发布的反d(可能是平方)公式,它将自动制作这些曲线。这与物理学中的重力和电场强度问题有些相似。您只需在该区域使用“力量”作为加权即可。 - user1181445

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