Я использую OpenCV для калибровки изображений, полученных с помощью камер с объективом типа «рыбий глаз».
Функции, которые я использую:
findChessboardCorners(...);
чтобы найти углы калибровочного шаблона.cornerSubPix(...);
уточнять найденные углы.fisheye::calibrate(...);
калибровать матрицу камеры и коэффициенты искажения.fisheye::undistortImage(...);
чтобы не искажать изображения, используя информацию камеры, полученную при калибровке.Хотя получающееся изображение выглядит хорошо (прямые линии и т. Д.), Моя проблема заключается в том, что функция обрезает слишком большую часть изображения.
Это реальная проблема, так как я использую четыре камеры с углом 90 градусов между ними, и когда большая часть сторон обрезана, между ними нет области перекрытия, которая необходима, поскольку я собираюсь сшивать изображения.
Я смотрел на использование fisheye::estimateNewCameraMatrixForUndistortRectify(...)
но я не мог получить его, чтобы дать хорошие результаты, так как я не знаю, что я должен положить в качестве R
вход, как выход вектора вращения fisheye::calibrate
3xN (где N — количество калибровочных изображений) и fisheye::estimateNewCameraMatrixForUndistortRectify
требуется 1×3 или 3×3.
Изображения ниже показывают изображение моего результата искажения и пример результата, который я бы идеально хотел.
Undistortion:
Пример желаемого результата:
Я думаю, что столкнулся с подобной проблемой, ища «альфа» узел в getOptimalNewCameraMatrix для рыбий глаз.
Я калибровал его с помощью 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)
И я думаю, что это слишком много. Я хочу увидеть весь кубик Рубика
Я чиню это с
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)
TADA!
У вас все хорошо, вам просто нужно использовать getOptimalNewCameraMatrix()
установить newCameraMatrix
в undistort()
, Для того, чтобы все пиксели были видны, вы должны установить alpha
до 1 в getOptimalNewCameraMatrix()
,
Я сложил ту же проблему. И если угол обзора вашей камеры ~ 180 градусов, я думаю, вы не сможете деформировать 100% поверхности исходного изображения. Более подробное объяснение я разместил Вот
проекция «рыбий глаз» не является «искаженным» изображением, и процесс не
«деформирование». Рыбий глаз, как и другие прогнозы, является одним из многих способов
отображая трехмерный мир на двухмерную плоскость, он не более или менее «искажен», чем другие проекции, включая прямоугольную перспективную проекцию
Чтобы получить проекцию без обрезки изображения, (и ваша камера имеет ~180 градусов FOV) вы можете проецировать Рыбий изображение в квадрате, используя что-то вроде этого:
Исходный код:
#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);
}