2014-10-28 3 views
1

Я получаю изображения с камеры, где невозможно взять изображение шахматной доски и вычислить матрицу коррекции с помощью OpenCV. До сих пор я исправлял изображения с помощью imagemagick convert с опцией '-distort Barrel' 0.0 0.0 -0.035 1.1 ", где я получил параметры с проб и ошибок.Корректное искажение ствола в OpenCV вручную, без изображения шахматной доски

Теперь я хочу сделать это внутри OpenCV, но все, что я нахожу в Интернете, - это автоматическая коррекция с использованием изображения шахматной доски. Есть ли возможность применить простую ручную пробную и искаженную коррекцию искажений объектива, как это было с imagemagick?

+0

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

+0

Я попытался сам определить углы шахматной доски (например, 4x4 точек), но не понял, какова должна быть структура массива углов. У кого-нибудь есть идея? –

+0

Хорошо, я думаю, что наименьший возможный массив должен быть сконфигурирован следующим образом: corners = np.zeros ((4 * 4,1,2), dtype = "float32"). С 3x3, похоже, не работает. Тем не менее я бы предпочел что-то вроде convert -distort Barrel вместо определения теперь искаженных точек. –

ответ

2

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

Поскольку я не знаю, какие коэффициенты ваши параметры дисторсия соответствуют (возможно, взглянуть на http://docs.opencv.org/doc/tutorials/calib3d/camera_calibration/camera_calibration.html и http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#initundistortrectifymap вам придется попробовать его или, может быть, кто-то может помочь здесь.

Другое дело, что я м не уверен, будет ли OpenCV обрабатывать как, плавать и в два раза автоматически Если это не так, что может быть ошибка в этом коде (я не знаю, предполагается ли двойной или одинарной точности):.

cv::Mat distCoeff; 
distCoeff = cv::Mat::zeros(8,1,CV_64FC1); 

// indices: k1, k2, p1, p2, k3, k4, k5, k6 
// TODO: add your coefficients here! 
double k1 = 0; 
double k2 = 0; 
double p1 = 0; 
double p2 = 0; 
double k3 = 0; 
double k4 = 0; 
double k5 = 0; 
double k6 = 0; 

distCoeff.at<double>(0,0) = k1; 
distCoeff.at<double>(1,0) = k2; 
distCoeff.at<double>(2,0) = p1; 
distCoeff.at<double>(3,0) = p2; 
distCoeff.at<double>(4,0) = k3; 
distCoeff.at<double>(5,0) = k4; 
distCoeff.at<double>(6,0) = k5; 
distCoeff.at<double>(7,0) = k6; 




// assume unit matrix for camera, so no movement 
cv::Mat cam1,cam2; 
cam1 = cv::Mat::eye(3,3,CV_32FC1); 
cam2 = cv::Mat::eye(3,3,CV_32FC1); 
//cam2.at<float>(0,2) = 100; // for testing a translation 

// here the undistortion will be computed 
cv::Mat map1, map2; 
cv::initUndistortRectifyMap(cam1, distCoeff, cv::Mat(), cam2, input.size(), CV_32FC1, map1, map2); 

cv::Mat distCorrected; 
cv::remap(input, distCorrected, map1, map2, cv::INTER_LINEAR); 
+0

Где k4, k5 и k6 исходит из? Это не часть документации, не так ли? Также есть фрагмент кода на Python? –

+0

Если я следую вашей ссылке, я вижу что-то вроде этого: xcor = x * (1 + k1 * r^2 + k2 * r^4 + k3 * r^6); это отличается от описания на imagemagick (http://www.imagemagick.org/Usage/distorts/#barrel), где применяется следующая формула: Rsrc = r * (A * r^3 + B * r^2 + C * r + D), поэтому установка, например, от k1 до 0,001, приводит к действительно странному изображению, но не исправляет искажение ствола ?!Тем не менее, я думаю, мы подошли ближе к решению. –

+0

Извините, у меня нет фрагмента python, но его как раз об вызове initUndistortRectifyMap и настройке коэффициентов. Википедия дает некоторые коэффициенты, подобные OpenCV (не проверял термины, хотя) http://en.wikipedia.org/wiki/Distortion_%28optics%29#Software_correction, поэтому, возможно, imageMagick использует другую модель искажений или они предполагают какие-то обратные параметры ?!? Не знаю, извините =) – Micka

6

Ok , Я думаю, что получил. В матрицах cam1, cam2 отсутствуют центры изображений (см. Doc тация). Я добавил его и изменил фокусное расстояние, чтобы избежать слишком сильного изменения размера изображения. Вот код:

import numpy as np 
    import cv2 

    src = cv2.imread("distortedImage.jpg") 
    width = src.shape[1] 
    height = src.shape[0] 

    distCoeff = np.zeros((4,1),np.float64) 

    # TODO: add your coefficients here! 
    k1 = -1.0e-5; # negative to remove barrel distortion 
    k2 = 0.0; 
    p1 = 0.0; 
    p2 = 0.0; 

    distCoeff[0,0] = k1; 
    distCoeff[1,0] = k2; 
    distCoeff[2,0] = p1; 
    distCoeff[3,0] = p2; 

    # assume unit matrix for camera 
    cam = np.eye(3,dtype=np.float32) 

    cam[0,2] = width/2.0 # define center x 
    cam[1,2] = height/2.0 # define center y 
    cam[0,0] = 10.  # define focal length x 
    cam[1,1] = 10.  # define focal length y 

    # here the undistortion will be computed 
    dst = cv2.undistort(src,cam,distCoeff) 

    cv2.imshow('dst',dst) 
    cv2.waitKey(0) 
    cv2.destroyAllWindows() 

Большое спасибо за вашу помощь.

+0

Приятно слышать. Если вы протестировали его, и он работает, afaik вы можете принять свой собственный ответ, чтобы помочь другим найти решение по тому же вопросу – Micka

1

Это дополнительная функция к undistort, может быть быстрее или лучше способы сделать это, но это работает:

void distort(const cv::Mat& src, cv::Mat& dst, const cv::Mat& cameraMatrix, const cv::Mat& distCoeffs) 
{ 

    cv::Mat distort_x = cv::Mat(src.size(), CV_32F); 
    cv::Mat distort_y = cv::Mat(src.size(), CV_32F); 

    cv::Mat pixel_locations_src = cv::Mat(src.size(), CV_32FC2); 

    for (int i = 0; i < src.size().height; i++) { 
    for (int j = 0; j < src.size().width; j++) { 
     pixel_locations_src.at<cv::Point2f>(i,j) = cv::Point2f(j,i); 
    } 
    } 

    cv::Mat fractional_locations_dst = cv::Mat(src.size(), CV_32FC2); 

    cv::undistortPoints(pixel_locations_src, pixel_locations_dst, cameraMatrix, distCoeffs); 

    cv::Mat pixel_locations_dst = cv::Mat(src.size(), CV_32FC2); 

    const float fx = cameraMatrix.at<double>(0,0); 
    const float fy = cameraMatrix.at<double>(1,1); 
    const float cx = cameraMatrix.at<double>(0,2); 
    const float cy = cameraMatrix.at<double>(1,2); 

    // is there a faster way to do this? 
    for (int i = 0; i < fractional_locations_dst.size().height; i++) { 
    for (int j = 0; j < fractional_locations_dst.size().width; j++) { 
     const float x = fractional_locations_dst.at<cv::Point2f>(i,j).x*fx + cx; 
     const float y = fractional_locations_dst.at<cv::Point2f>(i,j).y*fy + cy; 
     pixel_locations_dst.at<cv::Point2f>(i,j) = cv::Point2f(x,y); 
    } 
    } 

    cv::remap(src, dst, pixel_locations_dst, cv::Mat(), CV_INTER_LINEAR); 
} 
Смежные вопросы