parent
e9e024406a
commit
3e784fb999
@ -0,0 +1,154 @@
|
||||
#include "googleTile.h"
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
|
||||
googleTile::googleTile(const cv::Mat& img, const std::vector<std::pair<double, double>>& geoCorners, int zoom, const std::string& outputDir)
|
||||
{
|
||||
image_ = img.clone();
|
||||
geoCorners_ = geoCorners;
|
||||
zoom_ = zoom;
|
||||
outputDir_ = outputDir;
|
||||
}
|
||||
|
||||
cv::Point2f googleTile::latLonToGlobal(double lat, double lon)
|
||||
{
|
||||
double tileSize = 256.0;
|
||||
double n = std::pow(2.0, zoom_);
|
||||
double x = (lon + 180.0) / 360.0 * tileSize * n;
|
||||
double latRad = lat * CV_PI / 180.0;
|
||||
double y = (1 - std::log(std::tan(latRad) + 1 / std::cos(latRad)) / CV_PI) / 2 * tileSize * n;
|
||||
return cv::Point2f(static_cast<float>(x), static_cast<float>(y));
|
||||
}
|
||||
|
||||
std::pair<double, double> googleTile::globalToLatLon(const cv::Point2f& pt)
|
||||
{
|
||||
double tileSize = 256.0;
|
||||
double n = std::pow(2.0, zoom_);
|
||||
double lon = pt.x / (tileSize * n) * 360.0 - 180.0;
|
||||
double latRad = std::atan(std::sinh(CV_PI * (1 - 2 * pt.y / (tileSize * n))));
|
||||
double lat = latRad * 180.0 / CV_PI;
|
||||
return std::make_pair(lat, lon);
|
||||
}
|
||||
|
||||
cv::Mat googleTile::computeHomography()
|
||||
{
|
||||
std::vector<cv::Point2f> srcPts;
|
||||
std::vector<cv::Point2f> dstPts;
|
||||
|
||||
for (const auto& corner : geoCorners_)
|
||||
{
|
||||
srcPts.push_back(latLonToGlobal(corner.first, corner.second));
|
||||
}
|
||||
|
||||
dstPts.push_back(cv::Point2f(0.0f, 0.0f));
|
||||
dstPts.push_back(cv::Point2f(static_cast<float>(image_.cols), 0.0f));
|
||||
dstPts.push_back(cv::Point2f(static_cast<float>(image_.cols), static_cast<float>(image_.rows)));
|
||||
dstPts.push_back(cv::Point2f(0.0f, static_cast<float>(image_.rows)));
|
||||
|
||||
return cv::getPerspectiveTransform(srcPts, dstPts);
|
||||
}
|
||||
|
||||
void googleTile::generateKML(const std::vector<TileInfo>& tiles)
|
||||
{
|
||||
std::string kmlPath = outputDir_ + "/tiles.kml";
|
||||
std::ofstream ofs(kmlPath);
|
||||
if (!ofs)
|
||||
{
|
||||
std::cerr << "无法创建 KML 文件: " << kmlPath << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ofs << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
ofs << "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n";
|
||||
ofs << " <Document>\n";
|
||||
|
||||
for (const auto& tile : tiles)
|
||||
{
|
||||
ofs << " <GroundOverlay>\n";
|
||||
ofs << " <name>" << zoom_ << "/" << tile.x << "/" << tile.y << ".png</name>\n";
|
||||
ofs << " <Icon>\n";
|
||||
ofs << " <href>" << zoom_ << "/" << tile.x << "/" << tile.y << ".png</href>\n";
|
||||
ofs << " </Icon>\n";
|
||||
ofs << " <LatLonBox>\n";
|
||||
ofs << " <north>" << tile.north << "</north>\n";
|
||||
ofs << " <south>" << tile.south << "</south>\n";
|
||||
ofs << " <east>" << tile.east << "</east>\n";
|
||||
ofs << " <west>" << tile.west << "</west>\n";
|
||||
ofs << " </LatLonBox>\n";
|
||||
ofs << " </GroundOverlay>\n";
|
||||
}
|
||||
|
||||
ofs << " </Document>\n";
|
||||
ofs << "</kml>\n";
|
||||
|
||||
ofs.close();
|
||||
std::cout << "生成 KML 文件:" << kmlPath << std::endl;
|
||||
}
|
||||
|
||||
void googleTile::generateTiles()
|
||||
{
|
||||
std::filesystem::create_directories(outputDir_);
|
||||
cv::Mat H = computeHomography();
|
||||
|
||||
std::vector<cv::Point2f> globalCorners;
|
||||
for (const auto& corner : geoCorners_)
|
||||
{
|
||||
globalCorners.push_back(latLonToGlobal(corner.first, corner.second));
|
||||
}
|
||||
|
||||
float minX = globalCorners[0].x, maxX = globalCorners[0].x;
|
||||
float minY = globalCorners[0].y, maxY = globalCorners[0].y;
|
||||
|
||||
for (const auto& p : globalCorners)
|
||||
{
|
||||
minX = std::min(minX, p.x);
|
||||
maxX = std::max(maxX, p.x);
|
||||
minY = std::min(minY, p.y);
|
||||
maxY = std::max(maxY, p.y);
|
||||
}
|
||||
|
||||
int tileSize = 256;
|
||||
int xTileMin = static_cast<int>(std::floor(minX / tileSize));
|
||||
int xTileMax = static_cast<int>(std::floor(maxX / tileSize));
|
||||
int yTileMin = static_cast<int>(std::floor(minY / tileSize));
|
||||
int yTileMax = static_cast<int>(std::floor(maxY / tileSize));
|
||||
|
||||
std::vector<TileInfo> tileInfos;
|
||||
|
||||
for (int tx = xTileMin; tx <= xTileMax; tx++)
|
||||
{
|
||||
for (int ty = yTileMin; ty <= yTileMax; ty++)
|
||||
{
|
||||
std::vector<cv::Point2f> tileGlobalPts = {
|
||||
{cv::Point2f(tx * tileSize, ty * tileSize)},
|
||||
{cv::Point2f((tx + 1) * tileSize, ty * tileSize)},
|
||||
{cv::Point2f((tx + 1) * tileSize, (ty + 1) * tileSize)},
|
||||
{cv::Point2f(tx * tileSize, (ty + 1) * tileSize)} };
|
||||
|
||||
std::vector<cv::Point2f> tileImgPts;
|
||||
cv::perspectiveTransform(tileGlobalPts, tileImgPts, H);
|
||||
|
||||
//cv::Mat tileTransform = cv::getPerspectiveTransform(tileImgPts, {
|
||||
// {0, 0}, {tileSize, 0}, {tileSize, tileSize}, {0, tileSize} });
|
||||
|
||||
cv::Mat tileImg;
|
||||
//cv::warpPerspective(image_, tileImg, tileTransform, cv::Size(tileSize, tileSize));
|
||||
|
||||
std::string tileDir = outputDir_ + "/" + std::to_string(zoom_) + "/" + std::to_string(tx);
|
||||
std::filesystem::create_directories(tileDir);
|
||||
std::string tilePath = tileDir + "/" + std::to_string(ty) + ".png";
|
||||
|
||||
cv::imwrite(tilePath, tileImg);
|
||||
tileInfos.push_back({ tx, ty, globalToLatLon({cv::Point2f(tx * tileSize, ty * tileSize)}).first,
|
||||
globalToLatLon({cv::Point2f((tx + 1) * tileSize, (ty + 1) * tileSize)}).first,
|
||||
globalToLatLon({cv::Point2f((tx + 1) * tileSize, (ty + 1) * tileSize)}).second,
|
||||
globalToLatLon({cv::Point2f(tx * tileSize, ty * tileSize)}).second });
|
||||
}
|
||||
}
|
||||
|
||||
generateKML(tileInfos);
|
||||
}
|
Loading…
Reference in new issue