2017-09-14 7 views
1

J'essaie de calibrer une caméra avec un objectif fisheye. J'ai donc utilisé le module objectif fisheye, mais continue à obtenir des résultats étranges, peu importe les paramètres de distorsion que je fixe. Ceci est l'image d'entrée que j'utilise: https://i.imgur.com/apBuAwF.pngComment calibrer correctement mon appareil photo avec un objectif grand angle en utilisant openCV?

où les cercles rouges indiquent les coins que j'utilise pour calibrer mon appareil photo.

C'est le meilleur que je pouvais obtenir, sortie: https://imgur.com/a/XeXk5

Je ne en sais pas par cœur ce que les dimensions du capteur de la caméra sont, mais en fonction de la distance focale en pixels qui est calculée dans ma matrice nitrinsic , Je déduis que ma taille de capteur est d'environ 3,3 mm (en supposant que ma distance focale physique est de 1,8 mm), ce qui me semble réaliste. Pourtant, quand je ne déforme pas mon image d'entrée, j'ai un non-sens. Quelqu'un pourrait-il me dire ce que je fais peut-être incorrectement?

les matrices et efficace étant sortie par l'étalonnage:

K:[263.7291703200009, 0, 395.1618975493187; 
0, 144.3800397321767, 188.9308218101271; 
0, 0, 1] 

D:[0, 0, 0, 0] 

rms: 9.27628 

mon code:

#include <opencv2/opencv.hpp> 
#include "opencv2/core.hpp" 
#include "opencv2/imgcodecs.hpp" 
#include "opencv2/imgproc.hpp" 
#include "opencv2/highgui.hpp" 
#include "opencv2/ccalib/omnidir.hpp" 

using namespace std; 
using namespace cv; 

vector<vector<Point2d> > points2D; 
vector<vector<Point3d> > objectPoints; 

Mat src; 

//so that I don't have to select them manually every time 
void initializePoints2D() 
{ 
    points2D[0].push_back(Point2d(234, 128)); 
    points2D[0].push_back(Point2d(300, 124)); 
    points2D[0].push_back(Point2d(381, 126)); 
    points2D[0].push_back(Point2d(460, 127)); 
    points2D[0].push_back(Point2d(529, 137)); 
    points2D[0].push_back(Point2d(207, 147)); 
    points2D[0].push_back(Point2d(280, 147)); 
    points2D[0].push_back(Point2d(379, 146)); 
    points2D[0].push_back(Point2d(478, 153)); 
    points2D[0].push_back(Point2d(551, 165)); 
    points2D[0].push_back(Point2d(175, 180)); 
    points2D[0].push_back(Point2d(254, 182)); 
    points2D[0].push_back(Point2d(377, 185)); 
    points2D[0].push_back(Point2d(502, 191)); 
    points2D[0].push_back(Point2d(586, 191)); 
    points2D[0].push_back(Point2d(136, 223)); 
    points2D[0].push_back(Point2d(216, 239)); 
    points2D[0].push_back(Point2d(373, 253)); 
    points2D[0].push_back(Point2d(534, 248)); 
    points2D[0].push_back(Point2d(624, 239)); 
    points2D[0].push_back(Point2d(97, 281)); 
    points2D[0].push_back(Point2d(175, 322)); 
    points2D[0].push_back(Point2d(370, 371)); 
    points2D[0].push_back(Point2d(578, 339)); 
    points2D[0].push_back(Point2d(662, 298)); 


    for(int j=0; j<25;j++) 
    { 
     circle(src, points2D[0].at(j), 5, Scalar(0, 0, 255), 1, 8, 0); 
    } 

    imshow("src with circles", src); 
    waitKey(0); 
} 

int main(int argc, char** argv) 
{ 
    Mat srcSaved; 

    src = imread("images/frontCar.png"); 
    resize(src, src, Size(), 0.5, 0.5); 
    src.copyTo(srcSaved); 

    vector<Point3d> objectPointsRow; 
    vector<Point2d> points2DRow; 
    objectPoints.push_back(objectPointsRow); 
    points2D.push_back(points2DRow); 

    for(int i=0; i<5;i++) 
    { 

     for(int j=0; j<5;j++) 
     { 
      objectPoints[0].push_back(Point3d(5*j,5*i,1));   
     } 
    } 

    initializePoints2D(); 
    cv::Matx33d K; 
    cv::Vec4d D; 
    std::vector<cv::Vec3d> rvec; 
    std::vector<cv::Vec3d> tvec; 


    int flag = 0; 
    flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; 
    flag |= cv::fisheye::CALIB_CHECK_COND; 
    flag |= cv::fisheye::CALIB_FIX_SKEW; 
    flag |= cv::fisheye::CALIB_FIX_K1; 
    flag |= cv::fisheye::CALIB_FIX_K2; 
    flag |= cv::fisheye::CALIB_FIX_K3; 
    flag |= cv::fisheye::CALIB_FIX_K4; 


    double rms =cv::fisheye::calibrate(
objectPoints, points2D, src.size(), 
K, D, rvec, tvec, flag, cv::TermCriteria(3, 20, 1e-6)  
); 

    Mat output; 
    cerr<<"K:"<<K<<endl; 
    cerr<<"D:"<<D<<endl; 
    cv::fisheye::undistortImage(srcSaved, output, K, D); 
    cerr<<"rms: "<<rms<<endl; 
    imshow("output", output); 
    waitKey(0); 

    cerr<<"image .size: "<<srcSaved.size()<<endl; 

} 

Si quelqu'un a une idée, vous pouvez soit partager un peu de code en Python soit en C++. C'est comme tu veux.

EDIT:

Comme vous pouvez avoir un avis que je n'utilise un damier noir et blanc pour l'étalonnage, mais les coins de tuiles constituant mon tapis. À la fin de la journée, l'objectif - je pense - est d'obtenir des coordonnées de coin qui représentent des échantillons des rayons de distorsion. Le tapis est dans une certaine mesure identique au damier, la seule différence - encore une fois je pense - est le fait que vous avez moins de bords à haute fréquence à ceux par exemple des coins sur le tapis que sur un damier noir et blanc.

Je sais que le nombre de photos est très limité, c'est-à-dire seulement 1. Je m'attends à ce que l'image ne soit pas déformée dans une certaine mesure, mais je m'attends aussi à ce que le décalage soit très bien fait. Mais dans ce cas, la sortie de l'image ressemble à un non-sens total.

Je fini par utiliser cette image avec un jeu d'échecs: https://imgur.com/a/WlLBR fournis par ce site: https://sites.google.com/site/scarabotix/ocamcalib-toolbox/ocamcalib-toolbox-download-page Mais les résultats sont encore très pauvres: des lignes diagonales comme l'autre image de sortie I posté.

Merci

+0

C'est comme ça que c'est calibré. – karlphillip

+0

@karlphillip Je n'ai actuellement aucun accès physique à la caméra. Aussi basé sur ce que j'ai trouvé en ligne. Il n'est pas obligatoire d'utiliser un échiquier. – privetDruzia

+0

Oui, je voulais dire que c'était la façon la plus simple de le faire. Bonne chance alors! – karlphillip

Répondre

1

Votre premier problème est que vous utilisez uniquement une image. Même si vous possédez un appareil sténopé idéal sans distorsion, vous ne pourrez pas estimer les intrinsèques à partir d'une seule image de points coplanaires. Une image de points co-planaires ne vous donne pas assez de contraintes pour résoudre les intrinsèques.

Vous avez besoin d'au moins deux images à différentes orientations 3D, ou d'une plate-forme d'étalonnage 3D, où les points ne sont pas coplanaires. Bien sûr, en pratique, vous avez besoin d'au moins 20 images pour un étalonnage précis.

Votre deuxième problème est que vous utilisez un tapis comme damier. Vous devez être capable de détecter les points de l'image avec une précision sub-pixel. Les petites erreurs de localisation entraînent de grandes erreurs dans les paramètres de caméra estimés. Je doute sérieusement que vous puissiez détecter les coins des carrés de votre tapis avec une précision raisonnable.En fait, vous ne pouvez même pas mesurer très précisément les emplacements des points sur le tapis, car il est flou.

Bonne chance! Vous ne pouvez pas simplement imprimer un papier A4 avec l'image?

+0

merci beaucoup pour votre réponse, je vais regarder dans cela! Cela vous dérangerait-il d'élaborer sur la précision du sous-pixel? AFAIK les coins de la moquette ou du damier sont détectés dans l'espace d'image par exemple par un détecteur d'angle de harris, Whcih signifie que les emplacements dans les pixels des coins retournés par cette fonction sont des valeurs entières. – privetDruzia

+0

J'ai fini par utiliser cette image avec un échiquier: https://imgur.com/a/WlLBR Ce que j'ai trouvé sur ce site: https://sites.google.com/site/scarabotix/ocamcalib-toolbox/ocamcalib -toolbox-download-page Mais les résultats sont encore très mauvais: des lignes diagonales comme l'autre image de sortie que j'ai affichée. – privetDruzia

+0

@privetDruzia, oui, l'algorithme de Harris lui-même vous donne des coins aux coordonnées entières. Ensuite, vous prenez le voisinage de pixels centré au coin, et adaptez une fonction quadratique 2D à la fonction Harris dans ce voisinage. Ensuite, vous calculez le minimum du paraboloïde, et utilisez cela comme l'emplacement raffiné du coin. La plupart des fonctions qui intéressent la détection de points le feront pour vous. – Dima