具体实施方式
下面结合具体实施方式和附图对本发明进行详细描述。
本发明所述的方法主要应用于在将不同类型的字幕对象转换为由二次Bezier线段组成的包括一个或多个封闭轮廓的矢量轮廓信息时,将封闭轮廓转换为多边形的字幕渲染中。
将不同类型的字幕对象转换为由二次Bezier线段组成的包括一个或多个封闭轮廓的矢量轮廓信息可以采用如下方法。
由于字幕对象的类型包括文字字幕、基本图形字幕和复合字幕(包括文字和基本图形的字幕),因此针对不同类型的字幕对象需要进行不同的处理。
如果字幕对象的类型为文字字幕,则可以直接使用操作系统的TrueType字库,无需转换。其方法主要包括以下步骤:
①根据文字字幕对象的字体名称,使用操作系统提供的API(CreateFont)创建逻辑字体对象F;
②使用操作系统提供的API(SelectObject),将逻辑字体对象F设置到操作系统的资源描述表中,并保存操作系统原来的逻辑字体;
③根据当前字符的Unicode编码,使用操作系统提供的API (GetGlyphOutline),从操作系统的当前资源描述表中获取当前字符的矢量轮廓信息在TrueType字库中占用的内存字节数B;
④根据当前字符占用的内存字节数B,分配内存P;
⑤根据当前字符的Unicode编码和占用的内存P,再次使用操作系统提供的API(GetGlyphOutline),从操作系统当前资源描述表中获取当前字符的矢量轮廓信息G,并恢复操作系统原来的逻辑字体。
如果字幕对象的类型为基本图形字幕,则将其转换成由若干条三次贝塞尔线段组成的封闭轮廓的矢量轮廓信息,主要是根据基本图形的几何参数确定每条贝塞尔线段上的控制点坐标,具体包括以下步骤:
①根据基本图形字幕的几何形状,将基本图形字幕划分成多条曲线段,所述的曲线段包括直线段、正玄或余玄曲线段、圆弧段和椭圆弧段;
②根据基本图形字幕的外接矩形、每条曲线段的参数方程计算出每条曲线段转换成三次贝塞尔线段后的起始控制点和结束控制点的坐标;
③对每条三次贝塞尔线段,根据起始控制点和结束控制点的坐标和三次贝塞尔参数方程,分别计算t=1/3和t=2/3处的另外两个控制点的坐标。
以基本图形字幕的几何形状为椭圆形为例,如图1所示。首先,根据椭圆形与其外接矩形的四个交点P100、P103、P106和P109将其分成四条Bezier线段,分别为从P100到P103、从P103到P106、从P106到P109和从P109到P100。从P100到P103的三次Bezier曲线的四个控制点分别为P100、P101、P102和P103,从P103到P106的三次Bezier曲线的四个控制点分别为P103、P104、P105和P106,从P106到P109的三次Bezier曲线的四个控制点分别为P106、P107、P108和P109,从P109到P100的三次Bezier曲线的四个控制点分别为P109、P110、P111和P100。
然后,根据椭圆图元的外接矩形的四个顶点坐标计算出椭圆中心点的坐标(a,b)、横轴半径ra和纵轴半径rb。每条三次贝塞尔线段的各个控制点坐标的计算公式如下:
令PinA=ra*0.55179445,PinB=rb*0.55179445。
P100.x=a, P100.y=b+rb;
P101.x=a+PinA; P101.y=b+rb;
P102.x=a+ra; P102.y=b+PinB;
P103.x=a+ra; P103.y=b;
P104.x=a+ra; P104.y=b-PinB;
P105.x=a+PinA; P105.y=b-rb;
P106.x=a; P106.y=b-rb;
P107.x=a-PinA; P107.y=b-rb;
P108.x=a-ra; P108.y=b-PinB;
P109.x=a-ra; P109.y=b;
P110.x=a-ra; P110.y=b+PinB;
P111.x=a-PinA; P111.y=b+rb。
其中,P100.x表示P100点的横坐标,P100.y表示P100点的纵坐标。本实施方式中,其他类似的表示方式的含义与P100相同。
以基本图形字幕的几何形状为波浪旗飘形为例,如图2所示。首先,根据两条曲线段与两条直线段的四个交点P200、P203、P206和P209将其分成四条曲线段,分别为从P200到P203、从P203到P206、从P206到P209和从P209到P200。将每条曲线段转换成三次贝塞尔曲线后,从P200到P203的三次Bezier线段的四个控制点分别为P200、P201、P202和P203,从P203到P206的三次Bezier线段的四个控制点分别为P203、P204、P205和P206,从P206到P209的三次Bezier线段的四个控制点分别为P206、P207、P208和P209,从P209到P200的三次Bezier线段的四个控制点分别为P209、P210、P211和P200。
已知波浪旗飘形图元的外接矩形的四点坐标,可以计算出该图元外接矩形的宽度和高度,分别为W2和H2。此外,根据已知的调节波浪旗飘图元的水平和垂直幅度的参数fx和fy,可以计算出来P200点的坐标为(a,b),a=fx*W,b=fy*H。
每条三次贝塞尔线段上控制点坐标的计算过程包括以下步骤。
①基于正玄曲线方程,根据P200点坐标计算出P203点坐标。
P203.x=W2;
P203.y=b+b*0.9*sin((W2-a)*2*PI/W2)。
②以P200点为起点,以P203点为终点,根据三次Bezier曲线方程,分别计算t=1/3和t=2/3处的P201点和P202点的坐标。
P201.x=((m1*c2-m2*c1)-(a1*c2-a2*c1)*P200.x-(d1*c2-c1*d2)*P203.x)/(b1*c2-b2*c1)。
P202.x=((m1*b2-m2*b1)-(a1*b2-a2*b1)*P200.x-(d1*b2-d2*b1)*P203.x)/(c1*b2-c2*b1)。
其中,m1=a+(W2-a)/3,m2=a+(W2-a)*2/3;t1=1.0/3,t2=2.0/3;
a1=(1-t1)*(1-t1)*(1-t1);
b1=3*t1*(1-t1)*(1-t1);
c1=3*t1*t1*(1-t1);
d1=t1*t1*t1;
a2=(1-t2)*(1-t2)*(1-t2);
b2=3*t2*(1-t2)*(1-t2);
c2=3*t2*t2*(1-t2);
d2=t2*t2*t2。
P201.y=((n1*c2-n2*c1)-(a1*c2-a2*c1)*P200.y-(d1*c2-c1*d2)*P203.y)/(b1*c2-b2*c1)。
P202.y=((n1*b2-n2*b1)-(a1*b2-a2*b1)*P200.y-(d1*b2-d2*b1)*P203.y)/(c1*b2-c2*b1)。
其中,n1=b-b*0.9*sin((W2-a)*2*PI/(3*W2)),
n2=b-b*0.9*sin((W2-a)*2*PI*2/(3*W2))。
③基于正玄曲线方程,根据P200点坐标计算出P206点坐标。
P206.x=W2-a;
P206.y=H2-b-b*0.9*sin((W2-a)*2*PI/W2)
④计算P209点坐标。
P209.x=0;
P209.y=H2-b
⑤以P206点为起点,以P209点为终点,根据三次Bezier曲线方程,分别计算t=1/3和t=2/3处的P207点和P208点坐标,计算方法与计算P201 点、P202点的坐标相同。
⑥P204点坐标等于P203点坐标,P205点坐标等于P206点坐标,P210点坐标等于P209点坐标,P211点坐标等于P200点坐标。之所以要重复这几个点,是为了使得该字幕对象的封闭矢量轮廓信息中的每条Bezier线段都是三次Bezier曲线。实际上,由控制点P203、P204、P205、P206形成的三次Bezier曲线,以及由控制点P209、P210、P211、P200形成的三次Bezier曲线是一条直线段。
以基本图形字幕的几何形状为心形为例,如图3所示。已知心形图元的外接矩形的四点坐标,可以计算出该图元的宽度和高度,分别为W3和H3。首先将该图元分成8条曲线段,分别为从P300到P303、从P303到P306、从P306到P309、从P309到P312、从P312到P315、从P315到P318、P318到P320,从P320到P300。将每条曲线段转换成三次贝塞尔线段后各个控制点坐标的计算过程包括以下步骤。
①首先根据心形图元的形状特点,计算点P300、P303、P306和P309的坐标。
P300.x=0.73*W3+0.27*W3*cos(A),
P300.y=0.25*H3-0.25*H3*sin(A);
P303.x=0.73*W3+0.27*W3*cos(PI/3+A),
P303.y=0.25*H3-0.25*H3*sin(PI/3+A);
P306.x=0.73*W3+0.27*W3*cos(2*PI/3+A),
P306.y=0.25*H3-0.25*H3*sin(2*PI/3+A);
P309.x=0.73*W3+0.27*W3*cos(PI+A),
P309.y=0.25*H3-0.25*H3*sin(PI+A)。
其中PI和A为常数,PI=3.1415926,A=-0.5535442。
②利用三次Bezier参数方程,以P300点为起点,以P303点为终点,分别计算t=1/3和t=2/3处的P301点和P302点的坐标。三次Bezier曲线的矩阵形式如下:
t∈[0,1]
t∈[0,1]
t∈[0,1]
将上面矩阵展开后,得到:
X(t)=A0+A1*t+A2*t2+A3*t3
Y(t)=B0+B1*t+B2*t2+B3*t3
其中,A0=X0;A1=-3X0+3X1;A2=3X0-6X1+3X2;A3=-X0+3X1-3X2+X3;B0=Y0;B1=-3Y0+3Y1;B2=3Y0-6Y1+3Y2;B3=-Y0+3Y1-3Y2+Y3。
由于P300点和P303点的坐标X0、X3、Y0、Y3已知,P301点的t值为1/3,P302点的t值为2/3,因此可以列出一个如下四元一次方程组:
X1=A0+A1*(1/3)+A2*(1/3)2+A3*(1/3)3
Y1=B0+B1*(1/3)+B2*(1/3)2+B3*(1/3)3
X2=A0+A1*(2/3)+A2*(2/3)2+A3*(2/3)3
Y2=B0+B1*(2/3)+B2*(2/3)2+B3*(2/3)3
解该方程组,即可得到P301和P302点的坐标X1、X2、Y1、Y2的值。
③利用三次Bezier参数方程,以P303点为起点,以P306点为终点,分别计算t=1/3和t=2/3处的P304点和P305点的坐标。方法与第③步中求P301、P302的坐标相同,不再赘述。
④利用三次Bezier参数方程,以P306点为起点,以P309点为终点,分别计算t=1/3和t=2/3处的P307点和P308点的坐标。方法与第③步中求P301、P302的坐标相同,不再赘述。
⑤根据心形图元的左右对称性,可以得到P311、P312、P313、P314、P315、P316、P317和P318的坐标。
⑥P320点的坐标为(W/2,H)。
⑦P323、P324点的坐标等于P300点,P319点的坐标等于P318点,P321、P322点的坐标等于P320点。
最后,得到8条三次贝塞尔线段组成的矢量轮廓信息。这8条三次贝塞尔线段如下:
第一条线段由控制点(P300、P301、P302、P303)形成的三次贝塞尔线段;
第二条线段由控制点(P303、P304、P305、P306)形成的三次贝塞尔线段;
第三条线段由控制点(P306、P307、P308、P309)形成的三次贝塞尔线段;
第四条线段由控制点(P309、P310、P311、P312)形成的三次贝塞尔线段;
第五条线段由控制点(P312、P313、P314、P315)形成的三次贝塞尔线段;
第六条线段由控制点(P315、P316、P317、P318)形成的三次贝塞尔线段;
第七条线段由控制点(P318、P319、P320、P321)形成的三次贝塞尔线段(由于P318、P319的坐标相同,P320、P321的坐标相同,因此这条线段实际上是一条直线段);
第八条线段由控制点(P321、P322、P323、P324)形成的三次贝塞尔线段(由于P321、P322的坐标相同,P323、P324的坐标相同,因此这条线段实际上是一条直线段)。
对于其他类型的基本图形字幕对象,可以按照同样的思想,将其转换为由一次、二次或者三次Bezier线段组成的封闭轮廓。
当字幕对象的类型为复合字幕时,将其转换成矢量轮廓信息的方法包括以下步骤:
①根据复合字幕对象的数据结构,将其拆分为M(M为正整数)个基本字幕对象。基本字幕对象就是指文字字幕对象或者基本图形字幕对象。
②分别使用上述“文字字幕对象”和“基本图形字幕对象”的处理方法得到这M个基本字幕对象的矢量轮廓信息。
③根据M个基本字幕对象的相对空间坐标,将步骤②中得到的M个矢量轮廓信息组合在一起,形成该复合字幕对象的最终矢量轮廓信息。
将字幕对象经过上述转换后,还需要根据字幕对象的旋转、变形参数,将变换后的矢量轮廓信息进行空间几何变换。
假设字幕对象的旋转角度为A,基本字幕对象的控制点个数为n(n为正整数),分别为P[0]至P[n-1],则对一个基本字幕对象进行空间几何变换的过程包括以下步骤。
a.根据基本字幕对象的外接矩形的四个顶点坐标计算基本字幕对象的中心点Q的坐标。
b.按照如下公式修正旋转后的P[i](0≤i≤n,i为正整数)的坐标:
x=P[i].x-Q.x,
y=P[i].y-Q.y,
P[i].x=Q.x+x*cos(A)-y*sin(A),
P[i].y=Q.y+x*sin(A)+y*cos(A);
其中,P[i].x和P[i].y分别为P[i]点横、纵坐标,Q.x和Q.y分别为Q点的横、纵坐标。
在将不同类型的字幕对象转换为由一次、二次或三次Bezier曲线组成的封闭轮廓后,为了使渲染引擎在算法处理上的一致性,降低算法的复杂度,优化算法的效率,还需要将不同次数的Bezier线段统一转换为二次Bezier线段。
将一次Bezier线段转换为二次Bezier线段的原理为:将一次Bezier线段的前后两个控制点R0和R1作为二次Bezier线段的第一和第三个控制点,R0和R1的中点作为二次Bezier线段的第二个控制点。
图4是一次Bezier线段转换为二次贝塞尔线段示意图,4a为转换前的一次Bezier线段,4b为转换后的二次Bezier线段。其中,P40=R40,P42=R41,P41=(R40和R41的中点),即P41.x=(R40.x+R41.x)/2;P41.y =(R40.y+R41.y)/2。
将三次Bezier线段转换为二次Bezier线段的原理为:将一条三次Bezier线段转换成两条二次Bezier线段。
图5中的5a和5b分别是将三次Bezier线段转换为两条二次Bezier线段的两种情况示意图。假设一个三次Bezier线段的控制点分别为R50、R51、R52、R53。Q1是R50和R51的中点,Q2是R52和R53的中点,Q3是R51和R52的中点,Q4是Q1和Q3的中点,Q5是Q2和Q3的中点,Q6是Q4和Q5的中点,Q7是Q4和Q5构成的直线与R0和R1构成直线的交点,Q8是Q4和Q5构成的直线与R52和R53构成直线的交点。
根据R50、R51、R52、R53四点的坐标以及Bezier参数方程计算出Q1、Q2、Q3、Q4、Q5、Q6、Q7、Q8的坐标如下:
Q1.x=(R50.x+R51.x)/2,Q1.y=(R50.y+R51.y)/2;
Q2.x=(R52.x+R53.x)/2,Q2.y=(R52.y+R53.y)/2;
Q3.x=(R51.x+R52.x)/2,Q3.y=(R51.y+R52.y)/2;
Q4.x=(Q1.x+Q3.x)/2,Q4.y=(Q1.y+Q3.y)/2;
Q5.x=(Q2.x+Q3.x)/2,Q5.y=(Q2.y+Q3.y)/2;
Q6.x=(Q4.x+Q5.x)/2,Q6.y=(Q4.y+Q5.y)/2;
Q7.x=(3*Q1.x+3*Q4.x-R0.x-Q6.x)/4,
Q7.y=(3*Q1.y+3*Q4.y-R0.y-Q6.y)/4;
Q8.x=(3*Q2.x+3*Q5.x-R3.x-Q6.x)/4,
Q8.y=(3*Q2.y+3*Q5.y-R3.y-Q6.y)/4。
将原来的三次Bezier线段在Q6点处分成两条二次Bezier线段,一条Bezier线段的三个控制点分别为R50,Q7,Q6,另一条Bezier线段的三个控制点分别为Q6,Q8,R53。
在由二次Bezier曲线组成的封闭轮廓的矢量轮廓信息中,可能存在自相交的二次Bezier线段,即封闭轮廓内含一个或多个闭合环路,如图6、图7和图10所示。为了增强字幕的渲染效果,提高渲染效率,需要对这种情况进行处理,删除或者分割闭合环路。
处理自相交的二次贝塞尔曲线的方法为:首先判断封闭轮廓G中是否存在二次贝塞尔线段自相交的情况,如果存在,则继续判断是相邻二次贝塞尔线段自相交还是非相邻二次贝塞尔线段自相交,如果是相邻二次贝塞尔线段自相交,则将封闭轮廓G中内含的包括相邻二次贝塞尔线段自相交的闭合环路删除;如果是非相邻的二次贝塞尔线段自相交,则将封闭轮廓G和其内含的包括非相邻二次贝塞尔线段自相交的闭合环路分割成多个封闭轮廓。
判断封闭轮廓G中是否存在二次贝塞尔线段自相交的方法为:假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1];依次取出G中每个二次贝塞尔线段B[j],判断B[j]与G中的其它二次贝塞尔线段是否相交,如果相交,则G存在自相交情况;否则,不存在自相交情况。
判断两条二次贝塞尔线段是否相交的方法为:首先计算两条二次贝塞尔线段的外接矩形;然后判断两条二次贝塞尔线段的外接矩形是否存在交集,如果存在,则这两条二次贝塞尔线段相交,如果不存在,则这两条二次贝塞尔线段不相交。
参照图8,计算一条二次贝塞尔线段的外接矩形的方法为:假设二次贝塞尔线段的三个控制点分别为P0、P1和P2,P0点的横坐标为P0.x,纵坐标为P0.y;P1点的横坐标为P1.x,纵坐标为P1.y;P2点的横坐标为P2.x,纵坐标为P2.y;计算由P0、P1和P2构成的三角形的外接矩形T,T即为该二次贝塞尔线段的外接矩形,公式如下:
T.1eft=min(P0.x,P1.x,P2.x),
T.right=max(P0.x,P1.x,P2.x),
T.top=min(P0.y,P1.y,P2.y),
T.bottom=max(P0.y,P1.y,P2.y);
其中,T.1eft表示外接矩形左边框的横坐标,T.right表示外接矩形右边框的横坐标,T.top表示外接矩形上边框的纵坐标,T.bottom表示外接矩形下边框的纵坐标;min函数表示取所有参数中的最小值,max函数表示取所有参数中的最大值。
如果封闭轮廓G中存在二次贝塞尔线段自相交的情况,则判断是相邻二 次贝塞尔线段自相交还是非相邻二次贝塞尔线段自相交的方法为:如果B[j]与相邻线段B[j+1]相交,则是相邻二次贝塞尔线段自相交,否则是非相邻二次贝塞尔线段自相交。
参照图6,如果是相邻二次贝塞尔线段自相交,则将封闭轮廓G中内含的包括自相交的相邻二次贝塞尔线段的闭合环路删除的方法为:
假设G中有M个二次贝塞尔线段,分别是B[0]、B[1]、B[2]至B[M-1],两条自相交的相邻二次贝塞尔线段分别为B[j]和B[j+1];首先计算B[j]和B[j+1]的交点S;然后将B[j]的起始控制点与S相连构成一条新的二次贝塞尔线段B[j′],将S与B[j+1]的结束控制点相连构成一条新的二次贝塞尔线段B[j+1′],B[j′]、B[j+1′]与封闭轮廓G中原来的二次贝塞尔线段B[0]到B[j-1]、B[j+2]到B[M-1]构成了一个新的封闭轮廓G′,令G=G′;最后删除S与B[j]的结束控制点构成的封闭轮廓。图6中(6a)为处理前的封闭轮廓G,(6b)为处理后的封闭轮廓G,(6c)为删除的封闭轮廓。
参照图7,如果是非相邻二次贝塞尔线段自相交,则将封闭轮廓G和其内含的包括自相交的非相邻二次贝塞尔线段的闭合环路分割成多个封闭轮廓的方法为:
假设两条自相交的非相邻二次贝塞尔线段分别为B[j]和B[k],j<k;首先计算B[j]和B[k]的交点S;然后将B[j]的起始控制点与S相连构成一条新的二次贝塞尔线段B[j′],并将S与B[k]的结束控制点相连构成一条新的二次贝塞尔线段B[k′],B[j′]、B[k′]与封闭轮廓G中原来的线段B[0]到B[j-1]、B[k+1]到B[M-1]构成了一个新的封闭轮廓G′,令G=G′;最后将S与B[j]的结束控制点和B[k]的起始控制点相连,形成了两条新的二次贝塞尔线段,将这两条新的二次贝塞尔线段与B[j+1]到B[k-1]中所有的二次贝塞尔线段构成了一个新的封闭轮廓G",将G"加入到字幕对象矢量轮廓信息表。
计算字幕对象矢量轮廓信息中两条二次Bezier曲线交点的方法,从理论上来说,可以根据两条二次Bezier曲线的联合参数方程计算。但这种方法是不可取的,因为不但计算量巨大,而且都是基于浮点数的运算,算法的效率 会比较低。因此,本实施方式采用“二分迭代法”。该方法的核心思想为:如果两条二次Bezier线段相交,那么根据中点将这两条二次Bezier线段分别分成两条二次Bezier线段,得到4条二次Bezier线段;然后再按照同样的方法,处理这4条线段,直到最终每条线段的起始控制点和结束控制点的空间直线距离小于某一个值(通常情况下,这个值为
),最终可以归结为计算两条直线段的交点。该方法具体包括以下步骤:
(I)假设两条相交的二次贝塞尔线段分别为B[j]和B[k],将B[j]和B[k]分别进行如下处理:
①计算二次贝塞尔线段的起始控制点与结束控制点之间的空间直线距离L, 其中,x0、y0为起始控制点横、纵坐标,x1和y1为结束控制点横、纵坐标;
②判断L是否大于M,如果大于,则计算二次贝塞尔线段的中点,将二次贝塞尔线段在中点处划分成两条二次贝塞尔线段,所述的
③重复步骤①至步骤②,直到划分后的每条二次贝塞尔线段的起始控制点与结束控制点之间的空间直线距离L小于或等于M;
(II)将B[j]和B[k]经过步骤(I)处理后,假设最终相交的两条二次贝塞尔线段分别为B[j′]和B[k′],计算B[j′]的起始控制点和结束控制点构成的直线与B[k′]的起始控制点和结束控制点构成的直线的交点。
本实施方式中,计算二次贝塞尔线段的中点的方法为:假设二次贝塞尔线段的三个控制点分别为P0、P1和P2,函数表达式为
B(t)=(1-t)2P0+2t(1-t)2P1+t2P2 t∈[0,1];
令t=0.5,计算二次贝塞尔曲线方程上的一点,该点便是二次贝塞尔线段的中点,其坐标的计算公式为B=(P0+2*P1+P2)/4。
如图9所示,R1是直线(P0,P1)的中点,R2是直线(P1,P2)的中点,R3是直线(P2,P0)的中点,Q是直线(R1,R2)与直线(R3,P1)的交点。Q点便是二次Bezier曲线(P0,P1,P2)的中点。
R1点横坐标R1.x=(P0.x+P1.x)/2,R1点纵坐标R1.y=(P0.y+P1.y)/2;R2点横坐标R2.x=(P1.x+P2.x)/2,R2点纵坐标R2.y=(P1.y+P2.y)/2。其中,P0.x、P0.y为P0点横、纵坐标;P1.x、P1.y为P1点横、纵坐标;P2.x、 P2.y为P2点横、纵坐标。
Q点的横坐标Q.x=(R1.x+R2.x)/2=(P0.x+2*P1.x+P2.x)/4,Q点的纵坐标Q.y=(R1.y+R2.y)/2=(P0.y+2*P1.y+P2.y)/4。
当封闭轮廓G中非相邻二次贝塞尔线段自相交的情况处理后,分割后的封闭轮廓仍有可能存在自相交的情况。如图10所示,(10a)所示的封闭轮廓经过处理后,将其分割成(10b)、(10c)和(10d)所示的封闭轮廓,其中(10c)所示的封闭轮廓仍然存在自相交的情况,因此需要重复上述步骤对(10c)所示的封闭轮廓进行再处理,直到分割后的所有封闭轮廓中没有自相交的情况发生。(10c)所示的封闭轮廓经过再处理后,分割成(10c1)和(10c2)两个封闭轮廓。
在字幕对象的矢量轮廓信息中,不同的封闭轮廓之间可能存在相交的情况,为了有利于字幕对象的后续渲染,增强字幕对象的最终渲染效果,需要对这种情况进行处理,在交点处将一条二次Bezier线段分割成多条二次Bezier线段。
图11出示了本发明所述的根据交点分割字幕对象矢量轮廓中二次贝塞尔曲线的方法,包括以下步骤:
(1)计算字幕对象矢量轮廓中所有的二次贝塞尔线段与其他二次贝塞尔线段的交点;
(2)在每条二次贝塞尔线段的交点处,将该二次贝塞尔线段分割;
假设一条二次贝塞尔线段B的三个控制点分别是P[0]、P[1]、P[2],在B上有n个交点,分别为S[0]到S[n-1],每个交点对应的贝塞尔参数方程中的t值分别是S[0].t到S[n-1].t;
首先在S[0]点处将线段B分成两条线段B1和B1′;
B1的三个控制点分别为P[0]、Q[0]、S[0],P[0]和S[0]的坐标已知,Q[0]的坐标为:
Q[0].x=(1-t)*P[0].x+t*P[1].x,
Q[0].y=(1-t)*P[0].y+t*P[1].y;
B1′的三个控制点分别为S[0]、R[0]、P[2],S[0]和P[2]的坐标已知, R[0]的坐标为:
R[0].x=(1-t)*P[1].x+t*P[2].x,
R[0].y=(1-t)*P[1].y+t*P[2].y;
其中,Q[0].x表示Q[0]点的横坐标,Q[0].y表示Q[0]点的纵坐标,R[0].x表示R[0]点横坐标,R[0].y表示R[0]点纵坐标;t=(S[0].t-P[0].t)/(P[2].t-P[0].t),P[0].t为P[0]点对应的贝塞尔参数方程中的t值,P[2].t为P[2]点对应的贝塞尔方程中的t值;
然后在S[1]点处将线段B1′分成两条线段B2和B2′,方法与步骤①相同;
以此类推,最后在S[n-1]点处将线段Bn-1′分成两条线段Bn和Bn′;最终得到N+1条分割后的线段。
图12出示了计算字幕对象矢量轮廓中所有的二次贝塞尔线段与其他二次贝塞尔线段的交点的方法流程,包括以下步骤:
①遍历字幕对象矢量轮廓中所有的封闭轮廓,取出一个与已取不同的封闭轮廓G[i];
②遍历G[i]中所有的二次Bezier线段,取出一个与已取不同的二次贝塞尔线段B[j];
③遍历该字幕对象矢量轮廓中除B[j]之外的所有二次贝塞尔线段,取出一个与已取不同的二次贝塞尔线段B[k];
④判断B[j]与B[k]的外接矩形是否存在交集,如果不存在,则转至步骤③;如果存在,则计算B[j]与B[k]之间的交点。
计算B[j]与B[k]之间的交点与上述计算自相交的二次贝塞尔线段的交点的原理相同,此处不再赘述。
图13出示了根据二次贝塞尔线段的内外边属性对字幕对象矢量轮廓进行规并整理的方法流程,主要包括以下步骤。
(1)确定字幕对象所有封闭轮廓中每条二次贝塞尔线段的内外边属性。
确定一条二次贝塞尔线段的内边/外边属性,只需要确定该条二次贝塞尔线段上的任意一个点在整个字幕对象的矢量轮廓信息中是内点还是外点即 可,通常情况下可以使用该条线段的中点。如果该线段的中点是内点,则该条线段为内边;如果是外点,则该条线段为外边。
判断二次贝塞尔线段的中点在字幕对象所有封闭轮廓中是内点还是外点的方法包括以下步骤。
假设二次贝塞尔线段为B,B的三个控制点分别为P[0]、P[1]、P[2],中点为Q。
①确定B的方向值d:如果P[2].y>P[0].y,则d=1;如果P[2].y<P[0].y,则d=-1;如果P[2].y=P[0].y,则d=0。其中,P[0].y和P[2].y分别表示P[0]和P[2]的纵坐标。
②计算B的中点Q坐标。
③判断abs(P[2].y-P[0].y)是否大于abs(P[2].x-P[0].x),如是,则以Q点为起点,沿水平方向向右作一射线H;如否,则以Q点为起点沿竖直方向向上作一射线H。本实施方式中,假设沿水平方向向右作一射线H,如图14所示。计算字幕对象所有封闭轮廓中与H相交的除B之外的所有二次贝塞尔线段,假设有M条二次贝塞尔线段与H相交,分别为B[0]、B[1]至B[M-1]。其中,P[0].x和P[2].x分别表示P[0]和P[2]的横坐标,abs函数为取绝对值函数。
④分别计算B[i]的方向值d[i],方法与步骤①中计算d值的方法相同。其中,i=0、1、......、M-1。
⑤计算d[i]的和值d′:d′=d[0]+d[1]+......+d[M-1]。
⑥根据d和d′计算B的内外边属性值a:
a=1-abs(SIGN(d+d′)*SIGN(d′))。其中,SIGN(x)定义为(x==0)?0:((x>0)?1:-1)),即如果x=0,则SIGN(x)=0;如果x>0,则SIGN(x)=1;如果x<0,则SIGN(x)=-1。
如果a=0,则B为内边;如果a=1,则B为外边。
当确定了一个封闭轮廓中的一条二次贝塞尔线段的内外边属性后,则该封闭轮廓该条二次贝塞尔线段之后的二次贝塞尔线段的内外边属性与其相同,直到遇到一个交点为止。
利用上述方法可以确定所有封闭轮廓中包含的每条二次贝塞尔线段的内外边属性。
(2)将属性为内边的二次贝塞尔线段删除。
当确定了矢量轮廓信息中所有的封闭轮廓中包含的每条二次贝塞尔线段的内外边属性后,删除所有标记为内边的二次贝塞尔线段的方法为:在每条二次贝塞尔线段中,都有一个边界属性变量表示内边/外边属性,遍历矢量轮廓信息中所有的二次贝塞尔线段,将边界属性为内边的二次贝塞尔线段从封闭轮廓中删除即可。
(3)根据交点重构字幕对象的封闭轮廓。
删除属性为内边的二次贝塞尔线段后,需要对所有的封闭轮廓重新进行规并,即根据交点将二次贝塞尔线段连接起来,重新构建每个封闭轮廓。重新构建的封闭轮廓一定是互为不相交的封闭轮廓。
规并一个字幕对象的具体方法包括以下步骤:
a.从所有封闭轮廓中取出一个与已取不同的封闭轮廓G1;
b.判断G1的最后一条二次贝塞尔线段的结束点坐标与第一条二次贝塞尔线段的起始点坐标的差值是否小于等于阀值T,通常T取0.00001,如是,则G1不需要处理,重复步骤a至步骤b,直到所有的封闭轮廓被处理完毕;
c.取出与G1相邻的下一个封闭轮廓G2;
d.判断G1的曲线尾与G2的曲线头或者G1的曲线头与G2的曲线尾是否重合,即判断G1的最后一条二次贝塞尔线段的结束点坐标与G2的第一条二次贝塞尔线段的起始点坐标的差值或者G1的第一条二次贝塞尔线段的起始点坐标与G2的最后一条二次贝塞尔线段的结束点坐标的差值是否小于等于阀值T,如是,则将G1、G2合并,并从矢量轮廓中删除G2;
e.取出与G2相邻的下一个封闭轮廓G2′,令G2=G2′,重复步骤d,直到G2为最后一个封闭轮廓或者G2与G1相等;
f.重复步骤a至步骤e,直到所有的封闭轮廓被处理完毕。
上述过程用伪代码描述如下:
G1=矢量轮廓中第一个封闭轮廓;
while(G1!=NULL)//遍历矢量轮廓中所有的封闭轮廓
{
while(G1需要重新处理)
{
G2=G1.Next;//G2是与G1相邻的下一个封闭轮廓
while(G2!=NULL&&G2!=G1)
{
if(G2需要重新处理)
{
if(G1的曲线尾与G2的曲线头重合)
{
//将G1和G2首尾相连
G1.Tail.Next=G2.Head;
G1.Head.Prev=G2.Tail;
G2.Tail.Next=G1.Head;
G2.Head.Prev=G1.Tail;
G1.Tai1=G2.Tail;
G′=G2;
G2=G2.Prev;
从封闭轮廓链表中删除G′;
}
else if(G1的曲线头与G2的曲线尾重合)
{
//将G1和G2首尾相连
G2.Tail.Next=G1.Head;
G2.Head.Prev=G1.Tail;
G1.Tail.Next=G2.Head;
G1.Head.Prev=G2.Tai1;
G1.Head=G2.Head;
G′=G2;
G2=G2.Prev;
从封闭轮廓链表中删除G′;
}
}
G2=G2.Next;
}
}
G1=G1.Next;
}
(4)计算步骤(3)中获得的所有封闭轮廓以及所有封闭轮廓中每条二次贝塞尔线段的外接矩形,方法同上,此处不再赘述。
(5)标记步骤(3)中获得的所有封闭轮廓的方向,包括顺时针方向和逆时针方向。顺时针方向标记为1,逆时针标记为-1。判断一条封闭曲线G的方向,只需要取出G中任意一条二次贝塞尔线段,判断其方向即可。具体处理步骤如下:
①从封闭轮廓G中任取一条二次贝塞尔线段为B,假设B的三个控制点分别为P[0]、P[1]、P[2],中点为Q;
②确定B的方向值d:如果P[2].y>P[0].y,则d=1;如果P[2].y<P[0].y,则d=-1;如果P[2].y=P[0].y,则d=0;
③计算B的中点Q;
④判断abs(P[2].y-P[0].y)是否大于abs(P[2].x-P[0].x),如是,则以Q点为起点,沿水平方向作一射线H;如否,则以Q点为起点沿竖直方向作一射线H;计算字幕对象所有封闭轮廓中与H相交的除B之外的所有二次贝塞尔线段,假设有M条二次贝塞尔线段与H相交,分别为B[0]、B[1]至B[M-1];
⑤分别计算B[i]的方向值d[i],方法与步骤①中计算d值的方法相同;其中,i=0、1、......、M-1;
⑥计算d[i]的和值d′:d′=d[0]+d[1]+......+d[M-1];
⑦计算B的方向属性b的值,b=d*(1-2*abs(d′));如果b>0,则封闭轮廓G为顺时针方向,否则为逆时针方向。
字幕对象的矢量轮廓信息经过上述变换后,还需要将由二次贝塞尔线段组成的封闭轮廓转换成多边形,即将每条二次贝塞尔线段离散化为直线段。其核心思想包含了“t值的自适应步长选取”、“离散”、“化直”和“浮点坐标整数化”四个方面。
根据二次贝塞尔曲线参数方程,对t值从0到1每次步进一个数值,根据t值计算出对应的二次贝塞尔曲线上的点,假设相邻两个t值计算出来的 点为Q0和Q1,如果Q0和Q1的空间直线距离大于
,则在Q0的t值和Q1的t值之间再次选择一个t值,直到每两个t值对应的二次贝塞尔曲线上的点Q0和Q1的空间直线距离小于等于
为止。这时Q0和Q1构成的直线就是离散化后的一条直线段,最后将每个点的坐标放大M倍,使原来的浮点数坐标变换为整数型坐标。
之所以将离散化后的每条直线段的空间距离限制在
,主要的思想是使得离散化后的每条直线段的起点和终点的水平距离和垂直距离都小于等于
也就是使一条直线段最多经过
个像素。这样就可以保证字幕渲染的精度。
图15出示了本发明所述的将字幕对象矢量轮廓离散化为直线段的方法流程,主要包括以下步骤。
(1)遍历字幕对象的矢量轮廓,取出一个与已取不同的封闭二次贝塞尔曲线G[i],假设字幕对象的矢量轮廓包括N个封闭二次贝塞尔曲线,则i∈[0,N-1],N和i均为正整数。
(2)遍历封闭二次贝塞尔曲线G[i],取出一条与已取不同的二次贝塞尔线段B[j],假设G[i]中包含M个二次贝塞尔线段,则j∈[0,M-1],j为正整数。
(3)将B[j]离散化为直线段,参照图16,具体的实现过程如下:
假设B[j]的三个控制点分别为P[0]、P[1]和P[2];P[0]为起始控制点,P[1]为中间控制点,P[2]为终止控制点。
首先,以P[0]点为起点,计算B[j]离散化后的第一条直线段L[j][0]。
①设置t的初始值,t=P[0].t+L;其中,L为常数,0<L<1(本实施例中L=0.0625);P[0].t为P[0]点对应的二次贝塞尔曲线方程中的t值,P[0].t=0。
②根据二次贝塞尔曲线方程计算t值对应的二次贝塞尔曲线上点Q[0]的坐标。
③计算P[0]点和Q[0]点之间的空间直线距离d, 其中,x0、y0是P[0]的坐标,x1、y1是Q[0]的坐标。
④判断 是否成立,如果成立,则令t=(P[0].t+Q[0].t)/2, 其中,Q[0].t为Q[0]点对应二次贝塞尔曲线方程中的t值;重复步骤②至步骤④,直到 最终的Q[0]点与P[0]点构成的直线便是第一条离散化后的直线L[j][0]。
然后,以Q[0]点为起点,采用与计算B[j]离散化后的第一条直线段相同的方法计算第二条直线段L[j][1];
以此类推,直到处理到B[j]的结束控制点P[2]为止,获得K条直线段L[j][0]至L[j][K-1];
(4)重复步骤(2)至步骤(3),直到G[i]中所有的二次贝塞尔线段处理完毕;
(5)重复步骤(1)至步骤(4)直到字幕对象的矢量轮廓中所有的封闭曲线处理完毕。
将字幕对象中由二次贝塞尔线段组成的封闭轮廓转换成多边形后,为了字幕的后续渲染,还需要给多边形加内边和外边。加边前,首先要计算多边形每条边的如下属性:每条边的角度值a1、a2、a3以及每条边的加边矢量dx、dy的值。
a1表示多边形的一条边与水平向右方向的夹角,a2表示一条边的延长线和与其相邻的下一条边的夹角,a3表示一条边的延长线与下一条边的夹角的角平分线与水平向右方向的夹角,三者的关系如图18所示。dx表示加边时一条边的起始点移动的水平矢量;dy表示加边时一条边的起始点移动的竖直矢量。
一条边的a1=atan((y1-y0)/(x1-x0)),其中,(x0,y0)为该条边的起始点坐标,(x1,y1)为该条边的结束点坐标,atan为反正切函数。
a2的值等于相邻两条边的a1值的差值。
a3=a1-a2/2。
dx=Cos(a3)÷Sin(a2/2)。
dy=Sin(a3)÷Sin(a2/2)。
其中Sin为正玄函数,Cos为余玄函数。
在一个字幕对象的矢量轮廓中,既有顺时针方向的多边形,又有逆时针 方向的多边形,在计算每条边的角度a1、a2、a3和加边矢量dx、dy时都是根据多边形的方向进行的。另外,在字幕对象的渲染中,可以对多边形加不同类型的边,例如尖角边、圆角边、方角边等。在加圆角边和方角边,需要在原来多边形的顶点处增加一些顶点。如图19所示,其中19a为加尖角边示意图;19b为加方角边示意图,此时需要增加一个顶点;19c为加圆角边示意图,此时需要增加多个顶点。
由于上述两个原因,需要根据原来的多边形矢量重新创建出不同的多边形矢量。创建出加内边或外边的多边形矢量轮廓的核心思想是:将原来的多边形轮廓中的封闭多边形逐个拷贝,同时根据加内边还是加外边,以及当前多边形的顺时针/逆时针方向,重新对其中每条边的a1和a2值进行修正;然后根据加边的类型(尖角边、圆角边、方角边等)对多边形的顶点进行处理,加尖角边时不需要增加顶点,加方角边时需要增加一个顶点,加圆角边时则需要根据顶点的角度增加足够多的点,以保证圆角边的平滑。
图17出示了本发明所述的将字幕对象的矢量轮廓中的多边形加内外边的具体方法流程,包括以下步骤。
(1)计算矢量轮廓信息中所有多边形的每条边的角度值a1、a2、a3以及每条边的加边矢量dx、dy的值。
(2)遍历矢量轮廓信息中的多边形,取出一个与已取不同的多边形Q[i];
(3)复制Q[i],得到Q′[i];
(4)对于加外边的情况,如果Q′[i]的方向为逆时针,则取出其中的每条边L[j],按照如下公式修正每条边的a1和a2的值:
L[j].a1=L[j].a1+∏,L[j].a2=2∏-L[j].a2,其中∏=180度;
如果Q′[i]的方向为顺时针,则不需要做任何处理。
对于加内边的情况,如果Q′[i]的方向为顺时针,则取出其中的每条边L[j],按照如下公式修正每条边的a1和a2的值:
L[j].a1=L[j].a1+∏,L[j].a2=2∏-L[j].a2;
如果Q′[i]的方向为逆时针,则不需要做任何处理。
(5)确定加边类型;
如果加尖角边,则转至步骤(6);
如果加方角边,假设有三个连续的顶点P[0]、P[1]、P[2],需要在原来 的顶点为P[1]处增加一个新的顶点为P′;令P′的x坐标、y坐标、a1、a2、a3、dx、dy的初始值等于P[1]中的相应值,然后按照如下公式重新修正P[1]的各个属性值:
P[1].a1=P[0].a1+P′.a2/2;
P[1].a2=P[1].a1-P[0].a1;
P[1].a3=P[0].a1+P[1].a2/2;
P[1].dx=Cos(P[1].a3)÷Sin(P[1].a2/2);
P[1].dy=Sin(P[1].a3)÷Sin(P[1].a2/2)。
如果加圆角边,首先按照加方角边的方法,在顶点P[1]处增加一个新的顶点为P′,修正P[1]的各个属性值;然后判断修正后的P[1].a2是否小于∏/16,如果不小于,则重复上述步骤,继续在P[1]处增加一个新的顶点,直到P[1].a2<∏/16;
(6)重复步骤(1)至步骤(5),直到处理完矢量轮廓信息中所有的多边形。此时可以得到两个新的多边形矢量轮廓G1和G2,其中G1将用在加内边的后续处理中,G2将用在加外边的后续处理中。由于G1、G2与原来的矢量相比增加了一些顶点,所以需要重新计算G1和G2的外接矩形。
本发明所述的方法并不限于上述具体实施方式,本领域技术人员根据本发明的技术方案得出其他的实施方式,同样属于本发明的技术创新范围。