校正全景图(矩形)

时间:2019-06-21 09:21:48

标签: opencv fisheye

我正在校正WV-SFV481(松下)相机拍摄的全景(矩形)图像。

有关图像示例,请参见手册文件(第1.3-2节。全景): https://bizpartner.panasonic.net/public/sites/all/modules/panasonic/mypdfurl/pdf.js/web/viewer.html?file=/public/system/files/files/fields/field_file/psd/2017/09/20/PGQP1885UAC1_WV-SFV481_OI_en_1505871868.0502.pdf

我已使用国际象棋棋盘图像(全景格式)通过OpenCV校准参数,请按照本教程操作: https://medium.com/@kennethjiang/calibrate-fisheye-lens-using-opencv-part-2-13990f1b157f 但是,整改效果不佳(OpenCV模块不支持全景格式)。

是否有任何OpenCV模块或方法支持对全景图像进行校正?

1 个答案:

答案 0 :(得分:0)

虽然有点笨重,但您可以通过cv :: remap将圆柱(等边矩形全景)图像转换为直线(经典)图像。这是C ++代码:

using namespace cv;
const float PI = 3.1415927;

// Create 2 channel matrix with where values at I(x,y) = (x,y). This
// is to circumvent missing backward warping of CylindricalWarper
Mat createIndexMap(Size sz, Rect roi) {
    int nRows = roi.y + roi.height;
    int nCols = roi.x + roi.width;
    Mat res = Mat(Size(nCols, nRows), CV_32FC2);
    int i, j;
    float* p;
    for (i = 0; i < nRows; i++) {
        p = res.ptr<float>(i);
        for (j = 0; j < nCols; j++) {
            p[2 * j] = (float)j / nCols * sz.width;
            p[2 * j + 1] = (float)i / nRows * sz.height;
        }
    }
    return res;
}

// Create dewarp maps for transformation from cylindrical to rectilinear projection.
void createDewarpMaps(Size image_size, Size warped_size, Mat* map_x, Mat* map_y) {
    float warper_scale = image_size.width/ PI; // this assumes FOV 180 degrees

    Mat k = (Mat_<float>(3, 3) << 1, 0, image_size.width / (2.0 * warper_scale), 0, 1, image_size.height / (2.0 * warper_scale), 0, 0, 1 / warper_scale);
    Mat r = Mat::eye(3, 3, CV_32F);
    Ptr<WarperCreator> warper_creator;
    warper_creator = makePtr<CylindricalWarper>();
    Ptr<detail::RotationWarper> warper = warper_creator->create(static_cast<float>(warper_scale));
    Rect roi = warper->warpRoi(warped_size, k, r);
    roi.x = 0;
    roi.y = 0;
    Mat indexes = createIndexMap(warped_size, roi);
    Mat maps;
    warper->warpBackward(indexes, k, r, InterpolationFlags::INTER_CUBIC, BorderTypes::BORDER_REPLICATE, warped_size, maps);
    Mat map_array[2];
    split(maps, map_array);
    *map_x = map_array[0];
    *map_y = map_array[1];
}

// Draw dewarped image with center x
void dewarp(Mat frame, int center_x, Size dst_size, Mat* map_x, Mat* map_y) {
    int left_x = center_x - dst_size.width / 2;

    Rect roi(left_x, 0, dst_size.width, dst_size.height);
    Mat roi_mat = frame(roi);
    Mat dewarped_frame, rotated_frame;
    cv::remap(roi_mat, dewarped_frame, *map_x, *map_y, INTER_CUBIC, BORDER_CONSTANT, Scalar(255, 0, 0));
    imshow("dewarped", dewarped_frame);
}

int main(int argc, char** argv) {
    namedWindow("original", cv::WINDOW_NORMAL);
    namedWindow("dewarped", cv::WINDOW_AUTOSIZE);
    if (argc < 2) {
        cerr << "Provide path to image as an argument!\n";
        exit(-1);
    }
    shared_ptr<Mat> map_x = make_unique<Mat>();
    shared_ptr<Mat> map_y = make_unique<Mat>();
    Mat frame = imread(argv[1]);
    cv::resize(frame, frame, Size(), .5, .5);
    circle(frame, Point(frame.cols / 2, frame.rows / 2), 6, Scalar(255, 255, 0), -1);
    Size dst_size = frame.size();
    dst_size.width /= 2;
    createDewarpMaps(frame.size(), dst_size, map_x.get(), map_y.get());
    int x = frame.size().width /2 ;
    dewarp(frame, x, dst_size, map_x.get(), map_y.get());
}