Série de algoritmos 12: Algoritmo de preenchimento de área poligonal - vários algoritmos de preenchimento de marca de borda

Quatro, algoritmo de preenchimento de limite

        No plano de exibição raster, o polígono é fechado. É uma área fechada delimitada por uma determinada cor de borda. O preenchimento é feito linha a linha, ou seja, a linha de varredura é usada para cruzar o polígono linha a linha e preencher os pares de interseções. O algoritmo de preenchimento de marca de limite usa o limite ou cor de limite como a marca para preencher o processamento de linha. Para ser preciso, o algoritmo de preenchimento de limite não se refere a um algoritmo de preenchimento específico, mas um termo geral para um tipo de algoritmo de preenchimento que usa a ideia de continuidade de linha de varredura. Existem muitos tipos de algoritmos e este artigo apresentará alguns.

        Primeiro, introduza um algoritmo de preenchimento de borda com centro de borda. A ideia básica desse algoritmo de marcação de limite é: Para a interseção (xi , yi) de cada linha de varredura e cada lado do polígono , a intersecção à direita da interseção da linha de varredura Todos os pixels são complementados e cada lado do polígono é processado sucessivamente até que o preenchimento final seja concluído. Aqui nós introduzimos a definição complementada é assumido que a cor de um ponto M , então o ponto de cor resultante é complementado M '= A - M , A é um número muito grande, pelo menos melhor do que um grande valor de cor legal . De acordo com a definição de complemento, se um número par de operações de complemento for executado no valor de cor de uma determinada área do bitmap raster que foi marcada como M , a cor da área permanece inalterada; enquanto um número ímpar de operações de complemento é executado, a cor da área torna-se M “ A cor. O algoritmo pode ser simplesmente descrito em duas etapas:

 

1 , a cor de fundo da janela de desenho é definida como cor M ' ;

2. Para cada lado não horizontal do polígono, calcule o resto à direita de cada pixel do lado;

 

O processo de processamento do algoritmo é mostrado na Figura ( 12 ). O lado esquerdo é a forma do polígono, e o lado direito é a cor da área preenchida após o processamento de cada aresta. A cor de fundo inicial é M ' . Após o processamento, a área que precisa ser preenchida é Após o número ímpar de complementos, a cor final é o valor correto M a ser preenchido , e a área não preenchida é complementada por vezes, e ainda é a cor de fundo M ' :

Figura ( 12 ) Processo de processamento do algoritmo de preenchimento de borda

 

        Algoritmo é muito simples, para bitmap visualização raster, nós ainda usamos o método anteriormente utilizado, indica uma área do mapa raster bit usando matriz digitais, cada posição da matriz representa um pixel, com 0 - . 9 representam o valor da cor. Este algoritmo exemplar 9 indica o valor máximo A , 0 indica uma região inválida, o valor da cor é válido . 1 - . 8 .

87  void EdgeCenterMarkFill ( const Polygon & py , int color )

88  {

89      std :: vector < EDGE3 > et ;

90 

91      InitScanLineEdgesTable ( et , py ); // Inicializar a tabela de borda

92 

93      FillBackground ( A - color ); // Complementa a cor de fundo de toda a área preenchida

94      for_each ( et . Begin (), et . End (), EdgeScanMarkColor ); // Processa cada borda por vez

95  }

76  void EdgeScanMarkColor ( EDGE3 e e )

77  {

78      para ( int y = e . Ymax ; y > = e . Ymin ; y -)

79      {

80          int x = ROUND_INT ( e . Xi );

81          ComplementScanLineColor ( x , MAX_X_CORD , y );

82 

83          e . xi - = e . dx ;

84      }

85  }

这个算法非常简单,所有的函数实现也很简单,InitScanLineEdgesTable()函数前面已经介绍过,FillBackground()函数将填充背景初始化为要填充颜色的取补颜色,EdgeScanMarkColor()函数负责对每条非水平边进行处理,逐条扫描线进行颜色取补,ComplementScanLineColor()函数负责对y扫描线上[x1, x2]区间的点的颜色值取补。

        以上以边为中心的填充算法的优点是简单,缺点是对于复杂多边形,每一象素可能被访问多次(多次取补),效率不高。考虑对此算法改进,人们提出了栅栏填充算法。栅栏填充算法的基本思想是:经过多边形的某个顶点,在多边形内部建立一个与扫描线垂直的“栅栏”,当扫描线与多边形边有交点,就将交点与栅栏之间的象素取补。若交点位于栅栏左边,则将交点之右,栅栏之左的所有象素取补;若交点位于栅栏右边,则将栅栏之右,交点之左的象素取补。

        仍以图(12)所示的多边形为例,假设经过P4点建立一条栅栏,则改进的栅栏填充算法处理过程就如图(13)所示:

图(13)栅栏填充算法的处理过程

 

栅栏填充算法的实现和以边为中心的边缘填充算法类似,只是对每条边的扫描线取补处理的范围控制有区别,算法需要指定一个“栅栏”:

115 void EdgeFenceMarkFill(const Polygon& py, int fence, int color)

116 {

117     std::vector<EDGE3> et;

118 

119     InitScanLineEdgesTable(et, py);//初始化边表

120 

121     FillBackground(A - color); //对整个填充区域背景颜色取补

122     for_each(et.begin(), et.end(),

123         std::bind2nd(std::ptr_fun(FenceScanMarkColor), fence));//依次处理每一条边

124 }

 97 void FenceScanMarkColor(EDGE3 e, int fence)

 98 {

 99     for(int y = e.ymax; y >= e.ymin; y--)

100     {

101         int x = ROUND_INT(e.xi);

102         if(x > fence)

103         {

104             ComplementScanLineColor(fence, x, y);

105         }

106         else

107         {

108             ComplementScanLineColor(x, fence - 1, y);

109         }

110 

111         e.xi -= e.dx;

112     }

113 }

 

注意FenceScanMarkColor()函数和EdgeScanMarkColor()函数的区别,就是这点区别使得栅栏填充算法主动减少了很多像素被访问的次数,而多边形之外的像素也不会被多余处理,效率提高了不少。

        栅栏填充算法只是减少了被重复访问的象素的数目,但仍有一些象素会被重复访问。从图(13)中很容易看出这一点。下面介绍的边标志算法利用扫描线的连贯性,对每个像素只访问一次即可完成多边形区域的填充。边标志算法的思想是设置一个标志,沿着扫描线从左到右访问多边形所在区域的像素的时候,用这个标志标识是否扫描到了多边形的边界。如果碰到边界(边界用特殊的颜色标识),则改变标识状态,接下来根据标识状态决定扫描到的像素点是否要填充成指定颜色。

        在实施边标志填充算法通常先求出多边形所在图像区域的最小包围盒,以便缩小扫描范围,加快填充速度。完整的填充算法如下:

 5 void EdgeMarkFill(int xmin, int xmax, int ymin, int ymax,

 6                   int boundarycolor, int color)

 7 {

 8     int flag = -1;

 9     for(int y = ymin; y <= ymax; y++)

10     {

11         flag = -1;

12         for(int x = xmin; x <= xmax; x++)

13         {

14             if(GetPixelColor(x, y) == boundarycolor)

15             {

16                 flag = -flag;

17             }

18             if(flag == 1)

19             {

20                 SetPixelColor(x, y, color);

21             }

22         }

23     }

24 }

可以看到该算法思想简单,实现容易。算法既不需要初始化边表、求交点、交点排序等额外操作,也不需要使用链表、堆栈等数据结构。不过,边标志算法虽然简单,但是使用时对边界的处理要格外小心,否则很容易出错。比如上下顶点之类的局部极值点,会造成标志的奇偶计数不匹配,填充时会出现“抽丝”现象,也就是扫描线上不该填充的区段被填上色,而应该填充的区段却没有填上色。再比如边界像素点重复的问题,多边形的边界是利用直线的生成算法依次画出的,当扫描线遇到斜率小于1的边时,容易产生重复的边界点,如图(14)所示,引起标志的无序改变,从而造成填充错误。

 

图(14)斜率小于1的边的光栅扫描转换问题

         至此,本文完整介绍了8中常见的多边形区域填充算法,拖拖沓沓写了一个多月,总算完成了,居然有将近30页,总计13000多字(24000多可见字符),毕业以后就没写过这么长的文档了,感慨一下。本文给出的示例代码都是为了演示,基于可读性而设计的,大家在实际的图形处理软件中看到的算法实现可能和本文的示例算法“大相径庭”,但是基本原理都是一样的。

 

 

 

 

参考资料:

 

【1】计算几何:算法设计与分析 周培德  清华大学出版社 2005年

【2】计算几何:算法与应用 德贝尔赫(邓俊辉译)  清华大学出版社 2005年

【3】计算机图形学 孙家广、杨常贵 清华大学出版社 1995年

 

 

Acho que você gosta

Origin blog.csdn.net/orbit/article/details/7467543
Recomendado
Clasificación