diff --git a/main.cpp b/main.cpp index 15b570c..c475e5f 100644 --- a/main.cpp +++ b/main.cpp @@ -110,8 +110,9 @@ unsigned char pImageVL[IMAGE_WIDTH_VL * (IMAGE_HEIGHT_VL) * 2] = { 0 }; void ProcessIR(string filePath, string outname) { - auto stitcher = API_UnderStitch::Create(IMAGE_WIDTH_IR, IMAGE_HEIGHT_IR); + auto stitcher = API_UnderStitch::Create(); + stitcher->SetOutput(outname, "D:/google_tiles"); GD_VIDEO_FRAME_S frame = { 0 };//输入帧 GD_VIDEO_FRAME_S pan = { 0 };//输出全景 @@ -218,7 +219,7 @@ void ProcessIR(string filePath, string outname) stitcher->ProcessFrame(); // 输出谷歌png - stitcher->ExportGeoPng("D:/google_tiles", outname); + stitcher->ExportGeoPng(); imshow("pan_opt", mat_pan); waitKey(0); @@ -227,7 +228,9 @@ void ProcessIR(string filePath, string outname) void ProcessVL(string filePath,string outname) { - auto stitcher = API_UnderStitch::Create(IMAGE_WIDTH_VL, IMAGE_HEIGHT_VL); + auto stitcher = API_UnderStitch::Create(); + stitcher->SetOutput(outname, "D:/google_tiles"); + GD_VIDEO_FRAME_S frame = { 0 };//输入帧 GD_VIDEO_FRAME_S pan = { 0 };//输出全景 @@ -286,7 +289,7 @@ void ProcessVL(string filePath,string outname) frame.u32Height = IMAGE_HEIGHT_VL; frame.u64VirAddr[0] = pFrameVL; - if (i == 0) + if (i == 0 /*|| i == 200*/) { stitcher->Init(info); @@ -303,7 +306,7 @@ void ProcessVL(string filePath,string outname) } else { - if (i % 2 != 0) + if (i % 20 != 0) { i = i + 1; continue; @@ -355,10 +358,10 @@ void ProcessVL(string filePath,string outname) // 输出谷歌png - stitcher->ExportGeoPng("D:/google_tiles", outname); + //stitcher->ExportGeoPng(); // 输出谷歌tile - //stitcher->ExportGoogleTile("D:/google_tiles", outname); + //stitcher->ExportGoogleTile(); } @@ -485,12 +488,12 @@ void ProcessFrontVL(string filePath) int main(int, char**) { //ProcessIR("H:/ir_1280_1024_para40_y16/20241219155238_20.xraw", "20241219155238_20"); - //ProcessVL("H:/vl_1920_1080_para40_y8/22.video","22"); + ProcessVL("H:/vl_1920_1080_para40_y8/22.video","22"); //ProcessVL("H:/vl_1920_1080_para40_y8/20241219153557_11.video", "20241219152643_1"); //ProcessVL("H:/vl_1920_1080_para40_y8/20241219152917_4.video", "20241219152917_4"); //ProcessVL("H:/vl_1920_1080_para40_y8/20241219153515_10.video", "20241219153515_10"); // //ProcessVL("H:/vl_1920_1080_para40_y8/1.video", "1"); - ProcessFrontVL("H:/vl_1920_1080_para40_y8/1.video"); + //ProcessFrontVL("H:/vl_1920_1080_para40_y8/1.video"); } \ No newline at end of file diff --git a/stitch/src/API_UnderStitch.h b/stitch/src/API_UnderStitch.h index 8cb368e..0538c41 100644 --- a/stitch/src/API_UnderStitch.h +++ b/stitch/src/API_UnderStitch.h @@ -24,10 +24,16 @@ public: virtual ~API_UnderStitch() = default; // 初始化拼接 - virtual UPanInfo Init(FrameInfo info) = 0; + virtual UPanInfo Init(FrameInfo info) = 0; + + // 设置输出标识和路径 + virtual void SetOutput(std::string name, std::string outdir) = 0; // 几何校正快拼 - virtual BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; + virtual BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; + + // 实时裁切瓦片 + virtual void CutTileRealTime() = 0; // 缓存接收帧 virtual SINT32 ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; @@ -39,12 +45,12 @@ public: virtual GD_VIDEO_FRAME_S ExportPanAddr() = 0; // 输出地理产品:kml png全景 - virtual bool ExportGeoPng(std::string dir, std::string name) = 0; + virtual bool ExportGeoPng() = 0; // 输出地理产品:谷歌标准瓦片 - virtual bool ExportGoogleTile(std::string dir, std::string name) = 0; + virtual bool ExportGoogleTile() = 0; public: - static API_UnderStitch* Create(SINT32 nWidth, SINT32 nHeight); + static API_UnderStitch* Create(std::string cachedir = "./cache"); static void Destroy(API_UnderStitch* obj); }; diff --git a/stitch/src/Arith_BlendMap.cpp b/stitch/src/Arith_BlendMap.cpp index 4eb7f07..975ec79 100644 --- a/stitch/src/Arith_BlendMap.cpp +++ b/stitch/src/Arith_BlendMap.cpp @@ -39,7 +39,7 @@ void MapBlend::DirectMap(vector frameInd, cv::Mat mapH, cv::Mat pan, cv cv::warpPerspective(src, imagetmp, H, imagetmp.size(), cv::INTER_LINEAR, cv::BORDER_TRANSPARENT); - cv::Mat mask = cv::Mat::ones(cv::Size(src.cols - 200, src.rows - 200), CV_8UC1) * 255; + cv::Mat mask = cv::Mat::ones(cv::Size(src.cols - 200, src.rows - 200), CV_8UC1); cv::Mat warped_mask; cv::warpPerspective(mask, warped_mask, H, imagetmp.size(), cv::INTER_LINEAR); imagetmp.copyTo(pan, warped_mask); diff --git a/stitch/src/Arith_UnderStitch.cpp b/stitch/src/Arith_UnderStitch.cpp index ce3296d..e365b78 100644 --- a/stitch/src/Arith_UnderStitch.cpp +++ b/stitch/src/Arith_UnderStitch.cpp @@ -9,9 +9,9 @@ using namespace std; using namespace cv; -API_UnderStitch* API_UnderStitch::Create(SINT32 nWidth, SINT32 nHeight) +API_UnderStitch* API_UnderStitch::Create(std::string cachedir) { - return new UnderStitch(nWidth,nHeight); + return new UnderStitch(cachedir); } @@ -21,14 +21,15 @@ void API_UnderStitch::Destroy(API_UnderStitch* obj) } -UnderStitch::UnderStitch(SINT32 nWidth, SINT32 nHeight) +UnderStitch::UnderStitch(std::string cachedir) { + // 创建缓存对象 + _cache = new FileCache(50, cachedir); + _GeoSolver = new GeoSolver(); _FeaMatcher = new FeatureMatcher(DetectorType::SIFT, MatcherType::FLANN); - _cache = new FileCache(50,"./cache"); - _BATask = new BA_Task(_cache); _BlendTask = new MapBlend(_cache); @@ -63,9 +64,8 @@ UPanInfo UnderStitch::InitMap(FrameInfo info) UPanInfo panPara = { 0 }; panPara.m_pan_width = MIN(info.nWidth * 5,2000);//全景宽 panPara.m_pan_height = MIN(info.nWidth * 5,2000);//全景高 - panPara.scale = gsd /5;//比例尺,1m = ?pix + panPara.scale = gsd / 2;//比例尺,1m = ?pix - int zoom = _googleProduct.getZoomLevel(panPara.scale); // 直接无平移解算 cv::Mat H_0 = getAffineFromGeo2Pan(panPara); @@ -82,6 +82,30 @@ UPanInfo UnderStitch::InitMap(FrameInfo info) // 获取全景图的投影矩阵,全景图配置更新前保持不变 _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; } @@ -90,6 +114,7 @@ UPanInfo UnderStitch::InitMap(FrameInfo info) UPanInfo UnderStitch::Init(FrameInfo info) { + _panPara = InitMap(info); _panImage = cv::Mat::zeros(_panPara.m_pan_height, _panPara.m_pan_width, CV_8UC4); @@ -100,6 +125,15 @@ UPanInfo UnderStitch::Init(FrameInfo info) return _panPara; } +void UnderStitch::SetOutput(std::string filename, std::string outdir) +{ + _filename = filename; + _outDir = outdir; + _kmlPath = _outDir + "/" + _filename + ".kml"; +} + + + //BYTE8 UnderStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) //{ // Proj t_Proj = _GeoStitcher->AnlayseTform(para); @@ -168,19 +202,76 @@ BYTE8 UnderStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) cv::warpPerspective(src, imagetmp, H, imagetmp.size(), cv::INTER_LINEAR, cv::BORDER_TRANSPARENT); - cv::Mat mask = cv::Mat::ones(src.size(), CV_8UC1) * 255; + cv::Mat mask = cv::Mat::ones(src.size(), CV_8UC1); mask.colRange(0, 200).setTo(0); cv::Mat warped_mask; cv::warpPerspective(mask, warped_mask, H, imagetmp.size(), cv::INTER_LINEAR); imagetmp.copyTo(_panImage, warped_mask); + + // 覆盖区域掩码更新 + _panMask = _panMask | warped_mask; + + // 生产快拼瓦片 + CutTileRealTime(); + return 0; } +void UnderStitch::CutTileRealTime() +{ + // 在4倍降采样图上计算瓦片覆盖情况 + int downSampleR = 4; + + cv::Mat panMasksmall; + cv::resize(_panMask, panMasksmall, cv::Size(_panMask.cols / downSampleR, _panMask.rows / downSampleR)); + // 计算覆盖图的积分图 + cv::Mat integralMask; + cv::integral(panMasksmall, integralMask, CV_32S); + // 遍历已经在初始化阶段得到的瓦片划分 + auto tiles = _taskTilesVec; + int cnt = 0; + for (size_t i = 0; i < tiles.size(); i++) + { + TileInfo* ptile = &_taskTilesVec[i]; + RECT32S box = ptile->boxInPan; + + // 跳过已输出块 + if (ptile->nStatus > 0) + { + //cnt++; + //continue; + } + + SINT32 x1 = box.x/ downSampleR; + SINT32 y1 = box.y/ downSampleR; + SINT32 x2 = box.x/ downSampleR + box.w/ downSampleR; + SINT32 y2 = box.y/ downSampleR + box.h/ downSampleR; + + // 使用积分图快速计算区域和 + float maskSum = integralMask.at(y2, x2) + - integralMask.at(y1, x2) + - integralMask.at(y2, x1) + + integralMask.at(y1, x1); + + // 计算瓦片影像覆盖率 + float Coverage = maskSum * downSampleR * downSampleR / (box.w * box.h); + + if (Coverage > 0.95) + { + // 输出并标记 + ptile->nStatus = 1; + _googleProduct.ExportOneTile(_panImage, *ptile, _outDir, _filename); + } + + } + + +} SINT32 UnderStitch::ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) @@ -191,8 +282,6 @@ SINT32 UnderStitch::ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) _t_frame_cache->_para = para; _t_frame_cache->_frame_info = img; - - int imgSize = 0; if(img.enPixelFormat == GD_PIXEL_FORMAT_GRAY_Y8) @@ -261,7 +350,7 @@ SINT32 UnderStitch::ProcessFrame() -bool UnderStitch::ExportGeoPng(std::string dir, std::string name) +bool UnderStitch::ExportGeoPng() { // 计算全景图的坐标范围 auto P1 = getBLHFromPan(cv::Point2f(0, 0), _H_pan); @@ -278,50 +367,27 @@ bool UnderStitch::ExportGeoPng(std::string dir, std::string name) TileInfo info = { 0 }; - info.box.north = maxB; - info.box.south = minB; - info.box.west = minL; - info.box.east = maxL; - info.tileName = name; - info.href = name + ".png"; + info.boxLatLon.north = maxB; + info.boxLatLon.south = minB; + info.boxLatLon.west = minL; + info.boxLatLon.east = maxL; + info.tileName = _filename; + info.href = _filename + ".png"; // 输出谷歌地图产品 - _googleProduct.ExportGeoPng(_panImage, info, dir); + _googleProduct.ExportGeoPng(_panImage, info, _outDir); return 0; } -bool UnderStitch::ExportGoogleTile(std::string dir, std::string name) +bool UnderStitch::ExportGoogleTile() { - // 计算全景图的坐标范围 - auto P1 = getBLHFromPan(cv::Point2f(0, 0), _H_pan); - auto P2 = getBLHFromPan(cv::Point2f(_panImage.cols, 0), _H_pan); - - auto P3 = getBLHFromPan(cv::Point2f(_panImage.cols, _panImage.rows), _H_pan); - auto P4 = getBLHFromPan(cv::Point2f(0, _panImage.rows), _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); - - TileInfo info = { 0 }; - - info.box.north = maxB; - info.box.south = minB; - info.box.west = minL; - info.box.east = maxL; - info.ind.z = _googleProduct.getZoomLevel(_panPara.scale); - - _googleProduct.ExportTile(_panImage, info, dir, name); + _googleProduct.ExportTileSet(_panImage, _taskTilesVec, _outDir, _filename); return 0; } - - GD_VIDEO_FRAME_S UnderStitch::ExportPanAddr() { GD_VIDEO_FRAME_S pan_out; diff --git a/stitch/src/Arith_UnderStitch.h b/stitch/src/Arith_UnderStitch.h index 591373c..542d030 100644 --- a/stitch/src/Arith_UnderStitch.h +++ b/stitch/src/Arith_UnderStitch.h @@ -11,13 +11,19 @@ class UnderStitch :public API_UnderStitch { public: - UnderStitch(SINT32 nWidth, SINT32 nHeight); + UnderStitch(std::string cachedir = "./cache"); ~UnderStitch(); UPanInfo Init(FrameInfo info); + void SetOutput(std::string filename, std::string outdir); + + BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para); + // 实时裁切瓦片 + void CutTileRealTime(); + // 接收帧 SINT32 ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para); @@ -25,10 +31,10 @@ public: SINT32 ProcessFrame(); // 输出地理产品:kml png全景 - bool ExportGeoPng(std::string dir, std::string name); + bool ExportGeoPng(); // - bool ExportGoogleTile(std::string dir, std::string name); + bool ExportGoogleTile(); public: @@ -62,12 +68,14 @@ private: MapBlend* _BlendTask;// 融合模块 - +private: UPanInfo _panPara;//全景图配置 - cv::Mat _H_pan;//全景图投影矩阵:从地理系到全景地图 + TileInfo _panTile;//全景图瓦片配置 + cv::Mat _H_pan;//全景图投影矩阵:从地理系到全景地图 + vector _taskTilesVec;//划分的小瓦片方案 cv::Mat _panImage; @@ -75,4 +83,11 @@ private: int _totalFrameCnt;//处理帧计数 +private: + + string _kmlPath; + string _filename;//输出文件标识 + string _outDir;//输出拼接成果路径 + string _cacheDir;//缓存路径,优先使用SSD + }; \ No newline at end of file diff --git a/stitch/src/GoogleTile.cpp b/stitch/src/GoogleTile.cpp index 097b0cc..a838dab 100644 --- a/stitch/src/GoogleTile.cpp +++ b/stitch/src/GoogleTile.cpp @@ -12,7 +12,6 @@ namespace fs = std::filesystem; googleTile::googleTile() { - } googleTile::~googleTile() @@ -40,10 +39,135 @@ void googleTile::ExportGeoPng(cv::Mat _pan, TileInfo info, std::string dir) } -void googleTile::ExportTile(cv::Mat _pan, TileInfo panInfo, std::string dir,std::string fileString) +void googleTile::ExportTileSet(cv::Mat _pan, vector taskTilesVec, std::string dir,std::string fileString) +{ + + int panWidth = _pan.cols; + int panHeight = _pan.rows; + + int zoom = taskTilesVec[0].ind.z; + + + for (size_t i = 0; i < taskTilesVec.size(); i++) + { + TileInfo tile = taskTilesVec[i]; + + TileBox tilebox = tile.boxLatLon; + + RECT32S tileBoxInPan = tile.boxInPan; + + int x1 = tileBoxInPan.x; + int x2 = tileBoxInPan.x + tileBoxInPan.w; + int y1 = tileBoxInPan.y; + int y2 = tileBoxInPan.y + tileBoxInPan.h; + + // 有不完整瓦片,不保存 + if (x1 < 0 || y1 < 0 || x2 > panWidth - 1 || y2 > panHeight - 1) + { + continue; + } + + // 确保坐标在图像范围内 + x1 = std::max(0, std::min(x1, panWidth - 1)); + y1 = std::max(0, std::min(y1, panHeight - 1)); + x2 = std::max(0, std::min(x2, panWidth - 1)); + y2 = std::max(0, std::min(y2, panHeight - 1)); + + // 提取瓦片 + cv::Rect tileRect(x1, y1, x2 - x1, y2 - y1); + cv::Mat tileImg = _pan(tileRect); + + // 标准web瓦片尺寸 + if (tileImg.cols != 256 || tileImg.rows != 256) + { + cv::resize(tileImg, tileImg, cv::Size(256, 256)); + } + + // 生成文件名 + std::string tileDir = dir + "/" + std::to_string(zoom); + std::string fileName = tileDir + "/" + std::to_string(tile.ind.x) + "_" + std::to_string(tile.ind.y) + ".png"; + // 创建目录 + if (!fs::exists(tileDir)) + { + fs::create_directories(tileDir); + } + + // 保存瓦片为图像文件 + cv::imwrite(fileName, tileImg); + + } + + + // 输出KML + WriteKml(taskTilesVec,dir + "/" + fileString + "_z" + std::to_string(zoom) + ".kml"); + +} + +void googleTile::ExportOneTile(cv::Mat _pan, TileInfo tile, std::string dir, std::string fileString) { - int zoom = panInfo.ind.z; - TileBox panBox = panInfo.box; + + int panWidth = _pan.cols; + int panHeight = _pan.rows; + int zoom = tile.ind.z; + + TileBox tilebox = tile.boxLatLon; + + RECT32S tileBoxInPan = tile.boxInPan; + + int x1 = tileBoxInPan.x; + int x2 = tileBoxInPan.x + tileBoxInPan.w; + int y1 = tileBoxInPan.y; + int y2 = tileBoxInPan.y + tileBoxInPan.h; + + // 有不完整瓦片,不保存 + if (x1 < 0 || y1 < 0 || x2 > panWidth - 1 || y2 > panHeight - 1) + { + return; + } + + // 确保坐标在图像范围内 + x1 = std::max(0, std::min(x1, panWidth - 1)); + y1 = std::max(0, std::min(y1, panHeight - 1)); + x2 = std::max(0, std::min(x2, panWidth - 1)); + y2 = std::max(0, std::min(y2, panHeight - 1)); + + // 提取瓦片 + cv::Rect tileRect(x1, y1, x2 - x1, y2 - y1); + cv::Mat tileImg = _pan(tileRect); + + // 标准web瓦片尺寸 + if (tileImg.cols != 256 || tileImg.rows != 256) + { + cv::resize(tileImg, tileImg, cv::Size(256, 256)); + } + + // 生成文件名 + std::string tileDir = dir + "/" + std::to_string(zoom); + std::string fileName = tileDir + "/" + std::to_string(tile.ind.x) + "_" + std::to_string(tile.ind.y) + ".png"; + std::string kmlPath = tileDir + "/" + std::to_string(tile.ind.x) + "_" + std::to_string(tile.ind.y) + ".kml"; + + tile.href = std::to_string(tile.ind.x) + "_" + std::to_string(tile.ind.y) + ".png"; + + // 创建目录 + if (!fs::exists(tileDir)) + { + fs::create_directories(tileDir); + } + + // 保存瓦片为图像文件 + cv::imwrite(fileName, tileImg); + + vector info; + info.push_back(tile); + WriteKml(info, kmlPath); +} + + + +vector googleTile::CalcTileOverlayVec(TileInfo areaInfo,int panWidth,int panHeight) +{ + int zoom = areaInfo.ind.z; + TileBox panBox = areaInfo.boxLatLon; // 计算四至的瓦片编号 TileIndex WN = LatLonToTile(panBox.north, panBox.west, zoom); @@ -57,8 +181,6 @@ void googleTile::ExportTile(cv::Mat _pan, TileInfo panInfo, std::string dir,std: int yStart = EN.y; int yEnd = ES.y; - int panWidth = _pan.cols; - int panHeight = _pan.rows; vector taskTiles; @@ -66,54 +188,32 @@ void googleTile::ExportTile(cv::Mat _pan, TileInfo panInfo, std::string dir,std: { for (size_t j = xStart; j < xEnd; j++) { - TileIndex id = {j,i,zoom}; + TileIndex id = { j,i,zoom }; TileBox tilebox = GetTileBox(id); - // 填充 - TileInfo info = { 0 }; - info.box = tilebox; - info.ind = id; - - // 计算瓦片在全景图中的像素位置 - int x1 = (tilebox.west - panBox.west) / (panBox.east - panBox.west) * panWidth; - int y1 = (panBox.north - tilebox.north) / (panBox.north - panBox.south) * panHeight; - int x2 = (tilebox.east - panBox.west) / (panBox.east - panBox.west) * panWidth; - int y2 = (panBox.north - tilebox.south) / (panBox.north - panBox.south) * panHeight; - - // 有不完整瓦片,不保存 - if (x1 < 0 || y1 < 0 || x2 > panWidth - 1 || y2 > panHeight - 1) + // 瓦片不完整覆盖则不输出 + if (tilebox.west < panBox.west|| panBox.north < tilebox.north + || tilebox.east > panBox.east || panBox.south > tilebox.south) { continue; } - // 确保坐标在图像范围内 - x1 = std::max(0, std::min(x1, panWidth - 1)); - y1 = std::max(0, std::min(y1, panHeight - 1)); - x2 = std::max(0, std::min(x2, panWidth - 1)); - y2 = std::max(0, std::min(y2, panHeight - 1)); - - // 提取瓦片 - cv::Rect tileRect(x1, y1, x2 - x1, y2 - y1); - cv::Mat tile = _pan(tileRect); - - // 标准web瓦片尺寸 - // if (tile.cols != 256 || tile.rows != 256) - // { - // cv::resize(tile, tile, cv::Size(256, 256)); - // } - - // 生成文件名 - std::string tileDir = dir + "/" + std::to_string(zoom); - std::string fileName = tileDir + "/" + std::to_string(j) + "_" + std::to_string(i) + ".png"; - // 创建目录 - if (!fs::exists(tileDir)) - { - fs::create_directories(tileDir); - } - // 保存瓦片为图像文件 - cv::imwrite(fileName, tile); + // 计算瓦片在全景图中的像素位置 + RECT32S rect = { 0 }; + rect.x = (tilebox.west - panBox.west) / (panBox.east - panBox.west) * panWidth; + rect.y = (panBox.north - tilebox.north) / (panBox.north - panBox.south) * panHeight; + rect.w = (tilebox.east - panBox.west) / (panBox.east - panBox.west) * panWidth - rect.x; + rect.h = (panBox.north - tilebox.south) / (panBox.north - panBox.south) * panHeight - rect.y; + + + + // 填充 + TileInfo info = { 0 }; + info.boxLatLon = tilebox; + info.ind = id; + info.boxInPan = rect; // 补充瓦片信息 info.tileName = std::to_string(j) + "_" + std::to_string(i) + "_" + std::to_string(zoom); @@ -123,16 +223,14 @@ void googleTile::ExportTile(cv::Mat _pan, TileInfo panInfo, std::string dir,std: taskTiles.push_back(info); } - + } - - // 输出KML - WriteKml(taskTiles,dir + "/" + fileString + "_z" + std::to_string(zoom) + ".kml"); + return taskTiles; } -int googleTile::getZoomLevel(float mp) +int googleTile::ZoomLevel(float mp) { int nLev = 0; // 计算单位瓦片的实际覆盖 @@ -140,11 +238,12 @@ int googleTile::getZoomLevel(float mp) int earthLen = 40075017; - nLev = std::floor(std::log2(earthLen / meters_cover)); + nLev = std::floor(std::log2(earthLen / meters_cover)) + 1; return nLev; } + TileIndex googleTile::LatLonToTile(double latitude, double longitude, int zoomLevel) { // 将纬度转换为墨卡托投影 @@ -206,10 +305,10 @@ void googleTile::WriteKml(vector tiles, string filePath) kml_file << " " << tile.href << "" << std::endl; kml_file << " " << std::endl; kml_file << " " << std::endl; - kml_file << " " << tile.box.north << "" << std::endl; - kml_file << " " << tile.box.south << "" << std::endl; - kml_file << " " << tile.box.east << "" << std::endl; - kml_file << " " << tile.box.west << "" << std::endl; + kml_file << " " << std::fixed << std::setprecision(6) << tile.boxLatLon.north << "" << std::endl; + kml_file << " " << std::fixed << std::setprecision(6) << tile.boxLatLon.south << "" << std::endl; + kml_file << " " << std::fixed << std::setprecision(6) << tile.boxLatLon.east << "" << std::endl; + kml_file << " " << std::fixed << std::setprecision(6) << tile.boxLatLon.west << "" << std::endl; kml_file << " " << std::endl; kml_file << "" << std::endl; } @@ -223,6 +322,3 @@ void googleTile::WriteKml(vector tiles, string filePath) } - - - diff --git a/stitch/src/GoogleTile.h b/stitch/src/GoogleTile.h index 28298e1..ec479bb 100644 --- a/stitch/src/GoogleTile.h +++ b/stitch/src/GoogleTile.h @@ -4,10 +4,11 @@ #include #include #include - +#include "StitchStruct.h" using std::vector; using std::string; + struct TileIndex { int x; @@ -23,14 +24,20 @@ struct TileBox double west; }; + + +// 瓦片信息 struct TileInfo { TileIndex ind; std::string tileName; std::string href;//相对路径 - TileBox box; + TileBox boxLatLon; + RECT32S boxInPan; + SINT32 nStatus;//状态:0-未输出 1-已输出 2-已优化并输出 }; +// 标准web瓦片大小 const int TILE_SIZE = 256; class googleTile @@ -43,23 +50,25 @@ public: // 输出kml png void ExportGeoPng(cv::Mat _pan, TileInfo info, std::string dir); - // 输出tile - void ExportTile(cv::Mat _pan, TileInfo info, std::string dir, std::string fileString); + // 输出tile组 + void ExportTileSet(cv::Mat _pan, vector taskTilesVec, std::string dir, std::string fileString); + + // 输出单个tile + void ExportOneTile(cv::Mat _pan, TileInfo tile, std::string dir, std::string fileString); - // 计算给定分辨率最接近的瓦片等级,mp单位 米/像素 - int getZoomLevel(float mp); + // 使用感兴趣区大瓦片计算小瓦片覆盖表 + vector CalcTileOverlayVec(TileInfo areaInfo, int panWidth, int panHeight); + + // 计算给定分辨率最接近的瓦片等级,mp单位 米/像素 + int ZoomLevel(float mp); private: TileIndex LatLonToTile(double latitude, double longitude, int zoomLevel); // 瓦片编号对应的信息 TileBox GetTileBox(TileIndex ind); - - void WriteKml(vector tiles,string filePath); - - int zoom_; - + void WriteKml(vector tiles, string filePath); };