1 PUCPR- Pontifícia Universidade Católica Do Paraná PPGIA- Programa de Pós-Graduação Em Informática Aplicada PROF. DR. JACQUES FACON ALGORITMO DE AFINAMENTO EM DOIS SUBCICLOS PARA IMPLEMENTAÇÕES PARALELAS EM MÁQUINAS SIMD Resumo: Um novo algoritmo de afinamento paralelo com dois sub-ciclos está sendo proposto e comparado com outro algoritmo de afinamento paralelo de 8-conectores. Questões Computacionais são também relatadas baseadas na implementação do algoritmo de afinamento paralelo nas máquinas do SIMD CM-200 e MasPar MPP-12000. Palavras Chaves - Implementação Paralela, algoritmo de afinamento paralelo, máquinas SIMD, esqueletização. 1 Introdução O afinamento paralelo é visto como uma aproximação de afinamento ou esqueletização, devido ao crescimento real de arquiteturas paralelas e a real possibilidade do computador ser utilizado como sistema de visualização. É muito grande o crescimento de algoritmos paralelos baseados em redes neurais e afinamento tridimensional, gerando assim representações muito satisfatórias. Os algoritmos de afinamento paralelo são caracterizados pela repetição do processo de eliminação simultânea de todos os pontos de contorno “apagáveis” da imagem. Para ser eficiente, o numero de repetições ou iterações deve ser igual a metade da largura máxima dos objetos presentes na imagem. É óbvio que quanto menos tempo o algoritmo levar para processar, melhor será o processo, sobre a restrição que evitar erosão excessiva e manter as curvas as mais perfeitas possíveis. -Reduzir o número de iterações e o tempo de complexidade de cada iteração - Produzir perfeitamente linhas afinadas 8conectadas - Prevenir a erosão excessiva Esse algoritmo descreve que os pontos são eliminados a partir da análise dos pontos vizinhos utilizando uma máscara 3x4 na primeira etapa e logo, uma máscara 3x3 na segunda etapa. 2 Notações Básicas Conforme as especificações, está entendido que um pixel em estudo "p" é um pixel preto e que os seus vizinhos na janela (3x3) são rotulados como x1,x2,...,x8, conforme a figura 1. Com isso propõe-se um algoritmo que será executado em dois ciclos sendo capaz de: 1 2 - - - - - Definição 1: Os pixels (x1,x2,...,x8) são os 8vizinhos do pixel p, denotado por N(p) e são ditos 8adjacentes vizinhos a p; Definição 2: Os pixels (x1,x3,x5 e x7) são os 4 vizinhos do pixel P, e são ditos 4-adjacentes vizinhos a P; Definição 3: Uma seqüência de pontos Z1,Z2,...,Zn é chamado de 8-ou (4-) caminho em 8- ou (4-) vizinhos de Zi , para i= 1,2,...,n-1; Definição 4: Um subconjunto C de uma imagem P é denominado 8- ou (4-) conectado se para todo par de pontos(x,y) em C se existir 8- ou (4-)caminhos de x para y, e que sejam pontos pertencentes a C; Definição 5: O número de transições entre pixels pretos e brancos, e vice-versa e denominado número de Rutowitz é definido como sendo : 3 Os Dois Ciclos do Algoritmo de Afinamento O algoritmo paralelo com dois ciclos necessita de dois conjuntos de pontos “apagáveis” em paralelo, cuja união contém todo os pixels de bordas apagáveis. Esta noção de “apagabilidade” significa que, todos os pontos “P” do conjunto podem ser simultaneamente apagados sem causar a erosão excessiva e ainda mantém a topologia de qualquer padrão binário. Definição 6 : Se um pixel “P” preto possui pelo menos 1 pixel branco como vizinho, é chamado ponto de borda Definição 7: Um pixel preto tem no máximo 8 vizinhos com pixel preto, isso é chamado ponto final. Definição 8: A quebra de qualquer pixel “P” na continuidade da imagem padrão forma um ponto de quebra. A essência do algoritmo apresentado consiste em executar várias iterações sobre o padrão, onde muitos pontos pretos são apagados em cada iteração. Se nenhum ponto for apagado até o fim da execução, o algoritmo é finalizado. Em qualquer sub-ciclo, o conjunto de pixels preto apagado deve seguir um padrão que satisfaça os seguintes critérios: Um conjunto de pixels preto é apagado em paralelo se todo ponto desse conjunto é um ponto de borda, e não ponto final (break point). Pontos de borda são pontos (pixels), mais externos da imagem. Também esta possível eliminação não deve causar erosão excessiva. Lema 1:O conjunto I1 de pixels pretos p que satisfazer as seguintes condições: i) Número de transições: Xr(p)=2; ii) Número de pixels vizinhos: 2<=b (p)<=6; iii) R0=0 onde R0 é: De acordo com a condição “ii”, existem de 2 a 6 pixels vizinhos de P que são candidatos a serem apagados. No contrário a condição “i” diz que existe somente duas transições (0-1 ou 1-0), e isso corresponde a ter dois “1” entre x1,x2,...,X8, enquanto os seis pixels que faltam podem ser todos 0 ou 4 deles serem iguais a 1. Baseado nessas considerações, o conjunto N(p) contém entre 2 e 6 pixels pretos que estão 4-conectados entre eles, todas as possíveis pares de pixels são conectados por um 4-caminho. Além disso “P” não é um break point. Desde que os pixels satisfaçam as condições i e ii, eles podem ser apagados em paralelo. Para solucionar este problema não podemos usar máscara 3x3, temos que usar máscara 4x3 ou 3x4(a1 e a2-Logo abaixo). - Lema 2: IV) S0 ^ S1 ^(b(p)>=2) V) R1=0 ^ (b(p)>=3) O S0 é uma matriz 3x3(b1 e b2) e S1 é uma matriz (3x3), com rotação de 90º, 180º e 360º de seus elementos. Desde que estes modelos possuam entre 2 e 5 4-conectados pixels pretos, P tem pelo menos 4-vizinhos pixels brancos, e que não são pontos quebrados. Se b(p) > 2, garantimos que o ponto P, não é um ponto isolado ou ponto final. Desde que todo conjunto de pixels preto satisfaça a condição “V”, ele pode ser apagado em paralelo. Se a condição “V” não for respeitada, será preciso salvar o pixel, e aplicar outra expressão booleana. 2 3 A expressão seria a R1, que utilizaria uma matriz (d1 e d2) que satisfaria as condições IV e V. a) b) c) d) Grau de 8-conectado Grau de erosão Estabilidade sob a rotação Limite de ruído 5 Conclusão Neste resumo de artigo relatamos um novo algoritmo de afinamento paralelo com dois sub-ciclos, caracterizado pela utilização de matriz (3×4) ao primeiro sub-ciclo, e uma matriz (3×3) no segundo sub-ciclo. Concluímos que o referido algoritmo (Petrosino e Salvi) obtém resultados superiores quanto ao número de pixels do esqueleto e tempo de processamento. Um problema associado a muitos algoritmos existentes, é que estes produzem esqueletos com muito ruído se as bordas das imagens padrões possuírem muito ruído também. O efeito deste processo tem dado muita ênfase a estudos mais aprofundados. Por isso surgiram métodos para suavizar as bordas das imagens antes de aplicar o afinamento, utilizando filtros em níveis de cinza ou aplicando uma eliminação dos pontos ruidosos a cada interação. Em alguns casos a utilização de máscara 3x3 não tem retornado bons efeitos, sendo necessário aplicar uma máscara 5x5 em alguns pixels vizinhos ao ponto de partida. Na prática essa utilização de máscara 5x5 se resume na limpeza de pixels utilizando o OR (Booleano). 4 Comparações e resultados entre outros algoritmos Usamos o resultados do algoritmo com outros, como os de Deutsch, Zang e Suen, Chen e Hsu, Wang e Zhang, Susuki e Abe, Guo and Hall, Stefanelli e Rosenfeld[14], pudemos comparar os seguintes parâmetros: 6 Dificuldades e Resultados As dificuldades encontradas no desenvolvimento do algoritmo foram notadas na adaptação das expressões lógicas, que necessitaram de uma extrema atenção. A definição da matriz corretamente também foi muito importante, pois o algoritmo se baseia na utilização destas. Por conter expressões grandes, dividimos as mesmas em partes para facilitar o entendimento dos resultados e aplicações seguintes no contexto em geral. Foi possível notar que para desenvolver o algoritmo foi preciso seguir com extrema precisão as definições do artigo em si . Os resultados obtidos foram muito bons, ou seja, o algoritmo de Petrosino e Salvi funciona perfeitamente. Com relação ao algoritmo de Zang e Suen , o algoritmo de Petrosino e Salvi obteve um esqueleto muito mais definido em termos do número de pixels(menor quantidade), um desempenho muito bom e resultados visíveis interessantes. 7 Referências [PETROSINO (2000)], [SALVI (2000)]. ALFREDO PETROSINO AND GIUSEPPE SALVI, A Two-Sub cycle Thinning Algorithm and Its Parallel Implementation on SIMD Machines, IEEE TRANSACTIONS ON IMAGE PROCESSING, VOL. 9, NO. 2, FEBRUARY 2000. 3 4 CODIGO FONTE DO ALGORITMO DE AFINAMENTO 1- DEFINIÇÃO DA MATRIZ //PETROSINO //MAT 4X4 // // // // X4 X3 X2 Y4 X5 P X1 Y5 X6 X7 X8 Y6 Y1 Y2 Y3 #define P(MAT,X,Y) (MAT.GetAt(X ))->GetAt(Y) #define X1(MAT,X,Y) (MAT.GetAt(X ))->GetAt(Y+1) #define X2(MAT,X,Y) (MAT.GetAt(X-1))->GetAt(Y+1) #define X3(MAT,X,Y) (MAT.GetAt(X-1))->GetAt(Y) #define X4(MAT,X,Y) (MAT.GetAt(X-1))->GetAt(Y-1) #define X5(MAT,X,Y) (MAT.GetAt(X ))->GetAt(Y-1) #define X6(MAT,X,Y) (MAT.GetAt(X+1))->GetAt(Y-1) #define X7(MAT,X,Y) (MAT.GetAt(X+1))->GetAt(Y) #define X8(MAT,X,Y) (MAT.GetAt(X+1))->GetAt(Y+1) #define Y6(MAT,X,Y) (MAT.GetAt(X+1))->GetAt(Y+2) #define Y5(MAT,X,Y) (MAT.GetAt(X))->GetAt(Y+2) #define Y4(MAT,X,Y) (MAT.GetAt(X-1))->GetAt(Y+2) #define Y1(MAT,X,Y) (MAT.GetAt(X+2))->GetAt(Y-1) #define Y2(MAT,X,Y) (MAT.GetAt(X+2))->GetAt(Y) #define Y3(MAT,X,Y) (MAT.GetAt(X+2))->GetAt(Y+1) CÓDIGO DO ALGORITMO DE PETROSINO BOOL CPdiMorfoB::AfinamentoPetrosino(CString Titulo) { BOOL ThiningContinue=TRUE; int line, col, counter; PixelPoint ActualPixel; BYTE Conectivity=0, Neighboors=0; CArray <PixelPoint,PixelPoint> RemPoints; CArray<CArray<BYTE, BYTE> *,CArray<BYTE, BYTE> *> Iteraction; X RECEBE A LARGURA TOTAL DO BITMAP Y RECEBE A ALTURA TOTAL DO BITMAP int x = GetWidth(); int y = GetHeight(); int num_iteracoes = 0,linhas_codificadas=0; CString total; CTime start = CTime::GetCurrentTime(); 4 5 LAÇO PARA VERIFICAÇÃO DOS PIXELS PRETOS E BRANCOS CONTIDOS NO BITMAP for (line = 0; line < (int) GetHeight(); line++) { CArray<BYTE, BYTE> *ptrLine = new CArray<BYTE, BYTE>; for (col = 0; col < (int) GetWidth(); col++) { (int) GetPixelBW(col,line) ? ptrLine->Add(0) : ptrLine->Add(1); } Iteraction.Add(ptrLine); } while(ThiningContinue) { ThiningContinue = FALSE; num_iteracoes ++; PRIMEIRA ITERAÇÃO int R0,R1,Rtemp1,Rtemp2,Rtemp3,Rtemp4; int Bp = 0; int Xr = 0; for (line = 1; line < (int) GetHeight()-1; line++) { for (col = 1; col < (int) GetWidth()-1; col++) { Bp = 0; Xr = 0; linhas_codificadas=GetHeight(); PIXEL DEVE SER PRETO if( P(Iteraction,line,col) == 0 ) continue; CONETIVIDADE DEVE SER 2 Xr = (X1(Iteraction,line,col) == 0 && X2(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X2(Iteraction,line,col) == 0 && X3(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X3(Iteraction,line,col) == 0 && X4(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X4(Iteraction,line,col) == 0 && X5(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X5(Iteraction,line,col) == 0 && X6(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X6(Iteraction,line,col) == 0 && X7(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X7(Iteraction,line,col) == 0 && X8(Iteraction,line,col)== 1) ? 1 : 0; Xr += (X8(Iteraction,line,col) == 0 && X1(Iteraction,line,col)== 1) ? 1 : 0; if (Xr !=2) continue; NUMERO DE VIZINHOS DO PIXEL “P” DEVE SER MAIOR OU IGUAL A 2 E MENOR OU IGUAL A 6 5 6 // 2 <= Bp <= 6 Bp= X1(Iteraction,line,col) + X2(Iteraction,line,col)+X3(Iteraction,line,col)+X4(Iteraction,line,col) X6(Iteraction,line,col) + X7(Iteraction,line,col) + X8(Iteraction,line,col); +X5(Iteraction,line,col)+ if (Bp < 2 || Bp > 6) continue; AQUI DIVIDIMOS A EXPRESSÃO R0 EM VÁRIAS PARTES PARA FACILITAR A COMPREENSÃO // R0=0 R0=Rtemp1=Rtemp2=Rtemp3=Rtemp4=0; Rtemp1=(1-Y5(Iteraction,line,col))*X2(Iteraction,line,col)*X3(Iteraction,line,col)*(1-X5(Iteraction,line,col)); Rtemp2=(1-Y2(Iteraction,line,col))*(1X3(Iteraction,line,col))*X5(Iteraction,line,col)*X6(Iteraction,line,col); Rtemp3= (Rtemp1 ==0 && Rtemp2 == 0)? 0: 1; Rtemp4=X1 (Iteraction,line,col)*X7(Iteraction,line,col)*X8(Iteraction,line,col); R0 = Rtemp3*Rtemp4 ; if (R0 != 0) continue; PIXEL QUE DEVE SER DELETADO ThiningContinue = TRUE; ActualPixel.Px = line; ActualPixel.Py = col; RemPoints.Add(ActualPixel); } } for(counter=0;counter<RemPoints.GetSize();counter++) Delete(Iteraction,RemPoints[counter].Px,RemPoints[counter].Py); RemPoints.RemoveAll(); SEGUNDA ITERAÇÃO int S0,S1,Stemp1,Stemp2,Stemp3,Stemp4; for (line = 1; line < (int) GetHeight()-1; line++) { for (col = 1; col < (int) GetWidth()-1; col++) { O PIXEL DEVER SER PRETO 6 7 if( P(Iteraction,line,col) == 0 ) continue; S0=Stemp1=Stemp2=Stemp3=Stemp4=0; Stemp1=X3 (Iteraction,line,col)*X7(Iteraction,line,col); Stemp2=X5 (Iteraction,line,col)*X1(Iteraction,line,col); S0= (Stemp1 ==0 && Stemp2 == 0)? 0: 1; S1=Stemp1=Stemp2=Stemp3=Stemp4=0; AQUI DIVIDIMOS A EXPRESSÃO S1 EM VÁRIAS PARTES PARA FACILITAR A COMPREENSÃO Stemp1=((1-X4 (Iteraction,line,col))==0 && X7(Iteraction,line,col)== 0) ? 0: 1; Stemp1 *= X1 (Iteraction,line,col)*(1-X6(Iteraction,line,col)); Stemp2=((1-X6 (Iteraction,line,col))==0 && X5(Iteraction,line,col)== 0) ? 0:1; Stemp2 *= X3 (Iteraction,line,col)*(1-X8(Iteraction,line,col)); Stemp3=((1-X2 (Iteraction,line,col))==0 && X1(Iteraction,line,col)== 0) ? 0:1; Stemp3 *= X7 (Iteraction,line,col)*(1-X4(Iteraction,line,col)); Stemp4=((1-X8 (Iteraction,line,col))==0 && X7(Iteraction,line,col)== 0) ? 0:1; Stemp4 *= X5 (Iteraction,line,col)*(1-X2(Iteraction,line,col)); if(Stemp1==0 && Stemp2==0 && Stemp3==0 && Stemp4==0) S1=0; else S1=1; NUMERO DE VIZINHOS DEVE SER >= 2 // Bp >=2 Bp=X1(Iteraction,line,col)+X2(Iteraction,line,col)+X3(Iteraction,line,col)+X4(Iteraction,line,col) X6(Iteraction,line,col) + X7(Iteraction,line,col) + X8(Iteraction,line,col); +X5(Iteraction,line,col)+ // 1-S0 ^ S1 ^ (Bp >=2); if (!((1-S0==1) && (S1 ==1) && (Bp >=2))) continue; R1=Rtemp1=Rtemp2=Rtemp3=Rtemp4=0; int Rtemp5,Rtemp6; AQUI DIVIDIMOS A EXPRESSÃO R1 EM VÁRIAS PARTES PARA FACILITAR A COMPREENSÃO Rtemp1=(1-X8 (Iteraction,line,col))*X1(Iteraction,line,col); Rtemp2=(1-X6 (Iteraction,line,col))*X5(Iteraction,line,col); 7 8 Rtemp3= (Rtemp1 ==0 && Rtemp2 == 0)? 0: 1; Rtemp3 *= (1-X3 (Iteraction,line,col)); Rtemp4=(1-X8 (Iteraction,line,col))*(1-X5(Iteraction,line,col)); Rtemp5=(1-X6 (Iteraction,line,col))*(1-X1(Iteraction,line,col)); Rtemp6= (Rtemp4 ==0 && Rtemp5 == 0)? 0: 1; Rtemp6 *= (1-X7 (Iteraction,line,col)); R1= (Rtemp3 ==0 && Rtemp6 == 0)? 0: 1; if(!(R1 ==0 && Bp <= 3)) continue; PIXEL QUE DEVE SER DELETADO ThiningContinue = TRUE; ActualPixel.Px = line; ActualPixel.Py = col; RemPoints.Add(ActualPixel); } } for(counter=0;counter<RemPoints.GetSize();counter++) Delete(Iteraction,RemPoints[counter].Px,RemPoints[counter].Py); RemPoints.RemoveAll(); } FUNÇÃO QUE REDESENHA PIXEL COM A COR PRETA OU BRANCA for (line = 0; line < y; line++) { for (col = 0; col < x; col++) { if(P1(Iteraction,line,col) == 0) SetPixel((DWORD) col, (DWORD) (y-1)-line,RGB(255,255,255)); else SetPixel((DWORD) col, (DWORD) (y-1)-line,RGB(0,0,0)); } } FUNÇÃO CONTA O NUMERO DE PIXELS PRETOS int num_pixels_esqueleto = 0; for (line = 1; line < (int) GetHeight()-1; line++) { for (col = 1; col < (int) GetWidth()-1; col++) { // Pixel must be black if( GetPixel(col,line) == RGB(0,0,0) ) num_pixels_esqueleto++; 8 9 } } FUNÇÃO QUE CALCULA TEMPO DE PROCESSAMENTO CTime end = CTime::GetCurrentTime(); CTimeSpan elapsedTime = end - start; total = elapsedTime.Format( " %M min, %S seg" ); PASSAGEM DE PARAMETROS PARA A ESTATISTICA DO ALGORITMO CDadosEstudo* Estudo; Estudo = new CDadosEstudo(); Estudo->num_linhas_codificadas =228; Estudo->nome_esqueleto = "Petrosino"; Estudo->num_lacos_repeticao = 11; Estudo->tempo_processamento = total; Estudo->memory = "12Mbytes"; Estudo->nome_imagem = Titulo; Estudo->num_iteracoes = num_iteracoes; Estudo->num_pixels_esqueleto = num_pixels_esqueleto; ListaEstudo.AddTail(Estudo); return TRUE; } 9