|
|
|
|
@ -26,6 +26,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace cv;
|
|
|
|
|
|
|
|
|
|
@ -170,16 +171,130 @@ UPanInfo UnderStitch::InitMap(FrameInfo para)
|
|
|
|
|
return panPara;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double getLocalScaleFromH(const cv::Mat& H, double u, double v)
|
|
|
|
|
{
|
|
|
|
|
CV_Assert(H.rows == 3 && H.cols == 3 && H.type() == CV_64F);
|
|
|
|
|
|
|
|
|
|
// 提取矩阵元素
|
|
|
|
|
double h00 = H.at<double>(0, 0), h01 = H.at<double>(0, 1), h02 = H.at<double>(0, 2);
|
|
|
|
|
double h10 = H.at<double>(1, 0), h11 = H.at<double>(1, 1), h12 = H.at<double>(1, 2);
|
|
|
|
|
double h20 = H.at<double>(2, 0), h21 = H.at<double>(2, 1), h22 = H.at<double>(2, 2);
|
|
|
|
|
|
|
|
|
|
// 原始点的齐次坐标
|
|
|
|
|
double X = h00 * u + h01 * v + h02;
|
|
|
|
|
double Y = h10 * u + h11 * v + h12;
|
|
|
|
|
double W = h20 * u + h21 * v + h22;
|
|
|
|
|
|
|
|
|
|
double W2 = (std::abs(W) > 1e-12) ? W * W : 1e-12;
|
|
|
|
|
|
|
|
|
|
// 解析求导 —— Jacobian
|
|
|
|
|
double dx_du = (h00 * W - h20 * X) / W2;
|
|
|
|
|
double dx_dv = (h01 * W - h21 * X) / W2;
|
|
|
|
|
double dy_du = (h10 * W - h20 * Y) / W2;
|
|
|
|
|
double dy_dv = (h11 * W - h21 * Y) / W2;
|
|
|
|
|
|
|
|
|
|
// 两个方向的放缩比例(米 / 像素)
|
|
|
|
|
double sx = std::hypot(dx_du, dy_du);
|
|
|
|
|
double sy = std::hypot(dx_dv, dy_dv);
|
|
|
|
|
|
|
|
|
|
// 返回平均尺度
|
|
|
|
|
return 0.5 * (sx + sy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UPanInfo UnderStitch::InitMap_SCAN(FrameInfo para, float ptRange)
|
|
|
|
|
{
|
|
|
|
|
UPanInfo panPara = { 0 };
|
|
|
|
|
|
|
|
|
|
// 地理几何计算
|
|
|
|
|
RtK SE3;
|
|
|
|
|
cv::Mat H0 = _GeoSolver->findHomography(para, SE3);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算下视中心的地理坐标
|
|
|
|
|
para.servoInfo.fServoPt = 0;
|
|
|
|
|
cv::Point2f ct_geo = warpPointWithH(H0, cv::Point2f(para.nWidth / 2, para.nHeight / 2));
|
|
|
|
|
|
|
|
|
|
// 下视最大分辨率估计 m/p
|
|
|
|
|
double scale_max = getLocalScaleFromH(H0, para.nWidth / 2, para.nHeight / 2);
|
|
|
|
|
|
|
|
|
|
// 计算扫描边界的地理坐标
|
|
|
|
|
para.servoInfo.fServoPt = -ptRange;
|
|
|
|
|
cv::Point2f ct_geo_left = warpPointWithH(_GeoSolver->findHomography(para, SE3), cv::Point2f(para.nWidth / 2, para.nHeight / 2));
|
|
|
|
|
para.servoInfo.fServoPt = ptRange;
|
|
|
|
|
cv::Point2f ct_geo_right = warpPointWithH(_GeoSolver->findHomography(para, SE3), cv::Point2f(para.nWidth / 2, para.nHeight / 2));
|
|
|
|
|
|
|
|
|
|
// 载体速度矢量,以飞行15s计算,载体速度speed = 80m/s*15 = 2400m
|
|
|
|
|
double yaw_RAD = para.craft.stAtt.fYaw / 180 * 3.14159;
|
|
|
|
|
double dx = 1200 * std::sin(yaw_RAD);
|
|
|
|
|
double dy = 1200 * std::cos(yaw_RAD);
|
|
|
|
|
cv::Point2f ct_geo_left_fly = cv::Point2f(ct_geo_left.x + dx, ct_geo_left.y + dy);
|
|
|
|
|
cv::Point2f ct_geo_right_fly = cv::Point2f(ct_geo_right.x + dx, ct_geo_right.y + dy);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算下个全景地理中心和范围
|
|
|
|
|
float min_x = min(min(ct_geo_left.x, ct_geo_right.x), min(ct_geo_left_fly.x, ct_geo_right_fly.x));
|
|
|
|
|
float max_x = max(max(ct_geo_left.x, ct_geo_right.x), max(ct_geo_left_fly.x, ct_geo_right_fly.x));
|
|
|
|
|
float min_y = min(min(ct_geo_left.y, ct_geo_right.y), min(ct_geo_left_fly.y, ct_geo_right_fly.y));
|
|
|
|
|
float max_y = max(max(ct_geo_left.y, ct_geo_right.y), max(ct_geo_left_fly.y, ct_geo_right_fly.y));
|
|
|
|
|
|
|
|
|
|
float E_range = (max_x - min_x) * 1.2;
|
|
|
|
|
float N_range = (max_y - min_y) * 1.2;
|
|
|
|
|
|
|
|
|
|
// 不损失分辨率的全景图尺寸
|
|
|
|
|
panPara.m_pan_width = E_range / scale_max;
|
|
|
|
|
panPara.m_pan_height = N_range / scale_max;
|
|
|
|
|
|
|
|
|
|
// 救救内存
|
|
|
|
|
if (panPara.m_pan_width > 12000 || panPara.m_pan_height > 12000)
|
|
|
|
|
{
|
|
|
|
|
scale_max = E_range / 12000;
|
|
|
|
|
panPara.m_pan_width = E_range / scale_max;
|
|
|
|
|
panPara.m_pan_height = N_range / scale_max;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
panPara.scale = 1.0/scale_max;
|
|
|
|
|
|
|
|
|
|
// 重新计算投影矩阵
|
|
|
|
|
cv::Mat mapH0 = getAffineFromGeo2Pan(panPara);
|
|
|
|
|
auto cur = warpPointWithH(mapH0, ct_geo);
|
|
|
|
|
|
|
|
|
|
// 计算平移到全景图固定点的平移量
|
|
|
|
|
int planX = panPara.m_pan_width / 2;
|
|
|
|
|
int planY = panPara.m_pan_height / 2;
|
|
|
|
|
|
|
|
|
|
panPara.map_shiftX += planX - (cur.x);
|
|
|
|
|
panPara.map_shiftY += planY - (cur.y);
|
|
|
|
|
|
|
|
|
|
// 获取全景图的投影矩阵
|
|
|
|
|
_H_pan = getAffineFromGeo2Pan(panPara);
|
|
|
|
|
|
|
|
|
|
// 计算全景图瓦片相关
|
|
|
|
|
auto P1 = getBLHFromPan(cv::Point2f(0, 0), _H_pan);
|
|
|
|
|
auto P2 = getBLHFromPan(cv::Point2f(panPara.m_pan_width, 0), _H_pan);
|
|
|
|
|
auto P3 = getBLHFromPan(cv::Point2f(panPara.m_pan_width, panPara.m_pan_height), _H_pan);
|
|
|
|
|
auto P4 = getBLHFromPan(cv::Point2f(0, panPara.m_pan_height), _H_pan);
|
|
|
|
|
|
|
|
|
|
auto minL = min(min(min(P1.L, P2.L), P3.L), P4.L);
|
|
|
|
|
auto maxL = max(max(max(P1.L, P2.L), P3.L), P4.L);
|
|
|
|
|
auto minB = min(min(min(P1.B, P2.B), P3.B), P4.B);
|
|
|
|
|
auto maxB = max(max(max(P1.B, P2.B), P3.B), P4.B);
|
|
|
|
|
|
|
|
|
|
_panTile.boxLatLon.north = maxB;
|
|
|
|
|
_panTile.boxLatLon.south = minB;
|
|
|
|
|
_panTile.boxLatLon.west = minL;
|
|
|
|
|
_panTile.boxLatLon.east = maxL;
|
|
|
|
|
_panTile.ind.z = _googleProduct.ZoomLevel(panPara.scale);
|
|
|
|
|
|
|
|
|
|
// 生成瓦片划分
|
|
|
|
|
_taskTilesVec = _googleProduct.CalcTileOverlayVec(_panTile, panPara.m_pan_width, panPara.m_pan_height);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return panPara;
|
|
|
|
|
|
|
|
|
|
return UPanInfo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UPanInfo UnderStitch::ShiftMap(FrameInfo para,int& shift_x,int& shift_y)
|
|
|
|
|
@ -241,11 +356,13 @@ UPanInfo UnderStitch::Init(FrameInfo info)
|
|
|
|
|
// 设置拼接原点:地理计算的基准点
|
|
|
|
|
_GeoSolver->SetOriginPoint(info);
|
|
|
|
|
|
|
|
|
|
// 初始化全景图
|
|
|
|
|
_panPara = InitMap(info);
|
|
|
|
|
|
|
|
|
|
// 摆扫45度初始化地图尺寸
|
|
|
|
|
//_panPara = InitMap_SCAN(info,45);
|
|
|
|
|
#ifdef SCAN_MODE
|
|
|
|
|
_panPara = InitMap_SCAN(info,45);
|
|
|
|
|
#else
|
|
|
|
|
// 常规初始化全景图(基于内存限制)
|
|
|
|
|
_panPara = InitMap(info);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// 创建blender
|
|
|
|
|
_MapBlender = new MapBlend(_cache, _panPara);
|
|
|
|
|
@ -343,20 +460,18 @@ SINT32 UnderStitch::Run(GD_VIDEO_FRAME_S frame, FrameInfo para)
|
|
|
|
|
_googleProduct.ExportTileSet(mat_pan, mat_mask, tilesvec, outdirpath, filename);
|
|
|
|
|
}, "ExportTileSet");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// _googleProduct.ExportTileSet(panImage, panMask, _taskTilesVec, _outDir, _filename + std::to_string(_lastFrameKey));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 重新初始化投影参数
|
|
|
|
|
int shift_x = 0, shift_y = 0;
|
|
|
|
|
|
|
|
|
|
// 以向下初始化
|
|
|
|
|
para.servoInfo.fServoPt = 0;
|
|
|
|
|
_panPara = ShiftMap(para, shift_x, shift_y);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 清空全景视场
|
|
|
|
|
_MapBlender->ClearPan();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将BatchMap操作放入线程池中后台处理
|
|
|
|
|
_threadPool.commit([this, recvFrameKeys=_recvFrameKey, h_pan=_H_pan, Hgeos = _frameGeoHAll]() {
|
|
|
|
|
_MapBlender->BatchMapWithH(recvFrameKeys, h_pan, Hgeos);
|
|
|
|
|
@ -384,6 +499,7 @@ SINT32 UnderStitch::Run(GD_VIDEO_FRAME_S frame, FrameInfo para)
|
|
|
|
|
// 投影帧到全景
|
|
|
|
|
_MapBlender->FrameMap(src, H_geo, _H_pan);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 预处理+缓存
|
|
|
|
|
ReceiveFrame(frame, para);
|
|
|
|
|
|
|
|
|
|
|