|
|
|
@ -7,7 +7,7 @@
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
|
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
#define M_PI 3.1415926
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 写入kml
|
|
|
|
|
string kml_path = dir + "/" + name + ".kml";
|
|
|
|
|
std::ofstream kml_file(kml_path);
|
|
|
|
|
string kml_path = dir + "/" + info.tileName + ".kml";
|
|
|
|
|
|
|
|
|
|
// 写入 KML 文件的头部
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
// 写入 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;
|
|
|
|
|
vector<TileInfo> taskTiles;
|
|
|
|
|
taskTiles.push_back(info);
|
|
|
|
|
WriteKml(taskTiles, kml_path);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
int a = 0;
|
|
|
|
|
TileIndex WN = LatLonToTile(panBox.north, panBox.west, zoom);
|
|
|
|
|
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)
|
|
|
|
@ -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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|