web-dev-qa-db-fra.com

Détection de ligne horizontale avec OpenCV

J'essaie de trouver des lignes horizontales et verticales à partir d'une image issue d'un "document". Les documents sont des pages numérisées de contrats et les lignes ressemblent donc à ce que vous verriez dans un tableau ou dans un bloc de contrat.

J'ai essayé OpenCV pour le travail. L'implémentation de la transformation Hough dans OpenCV semblait utile pour le travail, mais je n'ai trouvé aucune combinaison de paramètres qui lui permettrait de trouver proprement les lignes verticales et horizontales. J'ai essayé avec et sans détection Edge. Pas de chance. Si quelqu'un a fait quelque chose de similaire, je suis curieux de savoir comment.

Voir ici une image de mes expérimentations avant et après avec HoughP dans OpenCV. C'est le mieux que je puisse faire, http://dl.dropbox.com/u/3787481/Untitled%201.png

Alors maintenant, je me demande s'il existe un autre type de transformation que je pourrais utiliser qui me permettrait de trouver de manière fiable des lignes horizontales et verticales (et de préférence des lignes en pointillés également).

Je sais que ce problème peut être résolu car j'ai des outils Nuance et ABBYY OCR qui peuvent à la fois extraire de manière fiable des lignes horizontales et verticales et me renvoyer la boîte englobante des lignes.

Merci! Patrick.

22
Patrick Collins

Avez-vous vu un exemple de code de la documentation de la fonction HoughLinesP ?

Je pense que vous pouvez l'utiliser comme point de départ pour votre algorithme. Pour choisir des lignes horizontales et verticales, il vous suffit de filtrer les autres lignes par angle de ligne.

MISE À JOUR:

Comme je vois, vous devez trouver non pas les lignes mais les bords horizontaux et verticaux sur la page. Pour cette tâche, vous devez combiner plusieurs étapes de traitement pour obtenir de bons résultats.

Pour votre image, je peux obtenir de bons résultats en combinant la détection Canny Edge avec HoughLinesP. Voici mon code (j'ai utilisé python, mais je pense que vous voyez l'idée):

img = cv2.imread("C:/temp/1.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 80, 120)
lines = cv2.HoughLinesP(edges, 1, math.pi/2, 2, None, 30, 1);
for line in lines[0]:
    pt1 = (line[0],line[1])
    pt2 = (line[2],line[3])
    cv2.line(img, pt1, pt2, (0,0,255), 3)
cv2.imwrite("C:/temp/2.png", img)

Le résultat ressemble à:

30
Andrey Kamaev

Si vous voulez juste les "lignes" et non les "segments de ligne", j'éviterais d'utiliser Canny, Hough, FindContours ou toute autre fonction de ce type au cas où vous voudriez plus de vitesse dans votre code. Si vos images ne sont pas tournées et que ce que vous voulez trouver est toujours vertical ou horizontal, j'utiliserais simplement cv :: Sobel (un pour vertical et un autre pour horizontal) et créer des tableaux d'accumulation pour les colonnes et les lignes. Ensuite, vous pouvez rechercher des maxima dans ces accumulations ou profils, par exemple en définissant un seuil, et vous connaîtrez la ligne ou la colonne dans laquelle il y a des lignes de bord verticales ou horizontales.

9
marcos.nieto

Ne convertissez pas le RVB en niveaux de gris. Parfois, différentes couleurs en RVB peuvent être fusionnées à la même valeur de niveaux de gris, de sorte qu'il peut manquer certains contours. Vous devez analyser chacun des canaux RVB séparément.

6
fzec

Vous pourriez envisager de quitter la détection de ligne Hough car cette méthode recherche les lignes "globales", pas nécessairement les segments de ligne. J'ai récemment implémenté une application qui identifiait les "parallélogrammes" - essentiellement des carrés qui pouvaient être tournés et la perspective raccourcie en raison de l'angle de vue. Vous pourriez envisager quelque chose de similaire. Mon pipeline était:

  1. Conversion de RVB en niveaux de gris (cvCvtColor)
  2. Lisse (cvSmooth)
  3. Seuil (cvThreshold)
  4. Détecter les bords (cvCanny)
  5. Rechercher des contours (cvFindContours)
  6. Contours approximatifs avec des caractéristiques linéaires (cvApproxPoly)

Dans votre application, la liste de contours résultante sera probablement grande (en fonction de l '"agressivité" du lissage et de l'amélioration des fonctionnalités du détecteur Canny Edge. Vous pouvez élaguer cette liste par une variété de paramètres: nombre de points renvoyés par le Finder de contours , zone du contour (cvContourArea), etc. D'après mon expérience, je m'attendrais à ce que les lignes "valides" de votre application aient des propriétés de zone et de nombre de sommets bien définies. De plus, vous pouvez filtrer les contours en fonction de la distance entre les extrémités. points, angle défini par la ligne reliant les extrémités, etc.

Selon le "temps" CPU dont vous disposez, vous pouvez toujours coupler l'algorithme Hough avec un algorithme comme celui ci-dessus pour identifier de manière robuste les lignes horizontales et verticales.

5
Throwback1986