实时动态切瓦片,流式输出

main
wangchongwu 4 months ago
parent 12bd9ad91d
commit cfc2925cf1

@ -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");
}

@ -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);
};

@ -39,7 +39,7 @@ void MapBlend::DirectMap(vector<KeyType> 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);

@ -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<FrameCache>(50, cachedir);
_GeoSolver = new GeoSolver();
_FeaMatcher = new FeatureMatcher(DetectorType::SIFT, MatcherType::FLANN);
_cache = new FileCache<FrameCache>(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<int>(y2, x2)
- integralMask.at<int>(y1, x2)
- integralMask.at<int>(y2, x1)
+ integralMask.at<int>(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;

@ -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<TileInfo> _taskTilesVec;//划分的小瓦片方案
cv::Mat _panImage;
@ -75,4 +83,11 @@ private:
int _totalFrameCnt;//处理帧计数
private:
string _kmlPath;
string _filename;//输出文件标识
string _outDir;//输出拼接成果路径
string _cacheDir;//缓存路径优先使用SSD
};

@ -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<TileInfo> 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<TileInfo> info;
info.push_back(tile);
WriteKml(info, kmlPath);
}
vector<TileInfo> 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<TileInfo> 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<TileInfo> tiles, string filePath)
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 << " <north>" << std::fixed << std::setprecision(6) << tile.boxLatLon.north << "</north>" << std::endl;
kml_file << " <south>" << std::fixed << std::setprecision(6) << tile.boxLatLon.south << "</south>" << std::endl;
kml_file << " <east>" << std::fixed << std::setprecision(6) << tile.boxLatLon.east << "</east>" << std::endl;
kml_file << " <west>" << std::fixed << std::setprecision(6) << tile.boxLatLon.west << "</west>" << std::endl;
kml_file << " </LatLonBox>" << std::endl;
kml_file << "</GroundOverlay>" << std::endl;
}
@ -223,6 +322,3 @@ void googleTile::WriteKml(vector<TileInfo> tiles, string filePath)
}

@ -4,10 +4,11 @@
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>
#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<TileInfo> 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<TileInfo> 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<TileInfo> tiles,string filePath);
int zoom_;
void WriteKml(vector<TileInfo> tiles, string filePath);
};

Loading…
Cancel
Save