补充瓦片生成

main
wangchongwu 5 months ago
parent 65f705aabe
commit 68327492bf

@ -216,7 +216,10 @@ void ProcessIR()
waitKey(0); waitKey(0);
// 输出谷歌png // 输出谷歌png
stitcher->ExportGeoPng("D:/", "IR_pan"); stitcher->ExportGeoPng("D:/google_tiles", "IR_pan");
// 输出谷歌tile
stitcher->ExportGoogleTile("D:/google_tiles", "IR_tiles");
} }
@ -333,10 +336,10 @@ void ProcessVL()
waitKey(0); waitKey(0);
// 输出谷歌png // 输出谷歌png
stitcher->ExportGeoPng("D:/", "VL_pan"); stitcher->ExportGeoPng("D:/google_tiles", "VL_pan");
// 输出谷歌tile // 输出谷歌tile
stitcher->ExportGoogleTile("D:/", "VL_pan"); stitcher->ExportGoogleTile("D:/google_tiles", "VL_tiles");
} }

@ -12,14 +12,14 @@ endif()
IF(WIN32) IF(WIN32)
set(OpenCV_DIR "D:/opencv410_vc17") set(OpenCV_DIR "D:/opencv410_vc17")
set(CMAKE_TOOLCHAIN_FILE "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/scripts/buildsystems/vcpkg.cmake")
# set(CMAKE_TOOLCHAIN_FILE "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/scripts/buildsystems/vcpkg.cmake") # set(CMAKE_TOOLCHAIN_FILE "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/scripts/buildsystems/vcpkg.cmake")
# set(Ceres_DIR "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/packages/ceres_x64-windows/share/ceres") # set(Ceres_DIR "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/packages/ceres_x64-windows/share/ceres")
# set(Eigen3_DIR "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/packages/eigen3_x64-windows/share/eigen3") # set(Eigen3_DIR "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/packages/eigen3_x64-windows/share/eigen3")
# set(glog_DIR "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/packages/glog_x64-windows/share/glog") # set(glog_DIR "D:/wangchongwu_gitea_2023/vcpkg-2025.01.13/packages/glog_x64-windows/share/glog")
ELSE(WIN32) ELSE(WIN32)
ENDIF(WIN32) ENDIF(WIN32)
find_package(Ceres REQUIRED) find_package(Ceres REQUIRED)
include_directories(${CERES_INCLUDE_DIRS}) include_directories(${CERES_INCLUDE_DIRS})

@ -153,8 +153,6 @@ BYTE8 VideoStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para)
// uv2Geo H // uv2Geo H
cv::Mat H1 = _GeoSolver->findHomography(para); cv::Mat H1 = _GeoSolver->findHomography(para);
cv::Mat H2 = _GeoSolver->findHomography2(para);
cv::Mat H = _H_pan * H1; cv::Mat H = _H_pan * H1;
// 利用H投影当前帧到全景 // 利用H投影当前帧到全景
@ -330,13 +328,15 @@ bool VideoStitch::ExportGeoPng(std::string dir, std::string name)
TileInfo info = { 0 }; TileInfo info = { 0 };
info.north = maxB; info.box.north = maxB;
info.south = minB; info.box.south = minB;
info.east = minL; info.box.west = minL;
info.west = maxL; info.box.east = maxL;
info.tileName = name;
info.href = name + ".png";
// 输出谷歌地图产品 // 输出谷歌地图产品
_googleProduct.ExportGeoPng(_panImage, info, dir, name); _googleProduct.ExportGeoPng(_panImage, info, dir);
return 0; return 0;
} }
@ -360,12 +360,13 @@ bool VideoStitch::ExportGoogleTile(std::string dir, std::string name)
TileInfo info = { 0 }; TileInfo info = { 0 };
info.north = maxB; info.box.north = maxB;
info.south = minB; info.box.south = minB;
info.east = minL; info.box.west = minL;
info.west = maxL; info.box.east = maxL;
info.ind.z = 17;
_googleProduct.ExportTile(_panImage, info, dir, name); _googleProduct.ExportTile(_panImage, info, dir);
return 0; return 0;
} }

@ -7,7 +7,7 @@
#include <filesystem> #include <filesystem>
using std::string; using std::string;
namespace fs = std::filesystem;
#define M_PI 3.1415926 #define M_PI 3.1415926
googleTile::googleTile() googleTile::googleTile()
@ -19,50 +19,111 @@ googleTile::~googleTile()
{ {
} }
void googleTile::ExportGeoPng(cv::Mat _pan, TileInfo info, std::string dir, std::string name) void googleTile::ExportGeoPng(cv::Mat _pan, TileInfo info, std::string dir)
{ {
// 创建目录
if (!fs::exists(dir))
{
fs::create_directories(dir);
}
// 保存全景图 // 保存全景图
string png_path = dir + "/" + name + ".png"; string png_path = dir + "/" + info.tileName + ".png";
cv::imwrite(png_path, _pan); cv::imwrite(png_path, _pan);
// 写入kml // 写入kml
string kml_path = dir + "/" + name + ".kml"; string kml_path = dir + "/" + info.tileName + ".kml";
std::ofstream kml_file(kml_path);
// 写入 KML 文件的头部 vector<TileInfo> taskTiles;
kml_file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; taskTiles.push_back(info);
kml_file << "<kml xmlns=\"http://www.opengis.net/kml/2.2\">" << std::endl; WriteKml(taskTiles, kml_path);
kml_file << "<Document>" << std::endl;
// 写入 GroundOverlay 元素
kml_file << "<GroundOverlay>" << std::endl;
kml_file << " <name>My Panoramic Image</name>" << std::endl;
kml_file << " <Icon>" << std::endl;
kml_file << " <href>" << name + ".png" << "</href>" << std::endl;
kml_file << " </Icon>" << std::endl;
// 使用四个角点计算 LatLonBox
kml_file << " <LatLonBox>" << std::endl;
kml_file << " <north>" << info.north << "</north>" << std::endl; // 经度范围
kml_file << " <south>" << info.south << "</south>" << std::endl;
kml_file << " <east>" << info.east << "</east>" << std::endl; // 纬度范围
kml_file << " <west>" << info.west << "</west>" << std::endl;
kml_file << " </LatLonBox>" << std::endl;
// 写入 KML 文件的尾部
kml_file << "</GroundOverlay>" << std::endl;
kml_file << "</Document>" << std::endl;
kml_file << "</kml>" << std::endl;
kml_file.close();
} }
void googleTile::ExportTile(cv::Mat _pan, TileInfo info, std::string dir, std::string name) void googleTile::ExportTile(cv::Mat _pan, TileInfo panInfo, std::string dir)
{ {
int zoom = panInfo.ind.z;
TileBox panBox = panInfo.box;
// 计算四至的瓦片编号 // 计算四至的瓦片编号
TileIndex westNorth = LatLonToTile(info.west, info.north, 10); TileIndex WN = LatLonToTile(panBox.north, panBox.west, zoom);
int a = 0; TileIndex WS = LatLonToTile(panBox.south, panBox.west, zoom);
TileIndex EN = LatLonToTile(panBox.north, panBox.east, zoom);
TileIndex ES = LatLonToTile(panBox.south, panBox.east, zoom);
int xStart = WN.x;
int xEnd = EN.x;
int yStart = EN.y;
int yEnd = ES.y;
int panWidth = _pan.cols;
int panHeight = _pan.rows;
vector<TileInfo> taskTiles;
for (size_t i = yStart; i < yEnd; i++)
{
for (size_t j = xStart; j < xEnd; j++)
{
TileIndex id = {j,i,17};
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)
{
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);
// 生成文件名
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);
// 补充瓦片信息
info.tileName = std::to_string(j) + "_" + std::to_string(i) + "_" + std::to_string(zoom);
info.href = std::to_string(zoom) + "/" + std::to_string(j) + "_" + std::to_string(i) + ".png";
taskTiles.push_back(info);
}
}
// 输出KML
WriteKml(taskTiles,dir + "/" + "tile" + std::to_string(zoom) + ".kml");
} }
TileIndex googleTile::LatLonToTile(double latitude, double longitude, int zoomLevel) TileIndex googleTile::LatLonToTile(double latitude, double longitude, int zoomLevel)
@ -81,6 +142,68 @@ TileIndex googleTile::LatLonToTile(double latitude, double longitude, int zoomLe
} }
// 将瓦片编号转换为经纬度
void TileToLatLon(int x, int y, int z, double& lat, double& lon)
{
double n = std::pow(2.0, z);
lon = x / n * 360.0 - 180.0;
double lat_rad = std::atan(std::sinh(M_PI * (1 - 2 * y / n)));
lat = lat_rad * 180.0 / M_PI;
}
TileBox googleTile::GetTileBox(TileIndex ind)
{
TileBox box = {0};
// 计算瓦片的西北角经纬度
TileToLatLon(ind.x, ind.y, ind.z, box.north, box.west);
// 计算瓦片的东南角经纬度
TileToLatLon(ind.x + 1, ind.y + 1, ind.z, box.south, box.east);
return box;
}
void googleTile::WriteKml(vector<TileInfo> tiles, string filePath)
{
// Open the KML file for writing
std::ofstream kml_file(filePath);
if (!kml_file.is_open()) {
std::cerr << "Failed to open KML file for writing: " << filePath << std::endl;
return;
}
// Write the KML header
kml_file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
kml_file << "<kml xmlns=\"http://www.opengis.net/kml/2.2\">" << std::endl;
kml_file << "<Document>" << std::endl;
// Loop through each tile and write a GroundOverlay element
for (const auto& tile : tiles)
{
kml_file << "<GroundOverlay>" << std::endl;
kml_file << " <name>" << tile.tileName << "</name>" << std::endl;
kml_file << " <Icon>" << std::endl;
kml_file << " <href>" << tile.href << "</href>" << std::endl;
kml_file << " </Icon>" << std::endl;
kml_file << " <LatLonBox>" << std::endl;
kml_file << " <north>" << tile.box.north << "</north>" << std::endl;
kml_file << " <south>" << tile.box.south << "</south>" << std::endl;
kml_file << " <east>" << tile.box.east << "</east>" << std::endl;
kml_file << " <west>" << tile.box.west << "</west>" << std::endl;
kml_file << " </LatLonBox>" << std::endl;
kml_file << "</GroundOverlay>" << std::endl;
}
// Write the KML footer
kml_file << "</Document>" << std::endl;
kml_file << "</kml>" << std::endl;
// Close the file
kml_file.close();
}

@ -5,6 +5,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
using std::vector;
using std::string;
struct TileIndex struct TileIndex
{ {
int x; int x;
@ -12,15 +15,22 @@ struct TileIndex
int z; int z;
}; };
struct TileInfo struct TileBox
{ {
TileIndex ind;
double north; double north;
double south; double south;
double east; double east;
double west; double west;
}; };
struct TileInfo
{
TileIndex ind;
std::string tileName;
std::string href;//相对路径
TileBox box;
};
class googleTile class googleTile
{ {
@ -30,15 +40,20 @@ public:
public: public:
// 输出kml png // 输出kml png
void ExportGeoPng(cv::Mat _pan, TileInfo info, std::string dir, std::string name); void ExportGeoPng(cv::Mat _pan, TileInfo info, std::string dir);
// 输出tile // 输出tile
void ExportTile(cv::Mat _pan, TileInfo info, std::string dir, std::string name); void ExportTile(cv::Mat _pan, TileInfo info, std::string dir);
public: public:
TileIndex LatLonToTile(double latitude, double longitude, int zoomLevel); TileIndex LatLonToTile(double latitude, double longitude, int zoomLevel);
private: private:
// 瓦片编号对应的信息
TileBox GetTileBox(TileIndex ind);
void WriteKml(vector<TileInfo> tiles,string filePath);
int zoom_; int zoom_;

Loading…
Cancel
Save