web-dev-qa-db-fra.com

Correction automatique de la perspective OpenCV

J'essaie d'implémenter la correction automatique de perspective dans mon programme iOS et lorsque j'utilise l'image de test que j'ai trouvée sur le tutoriel, tout fonctionne comme prévu. Mais quand je prends une photo, je retrouve un résultat étrange.

J'utilise le code trouvé dans ce tutoriel

Quand je lui donne une image qui ressemble à ceci:

enter image description here

J'obtiens ceci comme résultat:

enter image description here

Voici ce que dst me donne qui pourrait aider.

enter image description here

J'utilise ceci pour appeler la méthode qui contient le code.

quadSegmentation(Img, bw, dst, quad);

Quelqu'un peut-il me dire quand je reçois autant de lignes vertes par rapport au tutoriel? Et comment pourrais-je résoudre ce problème et recadrer correctement l'image pour ne contenir que la carte?

26
Clip

Pour transformer la perspective dont vous avez besoin,

points source-> Coordonnées des sommets quadrangulaires dans l'image source.

points de destination-> Coordonnées des sommets quadrangulaires correspondants dans l'image de destination.

Ici, nous allons calculer ces points par processus de contour.

Calculer les coordonnées des sommets quadrangulaires dans l'image source

  • Vous obtiendrez votre carte en tant que contour en flou, seuillage, puis trouvez le contour, trouvez le plus grand contour, etc.
  • Après avoir trouvé le plus grand contour, calculez simplement approximativement une courbe polygonale , ici vous devriez obtenir 4 points qui représentent les coins de votre carte. Vous pouvez ajuster le paramètre epsilon pour faire 4 coordonnées.

enter image description here

Calculer les coordonnées des sommets quadrangulaires correspondants dans l'image de destination

  • Cela peut être facilement découvert en calculant le rectangle englobant pour le plus grand contour.

enter image description here

Dans l'image ci-dessous, le rectangle rouge représente les points source et le vert pour les points de destination.

enter image description here

Ajustez l'ordre des coordonnées et appliquez la transformation Perspective

Voir le résultat final

enter image description here

Code

 Mat src=imread("card.jpg");
 Mat thr;
 cvtColor(src,thr,CV_BGR2GRAY);
 threshold( thr, thr, 70, 255,CV_THRESH_BINARY );

 vector< vector <Point> > contours; // Vector for storing contour
 vector< Vec4i > hierarchy;
 int largest_contour_index=0;
 int largest_area=0;

 Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0)); //create destination image
 findContours( thr.clone(), contours, hierarchy,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
 for( int i = 0; i< contours.size(); i++ ){
    double a=contourArea( contours[i],false);  //  Find the area of contour
    if(a>largest_area){
    largest_area=a;
    largest_contour_index=i;                //Store the index of largest contour
    }
 }

 drawContours( dst,contours, largest_contour_index, Scalar(255,255,255),CV_FILLED, 8, hierarchy );
 vector<vector<Point> > contours_poly(1);
 approxPolyDP( Mat(contours[largest_contour_index]), contours_poly[0],5, true );
 Rect boundRect=boundingRect(contours[largest_contour_index]);
 if(contours_poly[0].size()==4){
    std::vector<Point2f> quad_pts;
    std::vector<Point2f> squre_pts;
    quad_pts.Push_back(Point2f(contours_poly[0][0].x,contours_poly[0][0].y));
    quad_pts.Push_back(Point2f(contours_poly[0][1].x,contours_poly[0][1].y));
    quad_pts.Push_back(Point2f(contours_poly[0][3].x,contours_poly[0][3].y));
    quad_pts.Push_back(Point2f(contours_poly[0][2].x,contours_poly[0][2].y));
    squre_pts.Push_back(Point2f(boundRect.x,boundRect.y));
    squre_pts.Push_back(Point2f(boundRect.x,boundRect.y+boundRect.height));
    squre_pts.Push_back(Point2f(boundRect.x+boundRect.width,boundRect.y));
    squre_pts.Push_back(Point2f(boundRect.x+boundRect.width,boundRect.y+boundRect.height));

    Mat transmtx = getPerspectiveTransform(quad_pts,squre_pts);
    Mat transformed = Mat::zeros(src.rows, src.cols, CV_8UC3);
    warpPerspective(src, transformed, transmtx, src.size());
    Point P1=contours_poly[0][0];
    Point P2=contours_poly[0][1];
    Point P3=contours_poly[0][2];
    Point P4=contours_poly[0][3];


    line(src,P1,P2, Scalar(0,0,255),1,CV_AA,0);
    line(src,P2,P3, Scalar(0,0,255),1,CV_AA,0);
    line(src,P3,P4, Scalar(0,0,255),1,CV_AA,0);
    line(src,P4,P1, Scalar(0,0,255),1,CV_AA,0);
    rectangle(src,boundRect,Scalar(0,255,0),1,8,0);
    rectangle(transformed,boundRect,Scalar(0,255,0),1,8,0);

    imshow("quadrilateral", transformed);
    imshow("thr",thr);
    imshow("dst",dst);
    imshow("src",src);
    imwrite("result1.jpg",dst);
    imwrite("result2.jpg",src);
    imwrite("result3.jpg",transformed);
    waitKey();
   }
   else
    cout<<"Make sure that your are getting 4 corner using approxPolyDP..."<<endl;
37
Haris

teethe Cela se produit généralement lorsque vous comptez sur du code de quelqu'un d'autre pour résoudre votre problème particulier au lieu d'adopter le code. Regardez les étapes de traitement et aussi la différence entre leur et votre image (c'est une bonne idée en passant de commencer par leur image et de vous assurer que le code fonctionne):

  1. Obtenez la carte Edge. - fonctionnera probablement car vos bords sont fins
  2. Détectez les lignes avec la transformation de Hough. - échec car vous avez des lignes non seulement sur le contour mais aussi à l'intérieur de votre carte. Attendez-vous donc à beaucoup de fausses lignes d'alarme
  3. Obtenez les coins en trouvant des intersections entre les lignes. - échec pour la raison mentionnée ci-dessus
  4. Vérifiez si la courbe polygonale approximative a 4 sommets. - échec
  5. Déterminez les coins supérieur gauche, inférieur gauche, supérieur droit et inférieur droit. - échec
  6. Appliquez la transformation de perspective. - échec complet

Pour résoudre votre problème, vous devez vous assurer que seules les lignes de la périphérie sont extraites. Si vous avez toujours un fond sombre, vous pouvez utiliser ce fait pour supprimer les lignes avec d'autres contrastes/polarités. Vous pouvez également extraire toutes les lignes, puis sélectionner celles qui sont les plus proches de la limite de l'image (si votre arrière-plan n'a pas de lignes).

6
Vlad