#include "googleTile.h" #include #include #include #include #include #include googleTile::googleTile(const cv::Mat& img, const std::vector>& 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(x), static_cast(y)); } std::pair 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 srcPts; std::vector 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(image_.cols), 0.0f)); dstPts.push_back(cv::Point2f(static_cast(image_.cols), static_cast(image_.rows))); dstPts.push_back(cv::Point2f(0.0f, static_cast(image_.rows))); return cv::getPerspectiveTransform(srcPts, dstPts); } void googleTile::generateKML(const std::vector& tiles) { std::string kmlPath = outputDir_ + "/tiles.kml"; std::ofstream ofs(kmlPath); if (!ofs) { std::cerr << "无法创建 KML 文件: " << kmlPath << std::endl; return; } ofs << "\n"; ofs << "\n"; ofs << " \n"; for (const auto& tile : tiles) { ofs << " \n"; ofs << " " << zoom_ << "/" << tile.x << "/" << tile.y << ".png\n"; ofs << " \n"; ofs << " " << zoom_ << "/" << tile.x << "/" << tile.y << ".png\n"; ofs << " \n"; ofs << " \n"; ofs << " " << tile.north << "\n"; ofs << " " << tile.south << "\n"; ofs << " " << tile.east << "\n"; ofs << " " << tile.west << "\n"; ofs << " \n"; ofs << " \n"; } ofs << " \n"; ofs << "\n"; ofs.close(); std::cout << "生成 KML 文件:" << kmlPath << std::endl; } void googleTile::generateTiles() { std::filesystem::create_directories(outputDir_); cv::Mat H = computeHomography(); std::vector 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(std::floor(minX / tileSize)); int xTileMax = static_cast(std::floor(maxX / tileSize)); int yTileMin = static_cast(std::floor(minY / tileSize)); int yTileMax = static_cast(std::floor(maxY / tileSize)); std::vector tileInfos; for (int tx = xTileMin; tx <= xTileMax; tx++) { for (int ty = yTileMin; ty <= yTileMax; ty++) { std::vector 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 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); }