Localizando regiões / padrões simétricos na imagem

14

Eu tenho um conjunto de imagens que representam a curvatura média de uma superfície traseira humana.

O que eu quero fazer é "escanear" a imagem em busca de pontos que tenham "contrapartes" semelhantes e refletidas em alguma outra parte da imagem (provavelmente simétrica à linha média, mas não necessariamente, pois pode haver deformidades). Algumas técnicas de costura de imagens usam isso para "detectar automaticamente" pontos semelhantes entre as imagens, mas eu quero detectá-los nos dois lados da mesma imagem.

O objetivo final é encontrar uma linha longitudinal contínua, provavelmente curva, que divida adaptativamente as costas em "metades" simétricas.

Uma imagem de amostra é colocada abaixo. Observe que nem todas as regiões são simétricas (especificamente, logo acima do centro da imagem, a "faixa" vertical vermelha desvia para a direita). Essa região deve receber uma pontuação ruim, ou o que seja, mas a simetria local seria definida a partir de pontos simétricos colocados mais distantes. De qualquer forma, terei que adaptar qualquer algoritmo ao meu domínio de aplicativo, mas o que estou procurando é uma estratégia de correlação / convolução / correspondência de padrões, acho que já deve haver algo por aí.

(EDIT: existem mais imagens abaixo e mais algumas explicações)

insira a descrição da imagem aqui

EDIT: conforme solicitado, incluirei imagens mais típicas, bem comportadas e problemáticas. Porém, em vez de imagens mapeadas em cores, elas são em escala de cinza, de modo que a cor se relaciona diretamente à magnitude dos dados, o que não aconteceu com a imagem colorida (fornecida apenas para comunicação). Embora as imagens em cinza pareçam não ter contraste em comparação com as coloridas, os gradientes de dados estão lá e podem ser trazidos com algum contraste adaptável, se desejado.


1) Imagem de um assunto muito simétrico:

insira a descrição da imagem aqui


2) Imagem do mesmo assunto em um momento diferente. Embora existam mais "recursos" (mais gradientes), ele não "parece" tão simétrico como antes:

insira a descrição da imagem aqui


3) Um sujeito jovem e magro, com convexidades (saliências ósseas, denotadas por regiões mais claras) na linha média em vez da linha côncava mais comum:

insira a descrição da imagem aqui


4) Um jovem com desvio da coluna vertebral confirmado por raios X (observe as assimetrias):

insira a descrição da imagem aqui


5) O assunto "inclinado" típico (embora principalmente simétrico em torno da linha média curvada e, como tal, não esteja "deformado" adequadamente):

insira a descrição da imagem aqui


Qualquer ajuda é muito bem-vinda!

heltonbiker
fonte
Por que não usar a coluna como divisor?
Jim Clay
@JimClay: Eu suspeito que a coluna vertebral é a parte a ser medido, em relação ao eixo real de simetria do resto da imagem
endolith
"Algumas técnicas de costura de imagens usam isso para" detectar automaticamente "pontos semelhantes entre as imagens" Faça uma cópia invertida da imagem e use uma delas. :)
endolith 28/11
Você não poderia simplesmente espelhar a imagem ao longo do eixo Y e usar um algoritmo de registro? Porque já existem muitas pesquisas sobre algoritmos de registro flexíveis / não paramétricos nos quais você pode desenvolver.
Niki Estner
JimClay, a coluna é o que eu quero encontrar, não sei onde é; Endólito, minha pergunta envolve pessoas dizendo os nomes de alguns desses algoritmos, que ainda não encontrei. E Nikie, que é o ponto inteiro, mas eu não conheço nenhum desses algoritmos, é por isso que eu estou pedindo na questão, em primeiro lugar: o)
heltonbiker

Respostas:

9

Como eu disse nos comentários, o registro de imagens médicas é um tópico com muitas pesquisas disponíveis, e eu não sou especialista. Pelo que li, a idéia básica comumente usada é definir um mapeamento entre duas imagens (no seu caso, uma imagem e sua imagem espelhada), depois definir termos de energia para suavidade e semelhança de imagem se o mapeamento for aplicado e, finalmente, otimize esse mapeamento usando técnicas de otimização padrão (ou às vezes específicas de aplicativos).

Eu criei um algoritmo rápido no Mathematica para demonstrar isso. Este não é um algoritmo que você deve usar em um aplicativo médico, apenas uma demonstração das idéias básicas.

Primeiro, carrego sua imagem, espelho e divido essas imagens em pequenos blocos:

src = ColorConvert[Import["http://i.stack.imgur.com/jf709.jpg"], 
   "Grayscale"];
mirror = ImageReflect[src, Left -> Right];
blockSize = 30;
partsS = ImagePartition[src, {blockSize, blockSize}];
partsM = ImagePartition[mirror, {blockSize, blockSize}];
GraphicsGrid[partsS]

Gráficos do Mathematica

Normalmente, faríamos um registro rígido aproximado (usando, por exemplo, pontos-chave ou momentos de imagem), mas sua imagem está quase centralizada, então eu vou pular isso.

Se olharmos para um bloco e sua contrapartida de imagem espelhada:

{partsS[[6, 10]], partsM[[6, 10]]}

Gráficos do Mathematica

Podemos ver que eles são semelhantes, mas mudaram. A quantidade e a direção da mudança é o que estamos tentando descobrir.

Para quantificar a similaridade da correspondência, posso usar a distância euclidiana ao quadrado:

ListPlot3D[
  ImageData[
   ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]], 
    SquaredEuclideanDistance]]]

Gráficos do Mathematica

infelizmente, usar esses dados é a otimização diretamente mais difícil do que eu pensava, então usei uma aproximação de segunda ordem:

fitTerms = {1, x, x^2, y, y^2, x*y};

fit = Fit[
   Flatten[MapIndexed[{#2[[1]] - blockSize/2, #2[[2]] - 
        blockSize/2, #1} &, 
     ImageData[
      ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]], 
       SquaredEuclideanDistance]], {2}], 1], fitTerms, {x, y}];

Plot3D[fit, {x, -25, 25}, {y, -25, 25}]

Gráficos do Mathematica

A função não é a mesma que a função de correlação real, mas está próxima o suficiente para um primeiro passo. Vamos calcular isso para cada par de blocos:

distancesFit = MapThread[
   Function[{part, template},
    Fit[Flatten[
      MapIndexed[{#2[[2]] - blockSize/2, #2[[1]] - blockSize/2, #1} &,
        ImageData[
        ImageCorrelate[part, template, 
         SquaredEuclideanDistance]], {2}], 1], 
     fitTerms, {x, y}]], {partsM, partsS}, 2];

Isso nos dá nosso primeiro termo energético para a otimização:

variablesX = Array[dx, Dimensions[partsS]];
variablesY = Array[dy, Dimensions[partsS]];

matchEnergyFit = 
  Total[MapThread[#1 /. {x -> #2, y -> #3} &, {distancesFit, 
     variablesX, variablesY}, 2], 3];

variablesX/Ycontém as compensações para cada bloco e matchEnergyFitaproxima a diferença euclidiana ao quadrado entre a imagem original e a imagem espelhada com as compensações aplicadas.

A otimização dessa energia por si só daria resultados ruins (se é que convergiam). Também queremos que as compensações sejam suaves, onde a similaridade do bloco não diz nada sobre a compensação (por exemplo, ao longo de uma linha reta ou no fundo branco).

Então, configuramos um segundo termo de energia para suavidade:

smoothnessEnergy = Total[Flatten[
    {
     Table[
      variablesX[[i, j - 1]] - 2 variablesX[[i, j]] + 
       variablesX[[i, j + 1]], {i, 1, Length[partsS]}, {j, 2, 
       Length[partsS[[1]]] - 1}],
     Table[
      variablesX[[i - 1, j]] - 2 variablesX[[i, j]] + 
       variablesX[[i + 1, j]], {i, 2, Length[partsS] - 1}, {j, 1, 
       Length[partsS[[1]]]}],
     Table[
      variablesY[[i, j - 1]] - 2 variablesY[[i, j]] + 
       variablesY[[i, j + 1]], {i, 1, Length[partsS]}, {j, 2, 
       Length[partsS[[1]]] - 1}],
     Table[
      variablesY[[i - 1, j]] - 2 variablesY[[i, j]] + 
       variablesY[[i + 1, j]], {i, 2, Length[partsS] - 1}, {j, 1, 
       Length[partsS[[1]]]}]
     }^2]];

Felizmente, a otimização restrita está integrada no Mathematica:

allVariables = Flatten[{variablesX, variablesY}];
constraints = -blockSize/3. < # < blockSize/3. & /@ allVariables;
initialValues = {#, 0} & /@ allVariables;
solution = 
  FindMinimum[{matchEnergyFit + 0.1 smoothnessEnergy, constraints}, 
   initialValues];

Vejamos o resultado:

grid = Table[{(j - 0.5)*blockSize - dx[i, j], (i - 0.5)*blockSize - 
      dy[i, j]}, {i, Length[partsS]}, {j, Length[partsS[[1]]]}] /. 
   solution[[2]];
Show[src, Graphics[
  {Red,
   Line /@ grid,
   Line /@ Transpose[grid]
   }]]

Gráficos do Mathematica

O 0.1fator anterior smoothnessEnergyé o peso relativo que a energia da suavidade recebe em relação ao termo de energia da correspondência de imagem. Estes são resultados para pesos diferentes:

Gráficos do Mathematica

Possíveis melhorias:

  • Como eu disse, faça um registro rígido primeiro. Com um fundo branco, o registro simples baseado em momentos da imagem deve funcionar bem.
  • Este é apenas um passo. Você pode usar os desvios encontrados em uma etapa e melhorá-los em uma segunda etapa, talvez com uma janela de pesquisa menor ou tamanhos de bloco menores
  • Eu li artigos em que eles fazem isso sem blocos, mas otimizam um deslocamento por pixel.
  • Experimente diferentes funções de suavidade
Niki Estner
fonte
responder muito tempo para ler apenas para se divertir, mas a imagem final é bastante indicativa: parece incrível: D
penelope
Essa resposta foi muito esclarecedora. Vou precisar de algum tempo para engoli-lo, mas provavelmente a técnica de registro não rígida é o que precisarei usar. Felizmente, você forneceu alguns detalhes conceituais, portanto, no pior caso, posso descobrir uma abordagem semelhante. Enquanto isso, atualizarei a pergunta com mais imagens. Obrigado por ora!
heltonbiker
4

Pergunta interessante. Primeiro, talvez você esteja buscando abordagens com base no detector de ponto-chave de interesse e na correspondência. Isso incluiria SIFT (Transform-Invariant Feature Transform), SURF, ORB, etc ... ou até mesmo uma abordagem mais simples baseada exclusivamente no operador Harris (csce.uark.edu/~jgauch/library/Features/Harris.1988.pdf ) Não está claro em sua postagem o que você tentou, então, desculpe se estou sendo ingênuo aqui.

Dito isso, deixe-me adotar uma abordagem mais simples com a Morfologia matemática (MM) apenas por diversão :) As imagens para visualização de todas as etapas estão no final.

Peguei sua imagem de amostra e a converti para o espaço de cores L a b * usando o ImageMagick e usei apenas a banda L *:

convert x.jpg -colorspace Lab -separate %d.png

0.png corresponde à banda L *. Agora, tenho certeza de que você tem os dados reais da imagem, mas estou lidando com artefatos de compactação jpg e o que não. Para lidar parcialmente com esse problema, realizei uma abertura morfológica seguida de um fechamento morfológico com um disco plano de raio 5. Essa é uma maneira básica de reduzir o ruído com MM e, dado que o raio do disco, grande parte da imagem não é alterada. Em seguida, minha ideia foi baseada nessa imagem única, com grandes chances de falhar em outros casos. Sua região de interesse é distinguida visualmente por ser mais escura ("mais quente" na imagem colorida), então eu supunha que um binarizador estatístico pudesse ter um bom desempenho. Eu usei a abordagem do Otsu, que é automática.

Neste ponto, é possível visualizar claramente a região central de interesse. O problema é que, na minha abordagem, eu queria que fosse um componente fechado, mas não é. Começo descartando todos os componentes conectados menores que o maior (sem contar o fundo como um deles). Isso tem mais chance de funcionar em outros casos, se o resultado da binarização for bom. Na imagem de exemplo, há um componente conectado ao plano de fundo, portanto ele não é descartado, mas não causa problemas.

Se você ainda está me seguindo, ainda precisamos encontrar a suposta região central de interesse. Aqui está a minha opinião. Não importa quão curvada a pessoa seja (na verdade, posso ver certos casos problemáticos), a região se assemelha a uma linha vertical. Para esse fim, simplifico a imagem atual executando uma abertura morfológica com uma linha vertical de comprimento 100. Esse comprimento é puramente arbitrário, se você não tiver problemas de dimensionamento, esse valor não será difícil de determinar. Agora, descartamos novamente os componentes, mas tomei um pouco mais de cuidado nesta etapa. Usei a abertura por área com o complemento da imagem para descartar o que considerava pequenas regiões; isso poderia ser feito de maneira mais controlada, realizando algo sob a forma de análise granulométrica (também da MM).

Temos aproximadamente três peças agora: a parte esquerda da imagem, a parte central e a parte direita da imagem. Espera-se que a parte central seja o componente menor dos três, portanto é obtida trivialmente.

Aqui está o resultado final, a imagem inferior direita é apenas a imagem sobreposta à esquerda com a original. Os números individuais não estão todos alinhados, desculpe pela pressa.

http://i.imgur.com/XRhYv.png

mmgp
fonte
Muito obrigado pelo seu interesse, mas sua abordagem deve considerar certas propriedades dos meus dados (não uma reclamação, apenas um detalhamento): 1) Os dados reais são uma matriz 2D de carros alegóricos, mapeados por cores com um vermelho-amarelo- divergente- mapa de cores verde no matplotlib do Python. Não acho que trabalhar com os dados de cores seja conceitualmente correto, as imagens são mostradas apenas para fins de comunicação; 2) Os dados reais estão relacionados à curvatura da superfície (convexa vs. côncava), com as partes vermelhas sendo côncavas e as verdes sendo convexas. O eixo simétrico não cai necessariamente em uma região côncava.
heltonbiker
Em breve, adicionarei mais algumas imagens (e substituirei esta) por outras em escala de cinza, para que as próprias imagens possam ser usadas para testes, eliminando o risco de distorção do alcance dinâmico devido à cor.
heltonbiker
Os dados ainda não estão disponíveis, infelizmente. As imagens em escala de cinza são, na melhor das hipóteses, uma aproximação dela.
MMGP
Acredito que a aproximação provavelmente seja suficiente, mas não me importo de fornecer os dados reais. Posso postar alguns links públicos de download do DropBox, mas não sei em qual formato de arquivo.
heltonbiker