web-dev-qa-db-ja.com

OpenCV魚眼レンズキャリブレーションは、結果の画像をカットしすぎます

OpenCVを使用して、魚眼レンズ付きのカメラを使用して撮影した画像を調整しています。

私が使用している関数は次のとおりです。

  • findChessboardCorners(...);は、キャリブレーションパターンの角を見つけます。
  • cornerSubPix(...);は、見つかったコーナーを調整します。
  • fisheye::calibrate(...);は、カメラマトリックスと歪み係数を調整します。
  • fisheye::undistortImage(...);は、キャリブレーションから取得したカメラ情報を使用して画像の歪みを解消します。

結果の画像は見栄えが良いように見えますが(直線など)、私の問題は、関数が画像の多くを切り取ってしまうことです。

これは本当の問題です。私は4台のカメラを90度の間隔で使用しており、側面の多くが切り取られている場合、画像をステッチするときに必要な重複領域がありません。

fisheye::estimateNewCameraMatrixForUndistortRectify(...)の使用を検討しましたが、fisheye::calibrateの回転ベクトル出力がであるため、R入力として何を入力すればよいかわからないため、良い結果を得ることができませんでした。 3xN(Nはキャリブレーション画像の数)およびfisheye::estimateNewCameraMatrixForUndistortRectifyには1x3または3x3が必要です。

以下の画像は、歪みのない結果の画像と、理想的に必要な結果の例を示しています。

歪みのない:

My undistortion

必要な結果の例:

Example of wanted result

10
NoShadowKick

魚眼レンズ用のgetOptimalNewCameraMatrixで「アルファ」ノットを探しているときに、同様の問題が発生したと思います。

元のショット: Original

Cv2.fisheye.calibrateでキャリブレーションし、KパラメーターとDパラメーターを取得しました

K = [[ 329.75951163    0.          422.36510555]
 [   0.          329.84897388  266.45855056]
 [   0.            0.            1.        ]]

D = [[ 0.04004325]
 [ 0.00112638]
 [ 0.01004722]
 [-0.00593285]]

これは私が得るものです

map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, d, np.eye(3), k, (800,600), cv2.CV_16SC2)
nemImg = cv2.remap( img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)

そして、私はそれがあまりにも切り刻むと思います。ルービックキューブ全体を見たい

initUndistortRectifyMap/remap with the K,D

私はそれを修正します

nk = k.copy()
nk[0,0]=k[0,0]/2
nk[1,1]=k[1,1]/2
# Just by scaling the matrix coefficients!

map1, map2 = cv2.fisheye.initUndistortRectifyMap(k, d, np.eye(3), nk, (800,600), cv2.CV_16SC2)  # Pass k in 1st parameter, nk in 4th parameter
nemImg = cv2.remap( img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)

多田!

This is what I want

3
HelloSam

Paul Bourkehere で述べたように:

魚眼レンズの投影は「歪んだ」画像ではなく、プロセスは「ゆがみ」ではありません。他の投影法のような魚眼レンズは、3D世界を2D平面にマッピングする多くの方法の1つであり、長方形の透視投影法を含む他の投影法よりも多かれ少なかれ「歪んで」います。

画像をトリミングせずに投影を取得するには(カメラのFOVが〜180度)、魚眼レンズを投影できます次のようなものを使用した正方形の画像:

Fisheye to Rectangular

ソースコード:

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>

// - compile with:
// g++ -ggdb `pkg-config --cflags --libs opencv` fist2rect.cpp -o fist2rect
// - execute:
// fist2rect input.jpg output.jpg

 using namespace std;
 using namespace cv;
 #define PI 3.1415926536

 Point2f getInputPoint(int x, int y,int srcwidth, int srcheight)
 {
    Point2f pfish;
    float theta,phi,r, r2;
    Point3f psph;
    float FOV =(float)PI/180 * 180;
    float FOV2 = (float)PI/180 * 180;
    float width = srcwidth;
    float height = srcheight;

    // Polar angles
    theta = PI * (x / width - 0.5); // -pi/2 to pi/2
    phi = PI * (y / height - 0.5);  // -pi/2 to pi/2

    // Vector in 3D space
    psph.x = cos(phi) * sin(theta);
    psph.y = cos(phi) * cos(theta);
    psph.z = sin(phi) * cos(theta);

    // Calculate fisheye angle and radius
    theta = atan2(psph.z,psph.x);
    phi = atan2(sqrt(psph.x*psph.x+psph.z*psph.z),psph.y);

    r = width * phi / FOV;
    r2 = height * phi / FOV2;

    // Pixel in fisheye space
    pfish.x = 0.5 * width + r * cos(theta);
    pfish.y = 0.5 * height + r2 * sin(theta);
    return pfish;
}
int main(int argc, char **argv)
{
    if(argc< 3)
        return 0;
    Mat orignalImage = imread(argv[1]);
    if(orignalImage.empty())
    {
        cout<<"Empty image\n";
        return 0;
    }
    Mat outImage(orignalImage.rows,orignalImage.cols,CV_8UC3);

    namedWindow("result",CV_WINDOW_NORMAL);

    for(int i=0; i<outImage.cols; i++)
    {
        for(int j=0; j<outImage.rows; j++)
        {

            Point2f inP =  getInputPoint(i,j,orignalImage.cols,orignalImage.rows);
            Point inP2((int)inP.x,(int)inP.y);

            if(inP2.x >= orignalImage.cols || inP2.y >= orignalImage.rows)
                continue;

            if(inP2.x < 0 || inP2.y < 0)
                continue;
            Vec3b color = orignalImage.at<Vec3b>(inP2);
            outImage.at<Vec3b>(Point(i,j)) = color;

        }
    }

    imwrite(argv[2],outImage);

}
2
guerrerocarlos

私は同じ問題を積み重ねました。また、カメラのFOVが約180度の場合、最初の画像表面を100%歪ませることはできないと思います。私が置いたより詳細な説明 ここ

すべてのピクセルを取得するには、_fisheye::estimateNewCameraMatrixForUndistortRectify_をR=np.eye(3)(単位行列)および_balance=1_とともに使用する必要があります。

_new_K = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, D, dim, np.eye(3), balance=balance)
map1, map2 = cv2.fisheye.initUndistortRectifyMap(scaled_K, D, np.eye(3), new_K, dim, cv2.CV_32FC1)
# and then remap:
undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
_
0

うまくいっています。getOptimalNewCameraMatrix()を使用してundistort()newCameraMatrixを設定するだけです。すべてのピクセルを表示するには、getOptimalNewCameraMatrix()alphaを1に設定する必要があります。

0
alexisrozhkov