Qual é a melhor maneira de detectar os cantos de uma fatura / recibo / folha de papel em uma foto? Deve ser usado para correção de perspectiva subsequente, antes do OCR.
Minha abordagem atual tem sido:
RGB> Cinza> Canny Edge Detection with thresholding> Dilate (1)> Remove small objects (6)> Clear boarder objects> pick grande blog based on Convex Area. > [detecção de canto - não implementado]
Não posso deixar de pensar que deve haver uma abordagem "inteligente" / estatística mais robusta para lidar com esse tipo de segmentação. Não tenho muitos exemplos de treinamento, mas provavelmente poderia obter 100 imagens juntas.
Contexto mais amplo:
Estou usando matlab para prototipar e planejando implementar o sistema em OpenCV e Tesserect-OCR. Este é o primeiro de uma série de problemas de processamento de imagem que preciso resolver para este aplicativo específico. Portanto, estou procurando lançar minha própria solução e me familiarizar novamente com algoritmos de processamento de imagem.
Aqui estão alguns exemplos de imagem que eu gostaria que o algoritmo manipulasse: Se você gostaria de aceitar o desafio, as imagens grandes estão em http://madteckhead.com/tmp
(fonte: madteckhead.com )
(fonte: madteckhead.com )
(fonte: madteckhead.com )
(fonte: madteckhead.com )
Na melhor das hipóteses, isso dá:
(fonte: madteckhead.com )
(fonte: madteckhead.com )
(fonte: madteckhead.com )
No entanto, ele falha facilmente em outros casos:
(fonte: madteckhead.com )
(fonte: madteckhead.com )
(fonte: madteckhead.com )
Agradecemos antecipadamente por todas as ótimas ideias! Eu amo então!
EDIT: Progresso da Transformação de Hough
P: Qual algoritmo agruparia as linhas de altura para encontrar cantos? Seguindo os conselhos das respostas, consegui usar a transformada de Hough, escolher as linhas e filtrá-las. Minha abordagem atual é bastante rude. Presumi que a fatura sempre estará menos de 15 graus fora do alinhamento com a imagem. Acabo com resultados razoáveis para as linhas, se for esse o caso (veja abaixo). Mas não estou totalmente certo de um algoritmo adequado para agrupar as linhas (ou votar) para extrapolar para os cantos. As linhas de Hough não são contínuas. E nas imagens com ruído, pode haver linhas paralelas, portanto, alguma forma ou distância das métricas de origem da linha são necessárias. Alguma ideia?
(fonte: madteckhead.com )
fonte
Respostas:
Sou amigo de Martin que estava trabalhando nisso no início deste ano. Este foi meu primeiro projeto de codificação e meio que terminou com um pouco de pressa, então o código precisa de algum erro ... decodificação ... Vou dar algumas dicas do que eu já vi você fazer, e então classificar meu código no meu dia de folga amanhã.
Primeira dica,
OpenCV
epython
são fantásticos, mude para eles o mais rápido possível. : DEm vez de remover pequenos objetos e / ou ruído, reduza as restrições astutas, de modo que aceite mais arestas, e então encontre o maior contorno fechado (em OpenCV use
findcontour()
com alguns parâmetros simples, acho que useiCV_RETR_LIST
). ainda pode ter dificuldades quando está em um pedaço de papel branco, mas definitivamente estava fornecendo os melhores resultados.Para a
Houghline2()
transformação, tente com oCV_HOUGH_STANDARD
em oposição aCV_HOUGH_PROBABILISTIC
, ele fornecerá os valores rho e theta , definindo a linha em coordenadas polares, e então você pode agrupar as linhas dentro de uma certa tolerância a essas.Meu agrupamento funcionou como uma tabela de consulta, para cada linha gerada da transformação hough, ela forneceria um par rho e theta. Se esses valores estivessem dentro de, digamos 5% de um par de valores na tabela, eles seriam descartados; se estivessem fora desses 5%, uma nova entrada era adicionada à tabela.
Você pode então fazer análises de linhas paralelas ou distâncias entre linhas com muito mais facilidade.
Espero que isto ajude.
fonte
Um grupo de estudantes na minha universidade demonstrou recentemente um aplicativo para iPhone (e um aplicativo Python OpenCV) que eles escreveram para fazer exatamente isso. Pelo que me lembro, as etapas eram mais ou menos assim:
Isso pareceu funcionar muito bem e eles conseguiram tirar uma foto de um pedaço de papel ou livro, realizar a detecção de cantos e, em seguida, mapear o documento na imagem em um plano quase em tempo real (havia uma única função OpenCV para executar o mapeamento). Não havia OCR quando o vi funcionando.
fonte
Aqui está o que eu descobri depois de um pouco de experimentação:
Não é perfeito, mas pelo menos funciona para todas as amostras:
fonte
for line in lines[0]: cv2.line(edges, (line[0], line[1]), (line[2], line[3]), (255,0,0), 2, 8) # finding contours contours, _ = cv2.findContours(edges.copy(), cv.CV_RETR_EXTERNAL, cv.CV_CHAIN_APPROX_TC89_KCOS) contours = filter(lambda cont: cv2.arcLength(cont, False) > 100, contours) contours = filter(lambda cont: cv2.contourArea(cont) > 10000, contours)
Em vez de começar a partir da detecção de bordas, você pode usar a detecção de cantos.
O Marvin Framework fornece uma implementação do algoritmo Moravec para esse propósito. Você pode encontrar os cantos dos papéis como ponto de partida. Abaixo a saída do algoritmo de Moravec:
fonte
Você também pode usar MSER (regiões extremais estáveis ao máximo) sobre o resultado do operador Sobel para encontrar as regiões estáveis da imagem. Para cada região retornada pelo MSER, você pode aplicar o casco convexo e a aproximação poli para obter alguns como este:
Mas este tipo de detecção é útil para detecção ao vivo mais do que uma única imagem que nem sempre retorna o melhor resultado.
fonte
Após a detecção da borda, use a Transformação de Hough. Em seguida, coloque esses pontos em uma SVM (máquina de suporte vetorial) com seus rótulos, se os exemplos tiverem linhas suaves sobre eles, o SVM não terá dificuldade em dividir as partes necessárias do exemplo e outras partes. Meu conselho sobre SVM, coloque um parâmetro como conectividade e comprimento. Ou seja, se os pontos forem conectados e longos, eles provavelmente serão uma linha do recibo. Então, você pode eliminar todos os outros pontos.
fonte
Aqui você tem o código de @Vanuan usando C ++:
fonte
std::vector<cv::Vec4i> lines;
é declarado em um escopo global em meu projeto.Converter para espaço de laboratório
Use kmeans segmento 2 cluster
fonte