Правильный способ искажения изображения рыбий глаз

Я сделал несколько примеров программ, которые удаляют искажения объектива на шахматной доске, такие как изображения рыбий глаз, и это работает хорошо, вот снимок экрана

введите описание изображения здесь

Затем я хотел использовать шахматную доску "рыбий глаз" (правое изображение выше), чтобы убрать те же искажения линзы, но из реального изображения, и мне не повезло - искривление все еще остается на неискаженном изображении, поэтому я получил это вместо

введите описание изображения здесь

код

void getObjectPoints(cv::Size, std::vector<std::vector<cv::Point3f>>&);

bool getImagePoints(cv::Mat&, cv::Size&, std::vector<std::vector<cv::Point2f>>&);

void runCalibration(cv::Mat& image, cv::Matx33d&, cv::Vec4d&);

cv::Mat removeFisheyeLensDist(cv::Mat&, cv::Matx33d&, cv::Vec4d&);

// ... definitions    
void getObjectPoints(cv::Size patternSize, std::vector<std::vector<cv::Point3f>>& objectPoints)
{
    const float squareSize = 0.0015f;
    std::vector<cv::Point3f> knownBoardPositions;
    for (int i = 0; i < patternSize.height; ++i)
    {
        for (int j = 0; j < patternSize.width; ++j)
        {
            knownBoardPositions.push_back(cv::Point3f(j*squareSize, i*squareSize, 0.0f));
        }
    }
    if (knownBoardPositions.size() > 0)
        objectPoints.push_back(knownBoardPositions);
}

bool getImagePoints(cv::Mat& image, cv::Size& patternSize, std::vector<std::vector<cv::Point2f>>& imagePoints)
{
    bool patternFound = false;
    while (!patternFound)
    {
        std::vector<cv::Point2f> corners;
        for (int i = 7; i <= 30; ++i)
        {
            int w = i;
            int h = i - 2;

            patternFound = cv::findChessboardCorners(image, cv::Size(w, h), corners,
                                              cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE);
            if (patternFound)
            {
                patternSize.width = w;
                patternSize.height = h;
                imagePoints.push_back(corners);
                break;
            }
        }
    }

    return patternFound;
}

void runCalibration(cv::Mat& image, cv::Matx33d& K, cv::Vec4d& D)
{
    std::vector< std::vector<cv::Point2f> > imagePoints;
    std::vector< std::vector<cv::Point3f> > objectPoints;
    cv::Size patternSize;
    bool patternFound = getImagePoints(image, patternSize, imagePoints);

    if (patternFound)
    {
        getObjectPoints(patternSize, objectPoints);

        std::vector<cv::Vec3d> rvecs;
        std::vector<cv::Vec3d> tvecs;
        cv::fisheye::calibrate(
            objectPoints,
            imagePoints,
            image.size(),
            K,
            D,
            rvecs,
            tvecs,
            cv::fisheye::CALIB_FIX_SKEW |   cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC
        |   cv::fisheye::CALIB_FIX_K1   |   cv::fisheye::CALIB_FIX_K2
        |   cv::fisheye::CALIB_FIX_K3   |   cv::fisheye::CALIB_FIX_K4
//            cv::TermCriteria(3, 20, 1e-6)
        );
    }
}

cv::Mat removeFisheyeLensDist(cv::Mat& distorted, cv::Matx33d& K, cv::Vec4d& D)
{
    cv::Mat undistorted;
    cv::Matx33d newK = K;
    cv::fisheye::undistortImage(distorted, undistorted, K, D, newK);
    return undistorted;
}

int main(int argc, char* argv[])
{
    cv::Mat chessBoardPattern = //..
    cv::Mat distortedImage = //...
    cv::imshow("distorted", distortedImage);

    cv::Matx33d K;  cv::Vec4d D;
    runCalibration(chessBoardPattern, K, D);
    cv::Mat undistoredImage = removeFisheyeLensDist(distortedImage, K, D);    
    cv::imshow("undistored", undistoredImage);
    cv::waitKey(0);
    return 0;
}

Поскольку я думаю, что изображение с башней имеет очень похожие кривизны, как шахматная доска справа, поэтому тот же самый образец должен был работать для изображения башни...

Что я там делаю не так? И почему он не фиксирует искажения объектива для изображения башни?

1 ответ

Решение

К сожалению ваше предположение

если изображения имеют одинаковую кривизну, то параметры камеры должны быть примерно одинаковыми, и поэтому я могу не искажать изображение "рыбий глаз" с рисунком на шахматной доске.

неправильно. Даже камеры одной модели будут иметь различия в фокусном расстоянии, геометрии и расположении объектива и т. Д., Которые необходимо калибровать индивидуально. Кроме того, во время использования камеры эти параметры могут изменяться из-за нагревания, вибрации и других эффектов (обычно это игнорируется на практике).

Чтобы не искажать изображение, не имея доступа к камере, все, что вы можете сделать, - это просто выбрать простую модель камеры "рыбий глаз" и попытаться оценить параметры вручную, пытаясь сделать прямые линии прямыми (например, используя графический интерфейс с ползунками для всех параметров). Это может быть утомительно, но я не знаю лучших вариантов. Кроме того, некоторые программы для редактирования изображений могут иметь инструменты для этого (если я правильно помню, GIMP делает)

Другие вопросы по тегам