Преобразование коэффициентов искажения в HALCON в OpenCV - PullRequest
1 голос
/ 29 октября 2019

У меня откалиброванная многокамерная система. Как внутренние (фокусное расстояние, искажение и т. Д.), Так и внешние (позы) параметры камеры были оценены с помощью программы на основе HALCON. Теперь цель состоит в том, чтобы написать программу на C ++, чтобы считывать параметры камеры, в частности коэффициенты искажения (k1, k2, k3, p1, p2), оцененные HALCON, и использовать их для искажения изображений с помощью OpenCV. К сожалению, пока я не смог добиться успеха: одни и те же коэффициенты искажения, используемые в HALCON и OpenCV, генерируют совершенно разные неискаженные изображения! Я полагаю, проблема в том, как HALCON и OpenCV интерпретируют коэффициенты искажения или даже то, как они выполняют искажение.

Вот мой код HALCON для считывания коэффициентов искажения и использования их для искажения тестового изображения:

* Read the internal camera calibratino parameters ('area_scan_polynomial' model)
read_cam_par('Calibration.dat', CamParam)

* Estimate camera parameters without distortion: set all distortion coefficients to [k1, k2, k3, p1, p2] = [0, 0, 0, 0, 0] 
change_radial_distortion_cam_par ('fixed', CamParam, [0, 0, 0, 0, 0], CamParamOut)

* Estimate camera matrix of distortion-free parameters (used for OpenCV)
cam_par_to_cam_mat(CamParamOut, CamMatrix, ImageWidth, ImageHeight)

* Generate map to use for undistortion. 
* Note the use of type 'coord_map_sub_pix' which is of type 'vector_field_absolute', 
* i.e. the values are 2D absolute coordinates of the corresponding undistorted pixel location
gen_radial_distortion_map(Map, CamParam, CamParamOut, 'coord_map_sub_pix')

* Read a test image and undistort it using the estimate map
read_image (Image, 'test.jpg')
map_image(Image, Map, ImageRectified)

Я пытаюсь сделать то же самое в OpenCV, используя следующий код:

Mat view , rview, mapx, mapy;

// Read the same test image as in HALCON
view = imread("test.jpg");

// Get the image size
const Size viewSize = view.size();

// Generate map to use for undistortion
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
    cameraMatrix, viewSize, CV_16SC2, mapx, mapy);

// Undistort the image using the estimated map
remap(view, rview, mapx, mapy, INTER_LINEAR);

Переменная «cameraMatrix» в OpenCV равна переменной «CamMatrix» в HALCON,Коэффициенты искажения "distCoeffs" в OpenCV взяты из HALCON (k1, k2, k3, p1, p2) и переупорядочены в соответствии с документацией следующим образом:

distCoeffs = (Mat_<double>(5, 1) << k1, k2, p2, p1, k3)

Обратите внимание, что k3 предоставляется в качестве пятых параметрови p2 и p1 меняются местами. Согласно документации HALCON (https://www.mvtec.com/doc/halcon/12/en/calibrate_cameras.html, см. Функцию calibrate_cameras) неискаженные координаты в плоскости изображения (u, v) вычисляются из искаженного (u ', v') как:

u = u '+ u' (k1 r ^ 2 + k2 r ^ 4 + k3 r ^ 6) + p1 (r ^ 2 + 2 u '^ 2) + 2 p2 u' v '

v = v '+ v' (k1 r ^ 2 + k2 r ^ 4 + k3 r ^ 6) + p2 (r ^ 2 + 2 v '^ 2) + 2 p1 u' v '

имея r = sqrt (u '^ 2 + v' ^ 2)

В то время как в OpenCV (https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html, см. функцию initUndistortRectifyMap) одинаковые неискаженные координаты оцениваются аналогично, толькоp1 и p2 меняются местами.

Очевидно, что и OpenCV, и HALCON проецируют пиксели в плоскость изображения одинаково. То есть, имея пиксель (x, y), соответствующие координаты плоскости изображения вычисляются как:

u '= x - cx / fx

v' = y - cy / fy

Они, конечно, могут быть спроецированы обратно для повторного получения соответствующих координат пикселей:

x = u '* fx + cx

y= v '* fy + cy

Согласно документации, похоже, все должно работать как положено. Однако я не понимаю, почему коды на основе HALCON и OpenCV по-прежнему дают очень разные результаты. Я заметил, что для получения таких же неискаженных результатов (но не совсем таких), как в HALCON, мне пришлось уменьшить (коэффициент ~ 100!) Коэффициенты искажения в OpenCV. На самом деле, я заметил, что HALCON оценивает ОГРОМНЫЕ коэффициенты искажения. В качестве примера, чтобы произвести видимые изменения в неискаженном изображении, мне пришлось установить в HALCON k1 = 1000 , в то время как в OpenCV k1 = 1 изображение уже заметно изменилось. Для некоторых коэффициентов искажения мне даже пришлось инвертировать (с минусом) значения, чтобы получить неискаженные результаты, идущие в аналогичном направлении ...

Я еще немного покопался в коде искажения HALCON и попытался оценитьвручную неискаженные координаты (u, v), следуя документации, которая должна соответствовать найденной в «карте». Я сделал это, чтобы убедиться, что «Карта» действительно оценена так, как указано в документации / как я понимаю. Тем не менее, даже здесь я получил очень разные результаты, по сравнению с оценками в «Карта» ... Для проведения теста я использовал следующий код:

* Get the camera parameters from the calibration
get_cam_par_data (CamParam, 'k1', k1)
get_cam_par_data (CamParam, 'k2', k2)
get_cam_par_data (CamParam, 'k3', k3)
get_cam_par_data (CamParam, 'p1', p1)
get_cam_par_data (CamParam, 'p2', p2)
get_cam_par_data (CamParam, 'cx', cx)
get_cam_par_data (CamParam, 'cy', cy)
get_cam_par_data (CamParam, 'image_width', width)
get_cam_par_data (CamParam, 'image_height', height)

* Estimate the camera matrix, to read the focal length in pixel
cam_par_to_cam_mat(CamParamOut, CamMatrix, width, height)

* Extract the focal lenths in pixel from the estimated camera matrix (see above)
fx_px := CamMatrix[0]
fy_px := CamMatrix[4]

* Pick a pixel coordinate (I tried different values) in the image domain
x := 350
y := 450

* Convert into image plane coordinates
u_1 := (x - cx) / fx_px
v_1 := (y - cy) / fy_px

* Estimate the undistorted location u_2 and v_2
r2 := u_1 * u_1 + v_1 * v_1
u_2 := u_1 * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2) + 2 * p1 * u_1 * v_1 + p2 * (r2 + 2 * u_1 * u_1)
v_2 := v_1 * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2) + 2 * p2 * u_1 * v_1 + p1 * (r2 + 2 * v_1 * v_1)

* Back to pixel coordinate
x_1 := u_2 * fx_px + cx
y_1 := v_2 * fy_px + cy

* Compare the values with the value in Map (estimated as before). G_found and G_est should match!
G_found := [y_1, x_1]
get_grayval(Map, y, x, G_est)

Я пытался сосредоточиться на нескольких коэффициентах искажения одновременнот. е. только k1> 0, остальные равны 0. Однако в большинстве случаев (за редким исключением, когда x = cx, y = cy) неискаженные координаты превышают размер изображения или даже становятся отрицательными.

Разве это не способ, которым HALCON оценивает координаты карты искажения? Я что-то пропустил? Как следует преобразовать эти коэффициенты искажения, чтобы OpenCV создавал точно такие же неискаженные результирующие изображения? Любая помощь будет принята с благодарностью!

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

1 Ответ

0 голосов
/ 14 ноября 2019

К сожалению, нет прямого преобразования между калибровочными параметрами HALCON и OpenCV, поскольку базовые модели и то, как оцениваются параметры, различны. Параметры HALCON описывают преобразование из искаженных в неискаженные координаты, тогда как параметры OpenCV описывают обратное преобразование. Из-за высокой полиномиальной степени преобразование невозможно. Модель разделения, которую можно аналитически инвертировать, не существует в OpenCV.

...