将一个形状变换为另一个形状的算法

时间:2012-11-27 03:00:27

标签: php javascript image-manipulation

我正在尝试将一个“形状”转换为另一个“形状”的算法。两种形状都是任意的,甚至可能也有较小的脱节形状。

我到目前为止的基本思想如下:找到形状的边缘,沿着这些边缘放置点,然后对目标图像做同样的事情,然后将点移动到它们的目标。

以下是插图:

Morph

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

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

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

4 个答案:

答案 0 :(得分:5)

我在JavaScript中找到了a demonstration (using Raphael.js)轮廓变形和补间动画,显示了Raphael.js如何用于将一条曲线变换为另一条曲线。

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

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

答案 1 :(得分:5)

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

首先我们需要弄清楚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中的目的地。

  5. 我们还需要知道每个像素的兄弟姐妹 兄弟姐妹是一个紧挨着另一个像素的像素 要找到它,转到一个给定的像素,从中收集半径为1的所有像素,所有这些像素都是黑色..是像素的兄弟姐妹。当像素行进到目的地时,该信息对于将形状保持为单个单元是必要的。跳过兄弟姐妹会大大加快并简化变形,但没有它们,变形过程中形状可能会变得碎片化。可能想从一个没有兄弟的版本开始,看看情况如何。

    最后我们实现了变形:

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

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

    3. 这将显示你的变形。

答案 2 :(得分:2)

这样做不会很容易,但我可以给你一些起点。如果你想要一个简单的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

希望其中一个有所帮助。

答案 3 :(得分:1)

简短的回答,如果你想要自己动手,这不是一项简单的任务。在这些主题上有大量的数学运算来执行这些非常的变换(最常见的是你会发现最常见的形状,但很明显),但这可能会或可能不会被你访问,并且它不会那么容易弄清楚如何进行非标准转换。

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

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

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

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

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

  5. (作为读者的练习)将您不同边缘上的点整合到目标形状中,根据需要对齐,缩小或添加边缘上的点。

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

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