Processamento de imagens na prática

Watershed em imagens binárias, e um exemplo útil com ImageJ

Achei que começar uma série de artigos sobre watersheds seria uma boa idéia. E começar com um artigo simples e útil seria melhor ainda. Pela minha experiência, esta técnica de processamento acaba sub-utilizada porque a maior parte das implementações disponíveis e do material explicativo não favorece o usuário final. Ou são incompletos ou muito complicados.

Quero dar a minha contribuição para melhorar este quadro.

Explicando o watershed para imagens binárias

Segundo o livro de Russ (1998), a segmentação por watershed teve suas primeiras aparições como solução para um problema comum em segmentação de imagens: quando as partes segmentadas se tocam em pequenas áreas.

Originalmente era um método baseado em erosão e dilatação de imagens binárias, que se aproveitava do fato de que os objetos que se tocam, quando erodidos, se separam antes de desaparecer. A solução por operações morfológicas de erosão e dilatação era eficiente, mas de processamento demorado. Por isso logo apareceram implementações da mesma ideia usando um cálculo de distância euclidiana.

Este cálculo considera todos os objetos como se fossem montanhas, onde quanto maior a distância de um pixel da borda do objeto, maior seria a sua “altura”. Quando dois objetos se tocam, formam-se dois picos, e o vale entre eles é a linha que os separa. Daí o nome, watershed, que pode ser traduzido como bacia hidrográfica.

Mapa de distância euclidiana. Os círculos vermelhos marcam objetos correspontentes nas versões 2D e 3D.

Mapa de distância euclidiana. Os círculos vermelhos marcam objetos correspondentes nas versões 2D e 3D.

Este exemplo foi gerado com a imagem das sementes: o mapa de distância euclidiana foi gerado no ImageJ (usando o menu Process –> Binary –> Distance Map). Tive que ajustar o contraste para obter uma figura mais adequada à apresentação (isto também foi feito no ImageJ). A visualização 3D foi obtida no ImLab, e a montagem foi feita no Gimp.

Exemplo com ImageJ

Num tutorial sobre processamento em lote, terminei a segmentação por threshold com um resultado que não era perfeitamente real. Explico: as sementes foram segmentadas, mas algumas permaneceram unidas porque estavam muito próximas. Um passo a mais de segmentação, usando watershed, resolve isso.

Imagem original, resultado da segmentação por threshold, resultado da segmentação por watershed

Imagem original, resultado da segmentação por threshold, resultado da segmentação por watershed

Depois de obter a imagem binária por threshold é só chamar Process –> Binary –> Watershed e você terá uma imagem como a da direita. Simples assim.

O ImageJ implementa a segmentação por watersheds da forma como é descrito no Russ (1998). O cálculo das distâncias euclidianas para cada pixel gera os “picos das montanhas”, e então o algoritmo vai dilatando os objetos até o tamanho original, com a condição de não preencher pixels que pertenceriam a mais de um objeto.

Para ver o processo acontecendo, Habilite a opção Degug Mode, no diálogo Edit –> Options –> Misc… Com esta opção habilitada, aplicar o watershed vai gerar uma Stack que você pode animar em Image –> Stacks –> Start Animation e/ou salvar como Gif animado:

Gif animado gerado pelo ImageJ com o processo de segmentação por watersheds da imagem das sementes.

Gif animado gerado pelo ImageJ com o processo de segmentação por watersheds da imagem das sementes.

Importante!

É muito importante ter em mente que, neste caso, a segmentação por watershed foi apenas o passo final de todo um processo. Tentar aplicar este algoritmo (ou mesmo uma variação para tons de cinza, das quais vou falar qualquer dia) sem antes usar o threshold ia gerar um resultado maluco qualquer.

O fato é que vi alguns “exemplos” bem anti-didáticos na web, que fazem qualquer um pensar que o método não funciona! Como já expliquei no início do post, esta é uma das razões pelas quais se usa pouco esta ferramenta.

Referências

RUSS, John C. The Image Procesing Handbook. 3a. edição. IEEE Press, 1998.

As imagens dentro do post são minhas.

A imagem com link para o artigo na página principal é de fuzzytnth3.

Ente é só o início de uma série. Inscreva-se para receber as novidades assim que são publicadas.

8 Comentários para Watershed em imagens binárias, e um exemplo útil com ImageJ

  1. Andro's Gravatar Andro - 17 de março de 2009 at 15:38 | Permalink

    Vc salvou meu estágio
    muito obrigado
    estava com dificuldade de entender o Imagej
    agora vi que é muito fácil
    abraços!!!!

  2. Vinicius's Gravatar Vinicius - 10 de junho de 2009 at 15:13 | Permalink

    Cara muito bom seu post e site!
    Essa watershed realmente é muito boa.

    Parabens pela iniciativa.

    Abraços!

  3. Vinicius's Gravatar Vinicius - 9 de julho de 2009 at 10:42 | Permalink

    Gabriela parabens pelo post!

    Gostaria de saber aonde encontro o algoritimo ou implementacao em java da transformada watershed!

    Grato!

    Abracos!

  4. carolina's Gravatar carolina - 30 de abril de 2010 at 10:07 | Permalink

    Ola Gabriela
    Estou tentando entender o programa para análise de imagens de imunohistoquimica. Posso te mandar uma imagem para vc me ajudar? qual seu e-mail? se possivel me responde por e-mail?
    Abraço e obrigada

  5. Gilberto Kummer Junior's Gravatar Gilberto Kummer Junior - 7 de outubro de 2011 at 15:43 | Permalink

    Ola Gabriela.
    Sou estudante de Ciência da Computação e fui apresentado
    ao ImageJ esta semana gostei muito do software.
    Estou tendo um problema, tenho algumas imagens que foram retiradas de cameras de segurança em duas ações de Roubo. Ambas estão ruins e quando as aumento elas não geram imagens a ponto de se reconhecer a pessoa ou a placa de um veiculo. Existe alguma tecnica que possa ser usada no software para melhorar isto.
    Obrigado

Comente

Você pode usar estas tags e atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>