【问题标题】:Linear interpolation of two vector arrays with different lengths两个不同长度的向量数组的线性插值
【发布时间】:2020-02-07 08:40:18
【问题描述】:

我有两条曲线。一个手绘,一个是手绘的平滑版本。 每条曲线的数据存储在 2 个单独的向量数组中。 时间增量也存储在手绘曲线矢量中,因此我可以重播绘制过程,使其看起来自然。

现在我需要将时间增量从曲线 1(原始输入)转移到曲线 2(已经平滑的曲线)。

第一个向量的大小有时比第二个向量大,有时比第二个向量小。
(取决于输入绘制速度)

所以我的问题是:如何用正确的值填充向量 PenSmoot.time?

案例一:输入向量较大

PenInput.time[0] = 0         PenSmoot.time[0] = 0
PenInput.time[1] = 5         PenSmoot.time[1] = ?
PenInput.time[2] = 12        PenSmoot.time[2] = ?
PenInput.time[3] = 2         PenSmoot.time[3] = ?
PenInput.time[4] = 50        PenSmoot.time[4] = ?
PenInput.time[5] = 100
PenInput.time[6] = 20
PenInput.time[7] = 3
PenInput.time[8] = 9
PenInput.time[9] = 33

案例 2:输入向量更小

PenInput.time[0] = 0         PenSmoot.time[0] = 0
PenInput.time[1] = 5         PenSmoot.time[1] = ?
PenInput.time[2] = 12        PenSmoot.time[2] = ?
PenInput.time[3] = 2         PenSmoot.time[3] = ?
PenInput.time[4] = 50        PenSmoot.time[4] = ?
                             PenSmoot.time[5] = ?
                             PenSmoot.time[6] = ?
                             PenSmoot.time[7] = ?
                             PenSmoot.time[8] = ?
                             PenSmoot.time[9] = ?

简化表示:

PenInput holds the whole data of a drawn curve (Raw Input)

PenInput.x         // X coordinate)
PenInput.y         // Y coordinate)
PenInput.pressure  // The pressure of the pen)
PenInput.timetotl  // Total elapsed time)
PenInput.timepart  // Time fragments)

PenSmoot holds the data of the massaged (smoothed,evenly distributed) curve of PenInput

PenSmoot.x         // X coordinate)
PenSmoot.y         // Y coordinate)
PenSmoot.pressure  // Unknown - The pressure of the pen)
PenSmoot.timetotl  // Unknown - Total elapsed time)
PenSmoot.timepart  // Unknown - Time fragments)


这是我拥有的结构。

struct Pencil 
{
    sf::VertexArray vertices;
    std::vector<int> pressure;
    std::vector<sf::Int32> timetotl;
    std::vector<sf::Int32> timepart;
};

【问题讨论】:

  • 代码示例会更有帮助。
  • 到目前为止,您自己尝试做些什么来解决这个问题?
  • 对于线性插值,您有两个点(通常是 x,y 值),并且您在这两个点之间有一些第三点 x,您想要为其查找 y 值。您的问题的要点是什么,您要插入的x 值列表是什么,以找到y 的值?见Linear interpolation
  • 如果您只是想均匀地分配时间值,这非常简单。转换时间以存储累积和,然后对于目标中的每个索引,计算(可能是小数)索引以对“嘈杂”时间进行采样。使用基本的线性插值来计算分数索引的时间。现在,您的平滑时间也是重新采样的累积总和。现在将其反转以将这些时间变回增量,您就完成了。
  • 我说的是重新采样从一个样本计数到一个新样本计数的时间增量,假设您想尽可能地保留它们。微不足道的情况是噪声和平滑计数相同,所有其他情况通过累积和的线性插值来近似。在所有情况下,最终结果是噪声和平滑时间加起来应该是相同的总时间,并且具有大致相同的“形状”。

标签: c++ linear-interpolation


【解决方案1】:

[此答案已根据对问题的编辑进行了广泛修改。]

好的,在我看来,您只需插入与点平行的时间戳。

我猜测传入的数据是点数组(例如,X,Y 坐标)和时间增量数组的顺序,每个数组的数量相同,所以时间增量 N 告诉您从 N-1 点到 N 点所花费的时间。

当您对点进行插值时,您可能想要智能地进行插值。例如,在问题所示的形状中,我们有两条近似直线,一条斜率为正,另一条斜率为负。根据图片,那是由263个点组成的。通过选择两个端点加上两条线相交的一个点,我们可以将其减少到三个点,并且仍然可以相当合理地表示原始形状。

不过,我们可能不需要走那么远。特别是考虑到时间,我们可能希望至少使用 7 个点作为输出——每个彩色段的每个端点一个。这将给我们 6 条直线段。假设它们位于点 0、30、140、180、200、250 和 263。

然后我们会在时间增量上使用完全相同的分段。将 0 到 30 的增量相加,得到第一段的平均速度。将 31 到 140 的增量相加,得到第二段的平均速度(依此类推到最后)。

增加点数的方法大致相同。我们需要准确查看哪些输入点用于创建一对输出点。举一个简单的例子,假设我们产生的输出正好是输入点数的两倍。然后,我们会在每对输入点的中间精确插入时间增量。

在问题所示的情况下,我们从不均匀分布的输入开始,但产生均匀分布的输出。所以第二个输出点可能是前四个输入点的平均值。下一个输出点可能是三个输入点的平均值(依此类推)。在许多情况下,输出中段的任何端点都可能与输入中的任何点都不精确对应。

那也不错。我们在输入的两点之间进行插值,以确定输出段起点的时间间隔。对于终点也是如此。然后我们可以根据点之间的时间增量来计算它们之间应该花费的总时间。

如果您想变得花哨,可以使用高阶插值而不是线性插值。这确实需要每个插值更多的输入点,但看起来你可能有很多事情要做,比如二次或三次插值(在大多数情况下)。这可能会在转换时产生最大的差异——“笔”快速加速或减速的地方。在这样的地方,线性插值可能会产生一些误导性的结果(尽管考虑到您似乎正在使用的点数,它可能不会产生足够的差异来引起注意)。

作为一个例子,让我们考虑一条直线。我们将从 5 个输入点开始,生成 7 个输出点。

因此,输入点为 [0, 2, 7, 10, 15],相关的时间增量为 [0, 1, 4, 8, 3]。

因此,总行驶距离为 16,我们希望输出点均匀分布。因此,输出点之间的距离将是 16/7 =(大约)2.29。

所以,显然第一个输出点和时间都是0。第二个输出点是2.29。为了计算输出时间,我们将整个时间带到第一个输入点 (0->2),加上 0.29 / (7-2) * (4-1)。该插值部分给出 1.37,因此我们的第一个输出时间增量为 2.37。

下一个输出点应该在 4.58 的距离处。由于第二个输入段从 2 变为 7,我们的整个第二个输出段将位于第二个输入段内。因此,我们取 2.29 / (7-2),告诉使用该输出段占用输入段的 0.458。然后我们将其乘以第二个输入段的时间,得到第二个输出段的时间增量:.458 * (4-1) = 1.374。

[...它继续以同样的方式直到我们到达终点。]

【讨论】:

  • 您好,感谢您的回答。问题是我已经有两条曲线了。一个原始输入和一个平滑。缺少的是已经平滑曲线的时间。我想重现用户如何绘制。所以当我播放时它看起来很自然。但只是使用平滑曲线而不是原始输入。我使用 RamerDouglasPeucker 来减少 RAW 曲线,然后我应用 ChaikinSmooth,最后我应用 UniforLinearInterpolation 以使点均匀分布,以便在绘制实际画笔时没有间距。
  • 是的,你是对的,这是三角洲!时间分数。当你把它们加在一起时,你会看到绘制整条曲线需要多长时间。
  • 哇!谢谢!我想我必须多读 10 次,但我相信我了解基础知识。当您说“特别考虑到时间,我们可能希望使用至少 7 分作为输出”。这是否适用于任何类型的曲线/时间组合?例如,如果一个人画一个正方形怎么办?那么最多的时间集中在4个角落。算法如何“检测”这些时间集中区域并相应地进行拆分?
  • @Chris:我在an old answer 中讨论了如何进行拆分的一种可能性。就目前而言,使用 40% 的变化作为组变化的信号,但这是任意选择的——您可能需要进行一些调整才能为您的数据获得良好的结果。在这种情况下,您也不想在分组之前对数据进行排序。
  • @Chris:哦,还有一个细节:根据您收集数据的频率,您可能希望一次查看的点不止一对做出关于分组的决定。对于手部输入,您可能希望/需要在做出决定之前进行一些平均,以确保您看到的是真正的运动变化,而不仅仅是某人的手有点颤抖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
  • 2013-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-09
  • 2012-07-29
相关资源
最近更新 更多