【问题标题】:Algorithm to morph one shape into another.将一种形状变形为另一种形状的算法。
【发布时间】:2012-11-27 03:00:26
【问题描述】:

我正在尝试研究一种将一种“形状”变形为另一种“形状”的算法。这两种形状都是任意的,甚至可能还有更小、不连贯的形状。

到目前为止,我的基本想法如下:定位形状的边缘,沿这些边缘放置点,然后对目标图像执行相同操作,然后将点移动到它们的目标。

这是一个插图:

我只是不知道从哪里开始。上图是简化图,实际用例具有更复杂的形状/轮廓。我的主要问题是:如何处理不相交的形状?我能想到的最好的办法是找出两部分之间的最近点,并将它们连接在一起作为路径的一部分。但是我该如何实现呢?

我还没有任何代码,我仍处于计划阶段。我想我要问的是是否有人可以将我链接到任何可能有帮助的资源,或提供任何指示。搜索谷歌已经产生了一些有趣的变形算法,但它们都处理完整的图像,并涉及将图像分解成碎片以重塑它们,这不是我想要的。

请注意,这将在 JavaScript 中使用,但如果更简单,可以在 PHP 中预先计算。

【问题讨论】:

  • 可以为此安装第三方 PHP 扩展吗?有了 OpenCV it seem to be pretty straightforward 之后。
  • 我宁愿不必为了使用其中一个功能而获得整个扩展。有没有办法将该特定功能移植到 PHP 或 JavaScript?
  • 我想通过大量工作和 emscripten 它可以“移植”,还有其他部分 opencv 端口,如实现 findContours 的 js-aruco,但这个项目似乎被放弃了,但是它包含在 simplecv-js 项目中,该项目有其他相关的好东西(比如在 pixastic 中进行边缘检测以替代缺失的 canny)。
  • How do I handle disjoint shapes? 是什么意思你实现了标准形状吗?您的预期输出不清楚
  • 这绝对是矢量图的工作,而不是位图。在 Javascript 中的浏览器中将比在 PHP 中容易得多,因为浏览器内置了对矢量图形的支持。像 Raphael 这样的库会使其相对简单。

标签: php javascript image-manipulation


【解决方案1】:

最好将问题分解成多个可以独立解决的小问题。这样你在解决这个问题后也拥有独立的功能,可以添加到一些全局模块集合中。

首先我们需要弄清楚from_shape中的哪个像素去to_shape中的哪个像素。
我们可以通过以下方法来判断:

  1. 将 to_shape 放在 from_shape 上。

  2. 对于 from_shape 中的每个像素,找到它最接近的 to_shape 像素。
    形状中的每个像素都必须有一个唯一的 id,例如,该 id 可以是它的 xy 位置。

  3. 现在您可以在 from_shape 中记录每个唯一像素,以及它进入 to_shape 中的哪个唯一像素。

  4. 删除重叠的形状,回到原来的形状,
    刚才 from_shape 中的每个像素都知道它在 to_shape 中的目的地。

我们还需要知道每个像素有哪些“兄弟”。
同级像素是紧邻另一个像素的像素。
要找到它,请转到给定像素,从中收集半径为 1 的所有像素,所有这些像素都是黑色的......是来自像素的兄弟姐妹。当像素移动到目的地时,此信息对于将形状保持为单个单元是必要的。跳过兄弟姐妹会大大加快和简化变形,但如果没有它们,形状可能会在变形过程中变得支离破碎。可能想从无兄弟版本开始,看看情况如何。

最后我们实现了变形:

  1. 有 morph_time_duration。
    对于 from_shape 中的每个像素,在 to_shape 中找到到其目的地的距离。
    该距离除以 morph_time_duration,就是像素在变形过程中的速度。
    此外,朝向目的地的角度是旅行的角度。
    所以现在你有了速度和角度。

  2. 因此,在变形过程中的每一帧,给定的 from_pixel 现在都知道行进的方向、速度,并且它还知道它的兄弟姐妹。因此,在每一帧中,在以它的速度向它的方向移动之后,只需在它的新位置绘制像素。然后为所有像素兄弟画一条线。

这将显示你的变形。

【讨论】:

  • 这似乎是最有帮助的答案,因为它将问题分解为我可以弄清楚的步骤。
【解决方案2】:

我发现 a demonstration (using Raphael.js) 在 JavaScript 中进行轮廓变形和补间动画,展示了如何使用 Raphael.js 将一条曲线变形为另一条曲线。

另外,this related question(关于 JavaScript 中的形状补间)可能包含一些与此问题相关的答案。

MorpherJS library 也可能适用于此目的。使用 MorpherJS can be found here 进行轮廓变形的一些演示。

【讨论】:

【解决方案3】:

做到这一点并不容易,但我可以给你几个起点。如果你想要一个简单的 javascript 实现,一个很好的起点是: http://raphaeljs.com/animation.html 这正是你想要的。因此,您可以检查调用了哪些方法并浏览库源代码以查看这些方法的实现。

如果您需要在 PHP 中变形 2 个图像,我建议您使用某种扩展,而不是在普通 PHP 中这样做。这是一个使用 ImageMagick 执行此操作的示例: http://www.fmwconcepts.com/imagemagick/shapemorph2/index.php

如果您想了解更多关于它的内部结构: http://web.mit.edu/manoli/www/ecimorph/ecimorph.html#algo

希望其中之一有所帮助。

【讨论】:

    【解决方案4】:

    简短的回答是,如果您想自己动手,这不是一项简单的任务。有很多关于这些主题的数学可以执行这些转换(显然,你发现的最常见的处理最常见的形状),但这可能对你来说也可能不是,而且它不会那么容易弄清楚如何进行非标准转换。

    如果您只是在寻找一种合乎逻辑的方法,那么我将从这里开始(多年来没有做过数学计算,也没有研究过所链接图形库的内部工作原理):

    1. 选择一个距离,以任何有意义的单位测量,也许是像素。

    2. 识别每个形状中的每个连续边。在每个形状的一个边缘上选择一个任意点(例如,在 (0,0) 表示左上角的平面上,每个形状上最接近 (0,0) 的边缘点),然后在该平面上对齐您的单独形状观点。出于转换的目的,该点将保持静态,所有其他点都将符合它。

    3. 如果您的形状有两条或更多条不同的边,请按周长排序。考虑较短的长度从属于较长的长度。使用与第 2 步类似的过程选择任意点将这两条边连接在一起。

    4. 在您选择的每个点上,以您在步骤 1 中选择的距离为间隔计算边缘周围的点。

    5. (留给读者作为练习)将不同边缘上的点整合在一起并形成目标形状,并根据需要对齐、减少或添加边缘上的点。

    或者,您可以选择任意数量的点而不是任意距离,然后将它们沿着边缘适当地分布在它们适合的任何距离处,然后将这些点整合在一起。

    只是抛出一些想法,我真的不知道问题有多深。

    【讨论】:

      猜你喜欢
      • 2010-12-31
      • 2021-10-08
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 2013-08-05
      • 2015-01-26
      • 1970-01-01
      相关资源
      最近更新 更多