Quelle est la meilleure façon de détecter les coins d'une facture/reçu/feuille de papier dans une photo? Ceci doit être utilisé pour une correction de perspective ultérieure, avant l'OCR.
RVB> Gris> Détection Canny Edge avec seuillage> Dilater (1)> Supprimer les petits objets (6)> effacer les objets internes> choisir un blog large basé sur la zone convexe. > [détection de coin - Non implémenté]
Je ne peux pas m'empêcher de penser qu'il doit y avoir une approche "intelligente"/statistique plus robuste pour gérer ce type de segmentation. Je n'ai pas beaucoup d'exemples de formation, mais je pourrais probablement obtenir 100 images ensemble.
J'utilise matlab pour prototyper et je prévois d'implémenter le système dans OpenCV et Tesserect-OCR. Il s'agit du premier d'un certain nombre de problèmes de traitement d'image que je dois résoudre pour cette application spécifique. Je cherche donc à lancer ma propre solution et à me familiariser avec les algorithmes de traitement d'image.
Voici quelques exemples d'images que j'aimerais que l'algorithme gère: Si vous souhaitez relever le défi, les grandes images sont à http://madteckhead.com/tmp
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
(source: madteckhead.com )
Merci d'avance pour toutes les bonnes idées! J'aime tellement!
Q: Quel algorithme regrouperait les lignes de Hough pour trouver des coins? En suivant les conseils des réponses, j'ai pu utiliser la transformation de Hough, choisir des lignes et les filtrer. Mon approche actuelle est plutôt grossière. J'ai supposé que la facture sera toujours inférieure à 15 degrés par rapport à l'image. Je me retrouve avec des résultats raisonnables pour les lignes si c'est le cas (voir ci-dessous). Mais je ne suis pas entièrement sûr d'un algorithme approprié pour regrouper les lignes (ou voter) pour extrapoler pour les coins. Les lignes de Hough ne sont pas continues. Et dans les images bruyantes, il peut y avoir des lignes parallèles, donc une certaine forme ou distance par rapport à la ligne Origine est requise. Des idées?
(source: madteckhead.com )
Je suis l'ami de Martin qui y travaillait plus tôt cette année. Ce fut mon tout premier projet de codage, et s'est un peu terminé en un peu précipité, donc le code a besoin de quelques erreurs ... de décodage ... Je vais donner quelques conseils sur ce que je vous ai déjà vu faire, puis trier mon code sur mon jour de congé demain.
Premier conseil, OpenCV
et python
sont géniaux, passez à eux dès que possible. :RÉ
Au lieu de supprimer les petits objets et/ou le bruit, réduisez les restrictions, afin qu'il accepte plus de bords, puis trouvez le plus grand contour fermé (dans OpenCV, utilisez findcontour()
avec quelques paramètres simples, je pense que j'ai utilisé CV_RETR_LIST
). pourrait encore avoir du mal quand il est sur un morceau de papier blanc, mais fournissait certainement les meilleurs résultats.
Pour la transformation Houghline2()
, essayez avec le CV_HOUGH_STANDARD
Par opposition au CV_HOUGH_PROBABILISTIC
, Cela donnera rho et thêta valeurs, définissant la ligne en coordonnées polaires, puis vous pouvez regrouper les lignes dans une certaine tolérance à celles-ci.
Mon groupement fonctionnait comme une table de recherche, pour chaque ligne produite par la transformation de Hough, cela donnerait une paire rho et thêta. Si ces valeurs étaient à l'intérieur, disons 5% d'une paire de valeurs dans le tableau, elles ont été rejetées, si elles étaient en dehors de ces 5%, une nouvelle entrée a été ajoutée au tableau.
Vous pouvez ensuite analyser beaucoup plus facilement les lignes parallèles ou la distance entre les lignes.
J'espère que cela t'aides.
Un groupe d'étudiants de mon université a récemment présenté une application iPhone (et python OpenCV app) qu'ils avaient écrite pour faire exactement cela. Si je me souviens bien, les étapes étaient quelque chose comme ceci:
Cela semblait assez bien fonctionner et ils ont pu prendre une photo d'un morceau de papier ou d'un livre, effectuer la détection des coins, puis mapper le document dans l'image sur un plan plat presque en temps réel (il y avait une seule fonction OpenCV à effectuer la cartographie). Il n'y avait pas d'OCR quand je l'ai vu fonctionner.
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 __== '__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:
Au lieu de partir de la détection des bords, vous pouvez utiliser la détection des coins.
Marvin Framework fournit une implémentation de l'algorithme de Moravec à cet effet. Vous pourriez trouver les coins des papiers comme point de départ. Ci-dessous la sortie de l'algorithme de Moravec:
Vous pouvez également utiliser MSER (régions extrêmes maximales stables) sur le résultat de l'opérateur Sobel pour trouver les régions stables de l'image. Pour chaque région retournée par MSER, vous pouvez appliquer une coque convexe et une approximation poly pour en obtenir comme ceci:
Mais ce type de détection est utile pour la détection en direct plus qu'une seule image qui ne renvoie pas toujours le meilleur résultat.
Voici le code de @Vanuan en C++:
cv::cvtColor(mat, mat, CV_BGR2GRAY);
cv::GaussianBlur(mat, mat, cv::Size(3,3), 0);
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Point(9,9));
cv::Mat dilated;
cv::dilate(mat, dilated, kernel);
cv::Mat edges;
cv::Canny(dilated, edges, 84, 3);
std::vector<cv::Vec4i> lines;
lines.clear();
cv::HoughLinesP(edges, lines, 1, CV_PI/180, 25);
std::vector<cv::Vec4i>::iterator it = lines.begin();
for(; it!=lines.end(); ++it) {
cv::Vec4i l = *it;
cv::line(edges, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(255,0,0), 2, 8);
}
std::vector< std::vector<cv::Point> > contours;
cv::findContours(edges, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_TC89_KCOS);
std::vector< std::vector<cv::Point> > contoursCleaned;
for (int i=0; i < contours.size(); i++) {
if (cv::arcLength(contours[i], false) > 100)
contoursCleaned.Push_back(contours[i]);
}
std::vector<std::vector<cv::Point> > contoursArea;
for (int i=0; i < contoursCleaned.size(); i++) {
if (cv::contourArea(contoursCleaned[i]) > 10000){
contoursArea.Push_back(contoursCleaned[i]);
}
}
std::vector<std::vector<cv::Point> > contoursDraw (contoursCleaned.size());
for (int i=0; i < contoursArea.size(); i++){
cv::approxPolyDP(Mat(contoursArea[i]), contoursDraw[i], 40, true);
}
Mat drawing = Mat::zeros( mat.size(), CV_8UC3 );
cv::drawContours(drawing, contoursDraw, -1, cv::Scalar(0,255,0),1);
Après la détection des contours, utilisez Hough Transform. Ensuite, placez ces points dans une SVM (machine vectorielle de support) avec leurs étiquettes, si les exemples ont des lignes lisses dessus, SVM n'aura aucune difficulté à diviser les parties nécessaires de l'exemple et d'autres parties. 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 sont susceptibles d'être une ligne de la réception. Ensuite, vous pouvez éliminer tous les autres points.
Ensuite, utilisez des contours ou hough sur l'un des clusters (interne)
Use kmeans segment 2 cluster