Painterly Rendering com pinceladas curvas Autores: Fabiano Segadaes Romeiro Leandro de Mattos Ferreira Processamento de Imagens – IMPA 2001 Objetivos • Criar um programa que , utilizando-se de métodos da computação gráfica, permita a reprodução de diversas técnicas de pintura de forma prática , automatizada e intuitiva. • Permitir a criação de novos estilos por meio da alteração de parâmetros compreensíveis. Método de pintura • O processo físico de pintar utiliza-se de • pinceladas de diversos tamanhos e em várias direções. Estas pinceladas sozinhas, não têm muito significado, mas quando em conjunto formam os efeitos desejados na pintura. Este algoritmo começa a pintura com pincéis grandes , e depois a refina com pinceladas cada vez mais finas, assim como um artista normalmente faz. Método de Pintura Imagem de Teste – O Lagarto Método de Pintura Pintura no estilo Expressionista – processo detalhado 1 – Após pinceladas com o maior pincel (8 pixels) 2 – Após pinceladas com o pincel médio (4 pixels) 3 – Após pinceladas com o pincel médio (2 pixels) 4 – Após pinceladas com o menor pincel (1 pixel) Método de Pintura Resultado Final – O Lagarto expressionista O algoritmo • Inicialmente, produz-se uma tela a partir da imagem original. Cada pixel desta tela receberá a cor mais distante, no espaço RGB, do pixel correspondente na imagem original. • Esta distância é calculada pela seguinte fórmula: |(r1,g1,b1)-(r2,g2,b2)|=[(r1-r2)2 +(g1-g2)2 + (b1-b2)2]0,5 O algoritmo • Sobre essa tela começamos a pintar as camadas • • • • correspondentes a cada tamanho de pincel. Calculamos inicialmente as summed area tables (sat) correspondentes as componentes R, G e B da imagem original. Pintamos primeiramente a camada correspondente ao pincel de maior tamanho sobre a tela, utilizando para isso uma imagem de referência, gerada por um Blur da imagem original. Esse Blur é realizado através das sat, realizando para cada pixel uma média entre os pixels que o cercam (quanto maior o pincel, mais pixels são utilizados e mais borrada a imagem fica) Prosseguimos pintando as camadas para os outros pincéis, em ordem decrescente de tamanho. Algoritmo de pintura • • • • • • • • • • • • • Image *paint(Image *srcImage, pr_params pp ) { fill_sat(srcImage, sat_r, sat_g, sat_b); fill_canvas(canvas, srcImage); for each brush radius R in pp from largest to smallest do { satBlur(referenceImage, R, sat_r, sat_g, sat_b); paintLayer(canvas, referenceImage, pp,R) } return canvas } O Algoritmo – Pintura das camadas • Cria-se uma matriz que contem as diferenças entre os pixels da imagem original e da tela no seu estado atual. • Varremos então a imagem de referência (dividida em grids). • Para cada grid traçamos a pincelada correspondente. • Utilização de z-buffer para as pinceladas. O Algoritmo – Pintura das camadas • • • • • • • • • • • • • • • • • void paintLayer(canvas,referenceImage,pp, R) { Z_buff = matriz do z_buffer D = difference(canvas,referenceImage) grid = pp.f_grid*R for (x=0;x< imageWidth;x+=grid) for (y=0; y< imageHeight;y+=grid) { M= região (xgrid/2..x+grid/2, ygrid/2..y+grid/2) areaError = (sum(Di,j) for i in M )/ grid*grid; if (areaError > pp.Threshold) { (x1,y1) = ponto com Di,j máximo, com i pertencente a M makeSplineStroke(R,x1 ,y1 ,referenceImage,canvas, pp,z_buff) } } } O Algoritmo - Pinceladas • Para calcularmos a pincelada, partimos do ponto de controle inicial, seguindo na direção normal ao gradiente da luminância da imagem original. • Obtemos assim os demais pontos de controle, sobre os quais traçamos a pincelada como uma spline O Algoritmo – Pinceladas Void makeSplineStroke(R, x1, y1, referenceImage,canvas,pp,z_buff) { • strokeColor = referenceImage.color(x1 ,y1 ) • K = matriz que irá receber a pincelada • adiciona (x1 ,y1 ) a K • (x,y) = (x 1,y1 ) • (lastDx,lastDy) = (0,0) • for (i=1;i<maxStrokeLength;i++) • { • if (i > minStrokeLength and |refImage.color(x,y)canvas.color(x,y)|<|refImage.color(x,y)strokeColor|) • break; • if (refImage.gradient(x,y) ==(0, 0)) then • break; • (gx,gy) = refImage.gradientDirection(x,y) • (dx,dy) = (gy, gx) • if (lastDx * dx + lastDy * dy < 0) • (dx,dy) = (dx, dy) • (dx,dy) =pp.f c *(dx,dy)+(1pp.f c )*(lastDx,lastDy) • (dx,dy) = (dx,dy)/(dx 2 + dy 2 ) 1/2 • (x,y) = (x+R*dx, y+R*dy) • (lastDx,lastDy) = (dx,dy) • adiciona (x,y) to K • } • plotSplineStroke(canvas, strokeColor, K,z_buff); } Resultados e conclusões • Ao longo do desenvolvimento, com a interface gráfica o programa teve o seu manuseio bastante facilitado, sobretudo na geração de novos estilos de renderização das pinturas. • Tendo concluido o programa, testamos diferentes parâmetros/estilos, que geraram imagens bastante interessantes. Estilos - Impressionista Estilos – Colorist Wash Estilos - Pontilhismo Estilos – Psychodelic Estilos – Ridist Painterly Rendering FIM