如何实现photoshop的套索功能

 


最近没事在研究PS中一些我比较感兴趣的功能的实现方法,上一次实现了套索的蚂蚁线功能,效果还行。此次就来看看套索自己是如何实现的。算法

整体来讲要实现这个功能主要包括如下几个方面:一、套索也即复杂多边形的内外部识别;二、生成bitmap(相似于GDI中的region(区域));三、根据bitmap转换成套索;四、bitmap布尔操做。dom


---原理、实现---spa

一、套索也即复杂多边形的内外部识别3d

如何识别一个复杂多边形的内部区域,有两种经常使用的方法:一、奇偶规则(odd-even rule) 二、非零环绕数规则(nonzero winding-number rule)。blog

PS中使用的是非零环绕数规则,这个网上资料不少,在这简单说一下规则:首先假定多边形的边是有方向的:好比规定顺时针是正方向,逆时针是负方向。这时判断一个点是否在多边形内,能够从这一点向多边形外发射一条直线,直线每通过一条边根据此边是正方向仍是负方向分别+1和-1,最后统计若是非零则此点在多边形内,不然在外。为了方便计算通常引一条与X轴平行的线进行计算,这个方法主要的麻烦就在射线与边线以及边线与边线之间的交点计算,由于求交点是判断线段方向的前提,从图形学上来讲计算线段的相交性及交点都是比较麻烦的事。ip

有没有办法能够简化这些计算呢?上面的计算之因此麻烦是由于是从通常图形学角度来看的——线段是无限连续的,只能经过线段总体判断方向;若是只从计算机图形学的角度看——线段被光栅化、再也不是连续的、最小单位是像素、线段能够用连续的像素点表示——这个线段能够被离散化的特性就是简化计算的关键——判断方向不须要计算线段交点,只经过相邻点的坐标值比较便可判断。it

具体方法就是以像素为单位,沿着绘制多边形边的顺序,对每一个通过的坐标点维护一个值,顺时针移动时(比较Y值便可,比上一个点Y值大的表示顺时针)+1,逆时针移动-1,与X轴平行的点设为0,而后经过扫描这个结构(在此是一个二维表),就能够肯定多边形的内外部区域,生成bitmap。io


二、生成bitmap(相似于GDI中的region(区域))asm

相似边界标志算法,用平行于X轴的扫描线自左向右扫描上面生成的二维表结构,累加扫描通过的像素对应的值,不为0的即为内部点,填充到bitmap(位图)。原理


三、根据bitmap转换成套索

自上向下、从左到右两个方向扫描bitmap,记录轮廓线。


四、bitmap布尔操做

与、或、非、异或、减 (相似GDI里ROP码(光栅操做))

具体看dome和代码

 

效果图: 图1 原始线段

           图2 边线赋值、区份内外

           图3 新边缘

                                               

                        图1                                                                         图2                                                                        图3


---存在问题---

前面说了线段能够被离散化的特性是简化计算的关键,但代价是引入了交点计算偏差,从理论上说两方向相反非平衡的线段相交必有一个交点(见图4),根据非零环绕规则这个点的环绕数为0(1+-1=0),是一个外部的不该该显示的点。在用像素模拟线段交点时,根据的是像素是否重叠来判断交点的,但在有的状况下两条线段会出现相交而没有像素重叠的状况(见图5),这样简化方法没法断定交点,对此只能看成相邻的方向相反的像素来处理,本应环绕数为0而断开的位置,会有1个或几个(根据斜率)像素继续存在,会形成本不应联通的位置联通,同时用户使用此功能时也可能产生混乱。

                     

                   图4                                                               图5

---解决办法---

解决办法很简单就是不理它、无视它、塞到桌子下面看成这个世界依然完美,由于photoshop就是这么干的(有没有"说的如此有道理我居然无言以对"的感受)?嗯~试着猜一下PS容许这样干的理由:一、偏差影响范围有限,只在交点出现而且只影响周围有限几个像素;二、这个功能自己不须要那么精确。


---一点感想---

想了不少办法也作不到与ps的bitmap轮廓线彻底相同,不过各有优劣,ps大法虽好,这个细节作的也并不是完美^^,不同就不同吧。

相关算法找准关键字——“非零环绕数规则“、“多边形填充中的边界标志算法”——网上搜一搜都有。

 

---代码及程序(masm32)---

http://files.cnblogs.com/hhh2000/nonzero.zip

相关文章
相关标签/搜索