Gostaria de tirar fotos de etiquetas em um pote de comida e poder transformá-las para que a etiqueta fique plana, com o lado direito e esquerdo redimensionados para ficar alinhado com o centro da imagem.
Idealmente, eu gostaria de usar o contraste entre o rótulo e o plano de fundo para encontrar as arestas e aplicar a correção. Caso contrário, posso pedir ao usuário que identifique de alguma forma os cantos e os lados da imagem.
Estou procurando técnicas e algoritmos gerais para obter uma imagem inclinada esfericamente (cilíndrica no meu caso) e que possa achatar a imagem. Atualmente, a imagem de uma etiqueta enrolada em uma jarra ou garrafa terá recursos e texto que serão reduzidos à medida que retrocedem para a direita ou esquerda da imagem. Além disso, as linhas que indicam a borda do rótulo serão paralelas apenas no centro da imagem e se inclinarão uma na outra, no extremo direito e esquerdo do rótulo.
Depois de manipular a imagem, gostaria de ficar com um retângulo quase perfeito, onde o texto e os recursos são de tamanho uniforme, como se eu tivesse tirado uma foto da etiqueta quando ela não estava na jarra ou na garrafa.
Além disso, eu gostaria que a técnica pudesse detectar automaticamente as bordas do rótulo, a fim de aplicar a correção adequada. Caso contrário, eu teria que pedir ao meu usuário para indicar os limites do rótulo.
Já pesquisei no Google e encontrei artigos como este: achatando documentos curvos , mas estou procurando algo um pouco mais simples, pois minhas necessidades são de etiquetas com uma curva simples.
fonte
Respostas:
Uma pergunta semelhante foi feita no Mathematica.Stackexchange . Minha resposta por lá evoluiu e ficou bastante longa no final, então vou resumir o algoritmo aqui.
Abstrato
A ideia básica é:
O algoritmo funciona apenas para imagens em que:
No entanto, o algoritmo é modular. Pelo menos em princípio, você poderia escrever sua própria detecção de etiqueta que não requer um fundo escuro ou escrever sua própria função de medição de qualidade que pode lidar com etiquetas elípticas ou octogonais.
Resultados
Essas imagens foram processadas de forma totalmente automática, ou seja, o algoritmo obtém a imagem de origem, funciona por alguns segundos e mostra o mapeamento (à esquerda) e a imagem sem distorção (à direita):
As próximas imagens foram processadas com uma versão modificada do algoritmo, onde o usuário seleciona as bordas esquerda e direita do jar (não o rótulo), porque a curvatura do rótulo não pode ser estimada a partir da imagem em uma foto frontal (ou seja, o algoritmo totalmente automático retornaria imagens ligeiramente distorcidas):
Implementação:
1. Encontre o rótulo
O rótulo é brilhante diante de um fundo escuro, para que eu possa encontrá-lo facilmente usando a binarização:
Simplesmente escolho o maior componente conectado e assumo que esse é o rótulo:
2. Encontre as bordas do rótulo
Próxima etapa: encontre as bordas superior / inferior / esquerda / direita usando máscaras de convolução derivadas simples:
Essa é uma pequena função auxiliar que encontra todos os pixels brancos em uma dessas quatro imagens e converte os índices em coordenadas (
Position
retorna índices e os índices são baseados em 1 com base em {y, x} -tuplos, em que y = 1 está no topo de Mas todas as funções de processamento de imagem esperam coordenadas, com base em 0 (x, y} -tuples, em que y = 0 é a parte inferior da imagem):3. Encontre um mapeamento da imagem para as coordenadas do cilindro
Agora eu tenho quatro listas separadas de coordenadas das bordas superior, inferior, esquerda e direita do rótulo. Defino um mapeamento das coordenadas da imagem para as coordenadas do cilindro:
Este é um mapeamento cilíndrico, que mapeia coordenadas X / Y na imagem de origem para coordenadas cilíndricas. O mapeamento possui 10 graus de liberdade para altura / raio / centro / perspectiva / inclinação. Eu usei a série Taylor para aproximar o arco seno, porque não consegui fazer a otimização trabalhar diretamente com o ArcSin. o
Clip
chamadas são minha tentativa ad-hoc de impedir números complexos durante a otimização. Há uma troca aqui: por um lado, a função deve estar o mais próximo possível de um mapeamento cilíndrico exato, para fornecer a menor distorção possível. Por outro lado, se for muito complicado, fica muito mais difícil encontrar valores ótimos para os graus de liberdade automaticamente. (O bom de fazer o processamento de imagens com o Mathematica é que você pode brincar com modelos matemáticos como esse com muita facilidade, introduzir termos adicionais para diferentes distorções e usar as mesmas funções de otimização para obter resultados finais. Nunca consegui fazer nada usando o OpenCV ou o Matlab. Mas nunca experimentei a caixa de ferramentas simbólica do Matlab, talvez isso o torne mais útil.)Em seguida, defino uma "função de erro" que mede a qualidade de uma imagem -> mapeamento de coordenadas do cilindro. É apenas a soma dos erros ao quadrado dos pixels da borda:
Essa função de erro mede a "qualidade" de um mapeamento: é mais baixa se os pontos na borda esquerda são mapeados para (0 / [qualquer coisa]), os pixels na borda superior são mapeados para ([qualquer coisa] / 0) e assim por diante .
Agora posso dizer ao Mathematica para encontrar coeficientes que minimizem essa função de erro. Eu posso fazer "palpites" sobre alguns dos coeficientes (por exemplo, o raio e o centro do frasco na imagem). Eu os uso como pontos de partida da otimização:
FindMinimum
encontra valores para os 10 graus de liberdade da minha função de mapeamento que minimizam a função de erro. Combine o mapeamento genérico e esta solução e recebo um mapeamento das coordenadas da imagem X / Y, que se ajustam à área da etiqueta. Eu posso visualizar esse mapeamento usando aContourPlot
função do Mathematica :4. Transforme a imagem
Por fim, uso a
ImageForwardTransform
função do Mathematica para distorcer a imagem de acordo com este mapeamento:Isso fornece os resultados como mostrado acima.
Versão assistida manualmente
O algoritmo acima é totalmente automático. Não são necessários ajustes. Funciona razoavelmente bem desde que a foto seja tirada de cima ou de baixo. Mas se for uma foto frontal, o raio do frasco não pode ser estimado a partir da forma do rótulo. Nesses casos, obtenho resultados muito melhores se eu permitir que o usuário insira as bordas esquerda / direita do jar manualmente e defina explicitamente os graus de liberdade correspondentes no mapeamento.
Este código permite que o usuário selecione as bordas esquerda / direita:
Este é o código de otimização alternativo, onde o centro e o raio são dados explicitamente.
fonte