J'essaie de faire de l'OCR à partir de cet exemple de jouet de reçus. Utilisation de Python 2.7 et OpenCV 3.1.
Niveaux de gris + Flou + Détection de bord externe + Segmentation de chaque zone dans les reçus (par exemple "Catégorie" pour voir plus tard laquelle est marquée -dans ce cas en espèces-).
Je trouve compliqué lorsque l'image est "biaisée" de pouvoir transformer correctement puis segmenter "automatiquement" chaque segment des reçus.
Exemple:
Toute suggestion?
Le code ci-dessous est un exemple à obtenir jusqu'à la détection des contours, mais lorsque le reçu est comme la première image. Mon problème n'est pas l'image au texte. Est le prétraitement de l'image.
Toute aide plus qu'appréciée! :)
import os;
os.chdir() # Put your own directory
import cv2
import numpy as np
image = cv2.imread("Rent-Receipt.jpg", cv2.IMREAD_GRAYSCALE)
blurred = cv2.GaussianBlur(image, (5, 5), 0)
#blurred = cv2.bilateralFilter(gray,9,75,75)
# apply Canny Edge Detection
edged = cv2.Canny(blurred, 0, 20)
#Find external contour
(_,contours, _) = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
Un excellent tutoriel sur la première étape que vous avez décrite est disponible sur pyimagesearch (et ils ont de grands tutoriels en général)
En bref, comme décrit par Ella, vous devez utiliser cv2.CHAIN_APPROX_SIMPLE
. Une méthode légèrement plus robuste consisterait à utiliser cv2.RETR_LIST
au lieu de cv2.RETR_EXTERNAL
, puis triez les zones, car cela devrait fonctionner correctement même dans les arrière-plans blancs/si la page inscrit une forme plus grande en arrière-plan, etc.
Pour en venir à la deuxième partie de votre question, un bon moyen de segmenter les caractères serait d'utiliser l'extracteur de région extrême extrêmement stable disponible dans OpenCV. Une implémentation complète dans CPP est disponible ici dans un projet que j'aidais récemment. L'implémentation Python irait dans le sens de (Le code ci-dessous fonctionne pour OpenCV 3.0+. Pour la syntaxe OpenCV 2.x, vérifiez-la en ligne)
import cv2
img = cv2.imread('test.jpg')
mser = cv2.MSER_create()
#Resize the image so that MSER can work better
img = cv2.resize(img, (img.shape[1]*2, img.shape[0]*2))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
regions = mser.detectRegions(gray)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions[0]]
cv2.polylines(vis, hulls, 1, (0,255,0))
cv2.namedWindow('img', 0)
cv2.imshow('img', vis)
while(cv2.waitKey()!=ord('q')):
continue
cv2.destroyAllWindows()
Cela donne la sortie comme
Maintenant, pour éliminer les faux positifs, vous pouvez simplement parcourir les points dans les coques et calculer le périmètre (somme de la distance entre tous les points adjacents dans les coques [i], où coques [i] est une liste de tous les points dans une coque convexe) ). Si le périmètre est trop grand, classifiez-le comme n'étant pas un caractère.
Les lignes de diagnostic à travers l'image viennent car la bordure de l'image est noire. qui peut simplement être supprimé en ajoutant la ligne suivante dès que l'image est lue (sous la ligne 7)
img = img[5:-5,5:-5,:]
ce qui donne la sortie
L'option sur le dessus de ma tête nécessite l'extraction des 4 coins de l'image asymétrique. Pour ce faire, utilisez cv2.CHAIN_APPROX_SIMPLE
au lieu de cv2.CHAIN_APPROX_NONE
lors de la recherche des contours. Ensuite, vous pouvez utiliser cv2.approxPolyDP
et j'espère rester avec les 4 coins du reçu (si toutes vos images sont comme celle-ci, il n'y a aucune raison pour que cela ne fonctionne pas).
Utilisez maintenant cv2.findHomography
et cv2.wardPerspective
pour rectifier l'image selon les points source qui sont les 4 points extraits de l'image asymétrique et les points de destination qui doivent former un rectangle, par exemple les dimensions complètes de l'image.
Ici vous pouvez trouver des exemples de code et plus d'informations: OpenCV-Geometric Transformations of Images
Cette réponse peut également être utile - SO - Détecter et corriger le biais de texte
EDIT: correction de la deuxième chaîne d'environ cv2.CHAIN_APPROX_NONE
.