C++ 使用OpenCV将帧转换为从上方拍摄的帧
我正在做一个项目,用光流技术估算无人机(四架直升机)的位置。我目前有一个使用OpenCV算法的代码。当相机始终指向地面时,当前代码工作正常 现在,我想为相机不直接向下的情况添加支持,这意味着四架直升机现在有俯仰/滚转/偏航(欧拉角)。四角机的欧拉角是已知的,我正在寻找一种方法来计算和应用基于已知当前欧拉角所需的变换。这样,结果图像就好像是从上面拍摄的一样(见下图) 我通过OpenCV中的C++ 使用OpenCV将帧转换为从上方拍摄的帧,c++,opencv,image-processing,computer-vision,image-rotation,C++,Opencv,Image Processing,Computer Vision,Image Rotation,我正在做一个项目,用光流技术估算无人机(四架直升机)的位置。我目前有一个使用OpenCV算法的代码。当相机始终指向地面时,当前代码工作正常 现在,我想为相机不直接向下的情况添加支持,这意味着四架直升机现在有俯仰/滚转/偏航(欧拉角)。四角机的欧拉角是已知的,我正在寻找一种方法来计算和应用基于已知当前欧拉角所需的变换。这样,结果图像就好像是从上面拍摄的一样(见下图) 我通过OpenCV中的findHomography或getPerspectiveTransform函数,找到了在具有4个角点的2组(
findHomography
或getPerspectiveTransform
函数,找到了在具有4个角点的2组(源和目标)时计算转换的方法。但我找不到任何只知道欧拉角的方法(因为我不知道目标图像的corenrs)
所以我的问题是,我可以使用什么方法,以及如何将一个帧转换为从上面拍摄的帧,如果需要的话,只使用欧拉角和相机离地面的高度
为了证明我需要什么:
我当前代码的相关部分如下:
for(;;)
{
Mat m, disp, warp;
vector<Point2f> corners;
// take out frame- still distorted
cap >> origFrame;
// undistort the frame using the calibration parameters
cv::undistort(origFrame, undistortFrame, cameraMatrix, distCoeffs, noArray());
// lower the process effort by transforming the picture to gray
cvtColor(undistortFrame, gray, COLOR_BGR2GRAY);
if( !prevgray.empty() )
{
// calculate flow
calcOpticalFlowFarneback(prevgray, gray, uflow, 0.5, 3/*def 3 */, 10/* def 15*/, 3, 3, 1.2 /* def 1.2*/, 0);
uflow.copyTo(flow);
// get average
calcAvgOpticalFlow(flow, 16, corners);
// calculate range of view - 2*tan(fov/2)*distance
rovX = 2*0.44523*distanceSonar*100; // 2 * tan(48/2) * dist(cm)
rovY = 2*0.32492*distanceSonar*100; // 2 * tan(36/2) * dist(cm)
// calculate final x, y location
location[0] += (currLocation.x/WIDTH_RES)*rovX;
location[1] += (currLocation.y/HEIGHT_RES)*rovY;
}
//break conditions
if(waitKey(1)>=0)
break;
if(end_run)
break;
std::swap(prevgray, gray);
}
(;;)的
{
Mat m,disp,翘曲;
矢量角点;
//取出框架-仍然变形
cap>>原框架;
//使用校准参数使机架不失真
cv::不失真(origFrame、不失真Frame、cameraMatrix、DistCoefs、noArray());
//通过将图片转换为灰色,降低处理工作量
CVT颜色(不失真帧、灰色、颜色为灰色);
如果(!prevgray.empty())
{
//计算流量
calcOpticalFlowFarneback(prevgray、gray、uflow、0.5,3/*def 3*/、10/*def 15*/、3,3,1.2/*def 1.2*/、0);
uflow.copyTo(流);
//平均
钙质光流(流,16,角);
//计算视野范围-2*tan(视野/2)*距离
rovX=2*0.44523*距离声纳*100;//2*tan(48/2)*距离(厘米)
rovY=2*0.32492*距离声纳*100;//2*tan(36/2)*距离(厘米)
//计算最终的x,y位置
位置[0]+=(currenlocation.x/宽度×分辨率)*rovX;
位置[1]+=(currenlocation.y/高度分辨率)*rovY;
}
//中断条件
如果(等待键(1)>=0)
打破
如果(结束运行)
打破
标准::交换(灰色、灰色);
}
更新:
成功添加旋转后,我仍然需要将图像居中(并且不要超出框架窗口,如下所示)。我想我需要一些翻译我希望源映像的中心位于目标映像的中心。我如何才能添加此选项
工作的旋转功能:
void rotateFrame(const Mat &input, Mat &output, Mat &A , double roll, double pitch, double yaw){
Mat Rx = (Mat_<double>(3, 3) <<
1, 0, 0,
0, cos(roll), -sin(roll),
0, sin(roll), cos(roll));
Mat Ry = (Mat_<double>(3, 3) <<
cos(pitch), 0, sin(pitch),
0, 1, 0,
-sin(pitch), 0, cos(pitch));
Mat Rz = (Mat_<double>(3, 3) <<
cos(yaw), -sin(yaw), 0,
sin(yaw), cos(yaw), 0,
0, 0, 1);
Mat R = Rx*Ry*Rz;
Mat trans = A*R*A.inv();
warpPerspective(input, output, trans, input.size());
}
void rotateFrame(常数垫和输入、垫和输出、垫和A、双滚动、双俯仰、双偏航){
Mat Rx=(Mat_u3;(3,3)这是我在4个角中使用的方式:
// Desired four corners
std::vector<Eigen::Vector2f> Normalized_Reference_Pattern = { Eigen::Vector2f(0, 0), Eigen::Vector2f(0, 2), Eigen::Vector2f(2, 0), Eigen::Vector2f(2, 2) };
// Current four points
std::vector<Eigen::Vector2f> CurrentCentroids = { /* Whatever four corners you want, but relative sueqnece to above */ };
// Transform for current to desired
auto Master_Transform = get_perspective_transform(CurrentCentroids, Normalized_Reference_Pattern);
// abilitu to use the same tranformation for other points (other than the corners) in the image
Eigen::Vector2f Master_Transform_Centroid = Master_Transform * Eigen::Vector2f(currentX, currentY);
//所需的四个角
std::vector Normalized_Reference_Pattern={Eigen::Vector2f(0,0),Eigen::Vector2f(0,2),Eigen::Vector2f(2,0),Eigen::Vector2f(2,2)};
//当前四点
std::vector CurrentCentroids={/*任何您想要的四个角,但相对于上面的*/};
//将电流转换为所需电流
自动主控变换=获取透视变换(当前质心、标准化参考模式);
//能够对图像中的其他点(角点除外)使用相同的变换
本征::矢量2f主_变换_质心=主_变换*本征::矢量2f(currentX,currentY);
这是我的黑盒子:
Eigen::Matrix3f get_perspective_transform(const std::vector<Eigen::Vector2f>& points_from,const std::vector<Eigen::Vector2f>& points_to)
{
cv::Mat transform_cv = cv::getPerspectiveTransform(
convert::to_cv(points_from),
convert::to_cv(points_to));
Eigen::Matrix3f transform_eigen;
cv::cv2eigen(transform_cv, transform_eigen);
return transform_eigen;
}
Eigen::Matrix3f get_perspective_transform(const std::vector&points_from,const std::vector&points_to)
{
cv::Mat transform_cv=cv::getPerspectiveTransform(
转换::到_cv(点从),
convert::to_cv(points_to));
特征::矩阵x3f变换_特征;
cv::cv2eigen(transform\u cv,transform\u eigen);
返回变换_特征值;
}
如果您有一个(3x3),并且camara姿势之间没有转换,您只需找到单应H(3x3)并应用以下公式即可:
H = A * R * A.inv()
其中.inv()是矩阵求逆
更新:
如果要将图像居中,只需通过以下方式添加平移:
(这是查找中心的扭曲位置并将该点平移回中心)
W是您的最终变换。我得出结论,我必须使用4x4单应矩阵才能得到我想要的。为了找到正确的单应矩阵,我们需要:
warpPerspective(input, output, H, input.size(), INTER_LANCZOS4);
三维旋转矩阵R
摄像机校准固有矩阵A1
及其逆矩阵A2
翻译矩阵T
通过将X、Y、Z轴周围的旋转矩阵相乘,我们可以合成3D旋转矩阵R
:
Mat R = RZ * RY * RX
为了在图像上应用变换并使其居中,我们需要添加由4x4矩阵给出的平移,其中dx=0;dy=0;dz=1
:
Mat T = (Mat_<double>(4, 4) <<
1, 0, 0, dx,
0, 1, 0, dy,
0, 0, 1, dz,
0, 0, 0, 1);
有了这个单应矩阵,我们就可以使用OpenCV中的函数来应用转换
warpPerspective(input, output, H, input.size(), INTER_LANCZOS4);
关于此解决方案的结论和完整性,以下是完整代码:
void rotateImage(const Mat &input, UMat &output, double roll, double pitch, double yaw,
double dx, double dy, double dz, double f, double cx, double cy)
{
// Camera Calibration Intrinsics Matrix
Mat A2 = (Mat_<double>(3,4) <<
f, 0, cx, 0,
0, f, cy, 0,
0, 0, 1, 0);
// Inverted Camera Calibration Intrinsics Matrix
Mat A1 = (Mat_<double>(4,3) <<
1/f, 0, -cx/f,
0, 1/f, -cy/f,
0, 0, 0,
0, 0, 1);
// Rotation matrices around the X, Y, and Z axis
Mat RX = (Mat_<double>(4, 4) <<
1, 0, 0, 0,
0, cos(roll), -sin(roll), 0,
0, sin(roll), cos(roll), 0,
0, 0, 0, 1);
Mat RY = (Mat_<double>(4, 4) <<
cos(pitch), 0, sin(pitch), 0,
0, 1, 0, 0,
-sin(pitch), 0, cos(pitch), 0,
0, 0, 0, 1);
Mat RZ = (Mat_<double>(4, 4) <<
cos(yaw), -sin(yaw), 0, 0,
sin(yaw), cos(yaw), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
// Translation matrix
Mat T = (Mat_<double>(4, 4) <<
1, 0, 0, dx,
0, 1, 0, dy,
0, 0, 1, dz,
0, 0, 0, 1);
// Compose rotation matrix with (RX, RY, RZ)
Mat R = RZ * RY * RX;
// Final transformation matrix
Mat H = A2 * (T * (R * A1));
// Apply matrix transformation
warpPerspective(input, output, H, input.size(), INTER_LANCZOS4);
}
void rotateImage(常数垫和输入、UMat和输出、双滚动、双俯仰、双偏航、,
双dx、双dy、双dz、双f、双cx、双cy)
{
//摄像机校准内在矩阵
Mat A2=(Mat_U3,4)“从OpenCV中查找单色或getPerspectiveTransform函数。但是没有一个函数在不知道角点位置但具有已知角度的情况下执行此操作”你确定他们不处理角点位置吗?因为我用四角点进行转换。我的文章不够清楚,我已经编辑了。我的意思是我不知道
void rotateImage(const Mat &input, UMat &output, double roll, double pitch, double yaw,
double dx, double dy, double dz, double f, double cx, double cy)
{
// Camera Calibration Intrinsics Matrix
Mat A2 = (Mat_<double>(3,4) <<
f, 0, cx, 0,
0, f, cy, 0,
0, 0, 1, 0);
// Inverted Camera Calibration Intrinsics Matrix
Mat A1 = (Mat_<double>(4,3) <<
1/f, 0, -cx/f,
0, 1/f, -cy/f,
0, 0, 0,
0, 0, 1);
// Rotation matrices around the X, Y, and Z axis
Mat RX = (Mat_<double>(4, 4) <<
1, 0, 0, 0,
0, cos(roll), -sin(roll), 0,
0, sin(roll), cos(roll), 0,
0, 0, 0, 1);
Mat RY = (Mat_<double>(4, 4) <<
cos(pitch), 0, sin(pitch), 0,
0, 1, 0, 0,
-sin(pitch), 0, cos(pitch), 0,
0, 0, 0, 1);
Mat RZ = (Mat_<double>(4, 4) <<
cos(yaw), -sin(yaw), 0, 0,
sin(yaw), cos(yaw), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
// Translation matrix
Mat T = (Mat_<double>(4, 4) <<
1, 0, 0, dx,
0, 1, 0, dy,
0, 0, 1, dz,
0, 0, 0, 1);
// Compose rotation matrix with (RX, RY, RZ)
Mat R = RZ * RY * RX;
// Final transformation matrix
Mat H = A2 * (T * (R * A1));
// Apply matrix transformation
warpPerspective(input, output, H, input.size(), INTER_LANCZOS4);
}