3

OpenCV2.3.1とVisualStudio2010(c ++コンソールアプリ)を使用してWebカメラを調整しようとしています。私はこのクラスを使用しています:

class CameraCalibrator{
private:
   std::vector<std::vector<cv::Point3f>> objectPoints;
   std::vector<std::vector<cv::Point2f>> imagePoints;
   //Square Lenght
   float squareLenght;
   //output Matrices
   cv::Mat cameraMatrix; //intrinsic
   cv::Mat distCoeffs;
   //flag to specify how calibration is done
   int flag;
   //used in image undistortion
   cv::Mat map1,map2;
   bool mustInitUndistort;
public:
    CameraCalibrator(): flag(0), squareLenght(36.0), mustInitUndistort(true){};
    int addChessboardPoints(const std::vector<std::string>& filelist,cv::Size& boardSize){
        std::vector<std::string>::const_iterator itImg;
        std::vector<cv::Point2f> imageCorners;
        std::vector<cv::Point3f> objectCorners;
        //initialize the chessboard corners in the chessboard reference frame
        //3d scene points
        for(int i = 0; i<boardSize.height; i++){
            for(int j=0;j<boardSize.width;j++){
                objectCorners.push_back(cv::Point3f(float(i)*squareLenght,float(j)*squareLenght,0.0f));
            }
        }
        //2D Image points:
        cv::Mat image; //to contain chessboard image
        int successes = 0;
        //cv::namedWindow("Chess");
        for(itImg=filelist.begin(); itImg!=filelist.end(); itImg++){
            image = cv::imread(*itImg,0);
            bool found = cv::findChessboardCorners(image, boardSize, imageCorners);
            //cv::drawChessboardCorners(image, boardSize, imageCorners, found);
            //cv::imshow("Chess",image);
            //cv::waitKey(1000);
            cv::cornerSubPix(image, imageCorners, cv::Size(5,5),cv::Size(-1,-1),
                cv::TermCriteria(cv::TermCriteria::MAX_ITER+cv::TermCriteria::EPS,30,0.1));
            //if we have a good board, add it to our data
            if(imageCorners.size() == boardSize.area()){
                addPoints(imageCorners,objectCorners);
                successes++;
            }
        }
        return successes;
    }
    void addPoints(const std::vector<cv::Point2f>& imageCorners,const std::vector<cv::Point3f>& objectCorners){
        //2D image point from one view
        imagePoints.push_back(imageCorners);
        //corresponding 3D scene points
        objectPoints.push_back(objectCorners);
    }
    double calibrate(cv::Size &imageSize){
        mustInitUndistort = true;
        std::vector<cv::Mat> rvecs,tvecs;
        return
            cv::calibrateCamera(objectPoints, //the 3D points
                imagePoints,
                imageSize, 
                cameraMatrix, //output camera matrix
                distCoeffs,
                rvecs,tvecs,
                flag);
    }
    void remap(const cv::Mat &image, cv::Mat &undistorted){
        std::cout << cameraMatrix;
        if(mustInitUndistort){ //called once per calibration
            cv::initUndistortRectifyMap(
                cameraMatrix,
                distCoeffs,
                cv::Mat(),
                cameraMatrix,
                image.size(),
                CV_32FC1,
                map1,map2);
            mustInitUndistort = false;
        }
        //apply mapping functions
        cv::remap(image,undistorted,map1,map2,cv::INTER_LINEAR);
    }
};

解像度640x480のチェス盤の画像を10枚使用しています(キャリブレーションにはこれで十分だと思います)。主な関数は次のようになります。

int main(){
    CameraCalibrator calibrateCam;
    std::vector<std::string> filelist;
    filelist.push_back("img10.jpg");
    filelist.push_back("img09.jpg");
    filelist.push_back("img08.jpg");
    filelist.push_back("img07.jpg");
    filelist.push_back("img06.jpg");
    filelist.push_back("img05.jpg");
    filelist.push_back("img04.jpg");
    filelist.push_back("img03.jpg");
    filelist.push_back("img02.jpg");
    filelist.push_back("img01.jpg");

    cv::Size boardSize(8,6);
    double calibrateError;
    int success;
    success = calibrateCam.addChessboardPoints(filelist,boardSize);
    std::cout<<"Success:" << success << std::endl;
    cv::Size imageSize;
    cv::Mat inputImage, outputImage;
    inputImage = cv::imread("img10.jpg",0);
    outputImage = inputImage.clone();
    imageSize = inputImage.size();
    calibrateError = calibrateCam.calibrate(imageSize);
    std::cout<<"Calibration error:" << calibrateError << std::endl;
    calibrateCam.remap(inputImage,outputImage);
    cv::namedWindow("Original");
    cv::imshow("Original",inputImage);
    cv::namedWindow("Undistorted");
    cv::imshow("Undistorted",outputImage);
    cv::waitKey();
    return 0;
}

すべてがエラーなしで実行されます。cameraMatrixは次のようになります(おおよそ):

685.65 0 365.14
0 686.38 206.98
0 0 1

キャリブレーションエラーは0.310157で、許容範囲です。

しかし、リマップを使用すると、出力画像は元の画像よりもさらに悪く見えます。サンプルは次のとおりです。

元の画像:元の画像]

歪みのない画像:歪みのない画像]

だから、問題は、私がキャリブレーションの過程で何か間違ったことをしているのかということです。キャリブレーションには10種類のチェス盤画像で十分ですか?何か提案はありますか?

4

2 に答える 2

1

カメラマトリックスはレンズの歪みを解消しません。これらの4つの値は、単に焦点距離(HとV)と画像の中心(XとY)です。

レンズマッピングを含む別の3または4値の行マトリックス(distCoeffsコード内)があります-コード例についてはKarl'sAnswerを参照してください

于 2012-04-05T16:05:31.457 に答える
1

キャリブレーションは、解の近くでかなり浅い勾配を持つ数値最適化で行われます。また、最小化される関数は非常に非線形です。だから、私の推測では、あなたの10枚の画像は十分ではありません。私は非常に広角のレンズ(つまり、非常に歪んだ画像)を使用してカメラを調整し、50枚または60枚の画像を取得しようとしています。

私は、チェス盤が画像の各エッジに沿って3つまたは4つの位置にあり、さらに中央にいくつかあり、カメラに対して複数の方向を持ち、3つの異なる距離(非常に近い、典型的な、可能な限り)で画像を取得しようとしています。チェッカーボードを取得して解決します)。

チェス盤を角の近くに置くことは非常に重要です。サンプル画像には、画像の隅のすぐ近くにチェス盤がありません。画像の非常に歪んだ部分(コーナー)で正しいことを行うようにキャリブレーションを制約するのは、これらのポイントです。

于 2012-04-05T20:21:03.420 に答える