Documento - PUC-Rio

Propaganda
HDR com Python e GTK+
Aldo Nogueira
PUC-Rio
Introdução
Durante o curso de Fundamentos de Computação Gráfica, foram oferecidos vários temas
para o quarto trabalho. Um deles que me despertou interesse foi o de implementar o algoritmo para
geração de imagens HDR descrito em [debevec]. A princípio, pensei em desenvolver essa aplicação
em C, usando a Gnu Scientific Library [gsl] para o problema de minimização e GTK+ [gtk]para
interface gráfica. Cheguei a traduzir o algoritmo em Matlab/Octave do fim do artigo para C com
usando GSL. Foi durante o desenvolvimento da interface, que percebi que poderia fazer todo o
projeto em Python com muito menos esforço.
HDR
Um imagem, tipicamente, tem 256 níveis de intensidade para cada canal de cor vermelha,
verde e azul. Essa faixa não permite representar adequadamente, cenas que possuam áreas com
muita ou pouca exposição. Áreas pouco expostas são mapeadas para a cor preta e áreas muito
expostas para branco. Um fotógrafo deve então escolher em que faixa está o foco de interesse da
imagem e ajustar o tempo de exposição e/ou abertura do diafragma da câmera de acordo. Uma
imagem HDR (High Dynamic Range) é uma imagem cuja faixa de variação na intensidade luminosa
é maior do que uma imagem comum. Essa imagem pode ser obtida a partir de várias fotografias de
uma mesma cena com tempos de exposição diferentes.
Segundo [debevec], o processo de geração de uma imagem HDR começa com a obtenção da
função de resposta da câmera. Essa função é obtida a partir de uma série de fotografias e seus
tempos de exposição. O algoritmo usa minimização SVD. Veja em [otim], para mais informações
sobre otimização em Computação Gráfica. Uma vez obtida a função de resposta desse sistema, o
mapa de radiância pode ser obtido a partir de um somatório de todas as fotografias usando essa
função. Para geração de uma imagem virtual a partir do mapa de radiância, deve-se estipular um
tempo de exposição e então gerar essa imagem. O resultado final a x segundos, deve ser semelhante
à fotografia original nesse tempo de exposição.
Interface
Já que os algoritmos para geração da imagem HDR requerem um bocado de computação,
minha primeira opção foi desenvolvê-los em C ou C++. Além do código para o processamento das
imagens, queria que tivesse um a interface gráfica para facilitar sua utilização. Minha experiência
anterior com GTK+ foi boa, então decidi utilizá-la nesse projeto. GTK+ está presente em todas as
distribuições Gnu/Linux e diversas outras plataformas, incluindo Windows e MacOSX.
A interface com GTK+ pode ser feita de, duas formas: programando diretamente as janelas e
widgets, ou utilizando-se o Glade [glade]. Glade é um construtor de interface para GTK+.
Basicamente, o usuário clica em botões, arrasta widgets, define eventos de clique de botão e vai,
assim, montando sua interface. No final, é possível gerar código em C (e em C++, Ada, etc) que
mostre as janelas criadas. Basta, então, depois disso, programar o que será executado quando
ocorrer cada evento especificado.
Hoje em dia, na verdade, é mais comum, utilizar-se a Libglade [libglade] em vez de gerar
código. O programador cria interface, salva-a no formato do Glade, um arquivo XML, e chama a
Libglade a partir de seu programa, passando esse arquivo como parâmetro e assim a interface é
mostrada. Essa nova abordagem tem várias vantagens, dentre elas, que a interface pode ser
modificada mais facilmente e sem necessidade de recompilação.
Independentemente de que maneira eu iria implementar esse programa, comecei a esboçar
uma janela principal para o programa usando o Glade. Depois de algum tempo li alguns artigos
[pytgtk_articles] sobre PyGTK [pygtk] e aí surgiu a idéia de utilizar Python e PyGTK para esse
projeto. Tendo o arquivo XML gerado pelo Glade, bastou chamá-lo através do meu programa em
Python para a janela aparecer. A programação dos eventos foi feita em seguida ligando os eventos
gerados pelo Libglade aos métodos das classes no meu sistema.
Python [python]é uma linguagem interpretada, orientada a objetos de altíssimo nível. Muitos
nomes de peso dão crédito a essa linguagem como Bruce Eckel [eckel], Eric Raymond [raymond] e
outros. Eu particularmente, achei-a interessante pela produtividade, “economia de dedos” (é
concisa) e pela legibilidade. Existem diversos artigos comparando-a com Java, como [java] (um
pouco tendencioso). Tipicamente, um programa em Python é escrito muito mais rapidamente do que
o similar escrito em outra linguagem. A manutenção do programa também foi uma preocupação
minha. Programas difíceis de manter tendem a morrer por falta de atenção de seus desenvolvedores.
Processamento
A princípio, pensei em programar apenas a interface em Python e a computação mais intensa
seria feita em um módulo escrito em C. Python é bastante lenta por ser tão dinâmica e algum pontos
no programa ganhariam muito se fossem reescritos em C. Aliás, não é difícil estender Python com
módulos escritos em C, porém perde-se um pouco de portabilidade, pois adiciona-se um passo a
mais no ciclo de desenvolvimento, a compilação.
Uma biblioteca bastante popular no mundo Python é a Numeric Python [numpy]. Ela
permite fazer contas com matrizes a partir do Python. Percebi então que a obtenção da função de
resposta do câmera poderia ser feita usando essa biblioteca. Na verdade, não tem nenhum prejuízo
de performance, comparado com C puro, pois a montagem da matriz do sistema, que é feita em
código Python, é uma parte mínima do processamento. A maior parte do tempo é gasto na resolução
do sistema usando SVD, que é passada para código nativo utilizando uma biblioteca em Fortran ou
C como LAPACK (não sei ao certo qual é). A vantagem é que o programa permanece inteiramente
em Python.
Uma segunda parte do algoritmo é a montagem do mapa de radiância. Essa montagem é na
verdade uma série de somatórios ponderados, um para cada pixel das imagens. Essa parte foi
primeiramente implementada um método em Python com 4 loops for aninhados (!) e se revelou
lenta demais, como era de se esperar. Uma seqüência de 7 imagens de 320x200 demorou 45
segundos para ser processada em um AMD Duron 800 rodando Conectiva 10. Um outro teste no
Debian 3.1 (Sarge), mais recente, levou 26 segundos. Usando Psyco [psyco], também no Debian,
um compilador Just-in-time para Python conseguiu reduzir o tempo para 11 segundos. Reescreverei
o algoritmo em C para poder comparar o tempo de execução.
Como qualquer manual sobre Matlab/Octave diz, é melhor evitar loops e codificar utilizando
operações entre matrizes. Tentei escrever uma versão desse algoritmo com operações com matrizes,
usando uma técnica chamada vetorização. As técnicas que encontrei não atendiam às as
necessidades desse algoritmo especificamente. Enviei um email aos autores de um artigo sobre
vetorização em Python, um deles me respondeu dizendo que meu caso era um “nice puzzle” e que
a solução não era óbvia.
Destaque para uma diferença encontrada entre o Numeric Python e o Matlab/Octave. A
fatorização SVD do primeiro retorna U, Σ e V, enquanto o segundo retorna U, Σ e VT. Talvez isso
seja até um bug que, aliás, me custou quase duas semanas para resolver.
Screenshots
Ilustração 1 Tela inicial
Ilustração 2 Curvas de resposta da câmera
Ilustração 3 Imagem logarímica
Bibliografia
debevec: Paul E. Debevec and Jitendra Malik, Recovering High Dynamic Range Radiance Maps
from Photographs, 1997, http://www.debevec.org/Research/HDR/
gsl: M. Galassi et al, GNU Scientific Library Reference Manual, , http://www.gnu.org/software/gsl/
gtk: , GTK+: The GIMP Toolkit, , http://www.gtk.org/
otim: Velho, Luiz & Carvalho, Paulo C. P., Mathematical Optimization in Graphics and Vision,
2003, http://www.visgraf.impa.br/otim-03/course-notes.pdf
glade: , Glade - a User Interface Builder for GTK+ and GNOME, , http://glade.gnome.org/
libglade: , Libglade, , http://www.jamesh.id.au/software/libglade/
pytgtk_articles: , Articles and Tutorials about PyGTK, , http://www.pygtk.org/articles.html
pygtk: , PyGTK: GTK+ for Python, , http://www.pygtk.org/
python: , Python programming language, , http://www.python.org/
eckel: Bill Venners, Python and the Programmer, A Conversation with Bruce Eckel, 2003,
http://www.artima.com/intv/aboutme.html
raymond: Eric Raymond, Why Python?, 2000, http://www2.linuxjournal.com/article/3882
java: Steve Ferg, Python & Java: a Side-by-Side Comparison, 2004,
http://www.ferg.org/projects/python_java_side-by-side.html
numpy: , Numerical Python, , http://www.pfdubois.com/numpy/
psyco: , Psyco, , http://psyco.sourceforge.net/
Download