113 votes

Algorithme pour détecter les coins d'une feuille de papier en photo

Quelle est la meilleure façon de détecter les coins d'une facture/reçu/la feuille de papier dans une photo? C'est pour être utilisées pour la correction de la perspective, avant de ROC.

Mon approche actuelle a été:

RVB > Gris > Futé Détection de Bord avec seuillage > Dilater(1) > Supprimer les petits objets(6) > effacer la frontière des objets > choisir des grandes blog basé sur le Convexe de la Zone. > [angle de détection - Pas mises en œuvre]

Je ne peux pas aider mais pense qu'il doit être plus robuste 'intelligent'/approche statistique pour gérer ce type de segmentation. Je n'ai pas beaucoup d'exemples, mais je pourrais probablement obtenir 100 images.

Contexte plus large:

Je suis l'aide de matlab pour réaliser des prototypes, et de la planification à mettre en œuvre le système dans OpenCV et Tesserect-OCR. C'est la première d'un certain nombre de problèmes de traitement de l'image j'ai besoin pour résoudre pour cette application spécifique. Je suis donc à la recherche de rouler ma propre solution et re-me familiariser avec les algorithmes de traitement d'image.

Voici quelques exemples de l'image que je voudrais que l'algorithme de manche: Si vous souhaitez relever le défi de la grande image http://madteckhead.com/tmp

case 1case 2case 3case 4

Dans le meilleur des cas, cela donne:

case 1 - cannycase 1 - post cannycase 1 - largest blog

Cependant, il ne parvient pas facilement à d'autres cas:

case 2 - cannycase 2 - post cannycase 2 - largest blog

Merci d'avance pour toutes les grandes idées! J'aime TELLEMENT!

EDIT: Hough Transformer Progrès

Q: Quel algorithme de cluster sur le hough lignes pour trouver des coins? Suivant les conseils de réponses, j'ai pu utiliser la Transformation de Hough, ramasser les lignes, et de les filtrer. Ma démarche actuelle est plutôt rudimentaire. J'ai fait l'hypothèse que la facture sera toujours moins de 15deg hors de l'alignement avec l'image. Je me retrouve avec des résultats raisonnables pour des lignes si c'est le cas (voir ci-dessous). Mais je ne suis pas entièrement sûr d'un algorithme convenable pour regrouper les lignes (ou voix) pour extrapoler pour les coins. Le Hough lignes ne sont pas continues. Et dans le bruit des images, il peut y avoir des lignes parallèles de sorte que certains de la forme ou de la distance de la ligne de l'origine des mesures sont nécessaires. Des idées?

case 1case 2case 3case 4

31voto

Daniel Crowley Points 106

Salut, je suis l'ami de Martin, qui a travaillé sur cette plus tôt cette année. C'était mon premier codage projet, et un peu terminé un peu de rush, de sorte que le code a besoin de quelques euh...le décodage... Je vais vous donner quelques conseils de ce que j'ai vu que tu fais déjà, et puis trier mon code sur mon jour de congé demain.

Premier conseil, Opencv et python est génial, déplacer dès que possible. :D

Au lieu de supprimer les petits objets et de bruit ou de, baisser le savant contraintes, donc il accepte plus les bords, et puis trouver le plus grand contour fermé (dans opencv utilisation findcontour() avec quelques paramètres simples, je crois que j'ai utilisé CV_RETR_LIST). pourrait encore du mal quand c'est sur un morceau de papier blanc, mais il était certainement fournir de meilleurs résultats.

Pour le Houghline2() Transformer les, essayez avec l'CV_HOUGH_STANDARD par opposition à la CV_HOUGH_PROBABILISTIC, Ça va donner rho et les valeurs de thêta, la définition de la ligne en coordonnée polaire, et puis vous pouvez regrouper les lignes à l'intérieur d'une certaine tolérance pour ceux.

Mon groupement travaillé comme une table, pour chaque ligne de sortie de la transformation de hough ça donnerait un rho et thêta paire, si ces valeurs étaient à l'intérieur, de 5% d'une paire de valeurs dans le tableau, elles ont été rejetées, si ils étaient à l'extérieur que de 5%, une nouvelle entrée sera ajoutée à la table.

Vous pourrez alors faire une analyse des lignes parallèles ou de la distance entre les lignes beaucoup plus facilement.

Espérons que cela aide, Je vais prendre un peu de code demain.

22voto

Vanuan Points 4751

Voici ce que j'ai trouvé après un peu d'expérimentation:

 import cv, cv2, numpy as np
import sys

def get_new(old):
    new = np.ones(old.shape, np.uint8)
    cv2.bitwise_not(new,new)
    return new

if __name__ == '__main__':
    orig = cv2.imread(sys.argv[1])

    # these constants are carefully picked
    MORPH = 9
    CANNY = 84
    HOUGH = 25

    img = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)
    cv2.GaussianBlur(img, (3,3), 0, img)


    # this is to recognize white on white
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(MORPH,MORPH))
    dilated = cv2.dilate(img, kernel)

    edges = cv2.Canny(dilated, 0, CANNY, apertureSize=3)

    lines = cv2.HoughLinesP(edges, 1,  3.14/180, HOUGH)
    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)

    # simplify contours down to polygons
    rects = []
    for cont in contours:
        rect = cv2.approxPolyDP(cont, 40, True).copy().reshape(-1, 2)
        rects.append(rect)

    # that's basically it
    cv2.drawContours(orig, rects,-1,(0,255,0),1)

    # show only contours
    new = get_new(img)
    cv2.drawContours(new, rects,-1,(0,255,0),1)
    cv2.GaussianBlur(new, (9,9), 0, new)
    new = cv2.Canny(new, 0, CANNY, apertureSize=3)

    cv2.namedWindow('result', cv2.WINDOW_NORMAL)
    cv2.imshow('result', orig)
    cv2.waitKey(0)
    cv2.imshow('result', dilated)
    cv2.waitKey(0)
    cv2.imshow('result', edges)
    cv2.waitKey(0)
    cv2.imshow('result', new)
    cv2.waitKey(0)

    cv2.destroyAllWindows()
 

Pas parfait, mais fonctionne au moins pour tous les échantillons:

1234

20voto

Martin Foot Points 1617

Un groupe d'étudiants de mon université a récemment démontré qu'une application iPhone (et python OpenCV app) de ce qu'ils avaient écrit pour faire exactement cela. Que je me souvienne, les étapes ont été quelque chose comme ceci:

  • Filtre médian pour supprimer complètement le texte sur le papier (ce texte écrit à la main sur du papier blanc avec une assez bonne de l'éclairage et peut ne pas fonctionner avec le texte imprimé, ça a très bien fonctionné). La raison en était qu'il fait de l'angle de détection beaucoup plus facile.
  • Hough Transformer pour les lignes
  • Trouver les pics dans la Transformation de Hough accumulateur de l'espace et de tirer chaque ligne à travers l'ensemble de l'image.
  • Analyser les lignes et supprimer ceux qui sont très proches les uns des autres et sont au même angle (cluster les lignes en une seule). Cela est nécessaire parce que la Transformation de Hough n'est pas parfait car il travaille dans un échantillon injecté de l'espace.
  • Trouvez les paires de lignes à peu près parallèles et qui se croisent et d'autres paires de voir les lignes de forme carré.

Cela semblait fonctionner assez bien, et ils ont été en mesure de prendre une photo d'un morceau de papier ou d'un livre, d'effectuer le coin de détection et puis la carte du document dans l'image sur une surface plane en quasi temps réel (il n'y a qu'un seul OpenCV fonction pour effectuer la cartographie). Il n'y a pas de reconnaissance optique de caractères lorsque je l'ai vu travailler.

10voto

Gabriel Archanjo Points 1673

Au lieu de partir de la détection de bord, vous pouvez utiliser la détection de coin.

Marvin Framework fournit une implémentation de l'algorithme Moravec à cet effet. Vous pouvez trouver les coins des documents comme point de départ. Ci-dessous la sortie de l'algorithme de Moravec:

entrez la description de l'image ici

3voto

Hephaestus Points 28

Après la détection des contours, utilisez Hough Transform. Ensuite, placez ces points dans une SVM (machine à vecteurs de support) avec leurs étiquettes. Si les exemples comportent des lignes lisses, SVM n'aura aucune difficulté à diviser les parties nécessaires de l’exemple et les autres. Mon conseil sur SVM, mettez un paramètre comme la connectivité et la longueur. Autrement dit, si les points sont connectés et longs, ils constitueront probablement une ligne du reçu. Ensuite, vous pouvez éliminer tous les autres points.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X