前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >影像瓦片切割

影像瓦片切割

作者头像
Freedom123
发布2024-03-29 08:28:06
550
发布2024-03-29 08:28:06
举报
文章被收录于专栏:DevOpsDevOps
代码语言:javascript
复制
#include "gdal_priv.h"  
#include "ogrsf_frmts.h"  
#include <algorithm>

bool ImageTile::processByscale(std::string srcimagename, std::string outpath, int tilesize, std::string formattype, double scale, int threadSize, int levelNo)
{
	//初始化成员变量
	GDALAllRegister();
	m_format = formattype;
	m_srcimagename = srcimagename;
	m_outputstr = outpath;
	m_levelNo = levelNo;
	getOGRGeoTransform(); // 获取图层参数信息
	this->tilesize = tilesize;
	double level = scale2Level(scale);
	int xNum = 1.0*m_srcWidth / tilesize / level + 1;
	int yNum = 1.0*m_srcHeight / tilesize / level + 1;

	std::string levelNoPath;
	int x = 0;
	int count = GetSpliteCols();
	while (x < xNum) //列数
	{
		int xCount = count;
		if (x + xCount > xNum) {
			xCount = xNum - x;
		}
		
		if (m_levelNo <= 0) {
			if (!spliteNCols(xNum, yNum, x, xCount, level, m_outputstr, m_format, m_srcimagename, m_bandcount, threadSize)) {
				std::cout << "Failed spliteNCols" << std::endl;
				return false;
			}
		}
		else {			
			if (0 == x) {
				std::stringstream ss;
				ss << "L" << m_levelNo;
				levelNoPath = TDAPICommon::JoinPath(m_outputstr, ss.str());
				if (!CreatePath(levelNoPath, yNum, xNum)) {
					std::cout << "Failed CreatePath," << levelNoPath << std::endl;
					return false;
				}
			}
			if (!spliteElectronicMap(xNum, yNum, x, xCount, level, levelNoPath, m_format, m_srcimagename, m_bandcount, threadSize)) {
				std::cout << "Failed spliteElectronicMap" << std::endl;
				return false;
			}
		}

		x += xCount;
	}

	return true;
}

bool ImageTile::spliteElectronicMap(int xNum, int yNum, int x, int xCount, double level, std::string filepath, std::string formattype, std::string srcimagename, int bandCount, int threadSize)
{
	std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();

	std::string dstTileSuffixName = TDRasterCommon::GetSuffixByDriver(formattype);
	if (dstTileSuffixName.empty()) {
		std::cout << "No file suffix corresponding to " << formattype << " driver was found" << std::endl;
		return false;
	}

	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	auto armDriver = GetGDALDriverManager()->GetDriverByName(formattype.c_str());
	auto poDriver = GetGDALDriverManager()->GetDriverByName("MEM");

	if (nullptr == armDriver) {
		std::cout << "Gdal driver " << formattype << "does not exist" << std::endl;
		return false;
	}

	auto srcDataset = (GDALDataset*)GDALOpen(srcimagename.c_str(), GA_ReadOnly); //获取原始数据句柄
	if (nullptr == srcDataset) {
		std::cout << " Failed to open " << srcimagename << std::endl;
		return false;
	}
	auto pProjection = srcDataset->GetProjectionRef();
	if (nullptr == pProjection) {
		std::cout << "GetProjectionRef returns nullptr" << std::endl;
		return false;
	}

	//GDALRasterIOExtraArg exterArg;
	//INIT_RASTERIO_EXTRA_ARG(exterArg);
	//exterArg.eResampleAlg = GDALRIOResampleAlg::GRIORA_Bilinear;

	//读取影响的位置
	double startX = x * tilesize *level;
	double startY = 0;
	double sw = (m_srcWidth - (xNum - 1)*tilesize * level) / (tilesize * level);
	double w = m_srcWidth - (xNum - 1)*tilesize * level;
	double sh = (m_srcHeight - (yNum - 1)*tilesize * level) / (tilesize * level);
	double h = m_srcHeight - (yNum - 1)*tilesize * level;

	//
	size_t storeWidth = 0;
	//读取影像的宽度
	size_t readWidth = 0;

	if (x + xCount == xNum) {
		readWidth = tilesize * (xCount - 1)*level + w;
		storeWidth = tilesize * (xCount - 1) + tilesize * sw;
	}
	else {
		readWidth = tilesize * level* xCount;
		storeWidth = tilesize * xCount;
	}

	//读取影像的高度
	size_t readHeight = m_srcHeight;
	size_t storeHeight = tilesize * (yNum - 1) + tilesize * sh;

	//开辟空间
	size_t imgBufNum = storeWidth * storeHeight * bandCount;
	GByte *imgBuf = new GByte[imgBufNum];
	memset(imgBuf, 0, imgBufNum);

	//读取N列瓦片影像
	srcDataset->RasterIO(GF_Read, startX, startY, readWidth, readHeight, imgBuf, storeWidth, storeHeight,
		GDT_Byte, bandCount, nullptr, 0, 0, 0);
	std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
	std::cout << "read raster time : " << std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << " s" << std::endl;
	ThreadPool::ThreadPool threadPool(1, threadSize);
	for (size_t y = 0; y < yNum; ++y) {
		size_t tileSizeX = tilesize;
		size_t tileSizeY = tilesize;
		if ((yNum - 1) == y) {
			tileSizeY = tilesize * sh;
		}

		for (size_t i = 0; i < xCount; ++i) {
			size_t curX = x + i;
			if ((xNum - 1) == curX) {
				tileSizeX = tilesize * sw;
			}

			threadPool.CommitOneTask([this, curX, i, y, level, tileSizeX, tileSizeY, storeWidth, storeHeight, armDriver, poDriver, filepath, dstTileSuffixName, bandCount, srcDataset, imgBuf, pProjection]()
			{
				std::stringstream ss;
				ss << filepath << "/R" << curX << "/C" << y;
				std::string outputFilePath = ss.str();
				TDAPICommon::CreateDir(outputFilePath);

				ss.str("");
				ss << outputFilePath << "/" << curX << y << m_levelNo;
				std::string outputBaseFileName = ss.str();
				std::string  memName = outputBaseFileName + ".tif"; // 配置输出参数
				std::string  target_name = outputBaseFileName + dstTileSuffixName; // 配置输出参数				
				GDALDataset* poDstDS;
				poDstDS = poDriver->Create(memName.c_str(), tilesize, tilesize, bandCount, GDT_Byte, nullptr);
				if (nullptr == poDstDS) {
					return;
				}
				//设置放射变换参数		
				if (nullptr != pProjection) {
					poDstDS->SetProjection(pProjection);
				}
				
				double startX = curX * tilesize*level;
				double startY = y * tilesize*level;
				double xx, yy;
				TDRasterCommon::ImageRowCol2Projection(m_adfGeoTransform, startX, startY, xx, yy);
				double updateGeoTransfrom[6] = { 0.0 };
				poDstDS->SetGeoTransform(UpdateGeoTransfrom(m_adfGeoTransform, xx, yy, level, updateGeoTransfrom)); //设置图像参数

				GByte *pStart = new GByte[tileSizeX*tileSizeY*bandCount];

				memset(pStart, 0, tileSizeX*tileSizeY*bandCount);

				//计算原始影像一行瓦片的长度
				size_t rowTileWidth = storeWidth * tilesize;
				//计算N行瓦片的长度
				int nRowTileWidth = rowTileWidth * y;

				for (size_t iBand = 0;iBand < bandCount;++iBand) {
					//计算数据瓦片的波段起始位置 
					size_t dstStart = tileSizeX * tileSizeY * iBand;
					//计算读取的原始影像的影像的起始位置
					size_t srcStart = storeWidth * storeHeight * iBand;

					for (size_t j = 0; j < tileSizeY; ++j) {
						memcpy(pStart + dstStart + j * tileSizeX, imgBuf + srcStart + nRowTileWidth + j * storeWidth + i * tilesize, tileSizeX);
					}
				}

				poDstDS->RasterIO(GF_Write, 0, 0, tileSizeX, tileSizeY, pStart, tileSizeX, tileSizeY,
					GDT_Byte, bandCount, nullptr, 0, 0, 0);

				create_copy(poDstDS, target_name, armDriver);
				GDALClose(poDstDS);
				poDstDS = NULL;

				delete[] pStart;
			});
		}
	}

	threadPool.StopThreadPool();
	delete[] imgBuf;
	imgBuf = nullptr;
	GDALClose(srcDataset);
	srcDataset = NULL;
	end = std::chrono::steady_clock::now();
	std::cout << "handle one time is : " << std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << " s" << std::endl;
	return true;
}

bool ImageTile::spliteNCols(int xNum, int yNum, int x, int xCount, double level, std::string filepath, std::string formattype, std::string srcimagename, int bandCount, int threadSize)
{
	std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();

	std::string dstTileSuffixName = TDRasterCommon::GetSuffixByDriver(formattype);
	if (dstTileSuffixName.empty()) {
		std::cout << "No file suffix corresponding to "<< formattype << " driver was found" << std::endl;
		return false;
	}

	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	auto armDriver = GetGDALDriverManager()->GetDriverByName(formattype.c_str());

	if (nullptr == armDriver) {
		std::cout << "Gdal driver " << formattype << "does not exist" << std::endl;
		return false;
	}	
	
	auto srcDataset = (GDALDataset*)GDALOpen(srcimagename.c_str(), GA_ReadOnly); //获取原始数据句柄
	if (nullptr == srcDataset){
		std::cout << " Failed to open " << srcimagename << std::endl;
		return false;
	}
	auto pProjection = srcDataset->GetProjectionRef();
	if (nullptr == pProjection) {
		std::cout << "GetProjectionRef returns nullptr" << std::endl;
		return false;
	}

	//GDALRasterIOExtraArg exterArg;
	//INIT_RASTERIO_EXTRA_ARG(exterArg);
	//exterArg.eResampleAlg = GDALRIOResampleAlg::GRIORA_Bilinear;

	//读取影响的位置
	double startX = x * tilesize *level;
	double startY = 0;
	double sw = (m_srcWidth - (xNum - 1)*tilesize * level) / (tilesize * level);
	double w = m_srcWidth - (xNum - 1)*tilesize * level;
	double sh = (m_srcHeight - (yNum - 1)*tilesize * level) / (tilesize * level);
	double h = m_srcHeight - (yNum - 1)*tilesize * level;

	//
	size_t storeWidth = 0;
	//读取影像的宽度
	size_t readWidth = 0;

	if (x + xCount == xNum) {
		readWidth = tilesize*(xCount - 1)*level + w;
		storeWidth = tilesize * (xCount - 1) + tilesize * sw;
	}
	else {
		readWidth = tilesize*level* xCount;
		storeWidth = tilesize * xCount;
	}

	//读取影像的高度
	size_t readHeight = m_srcHeight;
	size_t storeHeight = tilesize * (yNum - 1) + tilesize * sh;

	//开辟空间
	size_t imgBufNum = storeWidth * storeHeight * bandCount;
	GByte *imgBuf = new GByte[imgBufNum];
	memset(imgBuf,0, imgBufNum);

	//读取N列瓦片影像
	srcDataset->RasterIO(GF_Read, startX, startY, readWidth, readHeight, imgBuf, storeWidth, storeHeight,
		GDT_Byte, bandCount, nullptr, 0, 0, 0);
	std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
	std::cout << "read raster time : " << std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << " s" << std::endl;

	
	TDThreadPool::ThreadPool threadPool(1, threadSize);
	for (size_t y = 0; y < yNum; ++y) {
		size_t tileSizeX = tilesize;
		size_t tileSizeY = tilesize;
		if ((yNum - 1) == y) {
			tileSizeY = tilesize * sh;
		}

		for (size_t i = 0; i < xCount; ++i) {
			size_t curX = x + i;
			if ((xNum - 1) == curX) {
				tileSizeX = tilesize * sw;
			}
			std::string  target_name = filepath + "/R" + DecIntToHexStr(y) + "C" + DecIntToHexStr(curX) + dstTileSuffixName; // 配置输出参数

			threadPool.CommitOneTask([this, curX,i,y, level,tileSizeX, tileSizeY, storeWidth, storeHeight, armDriver,target_name, bandCount, srcDataset, imgBuf, pProjection]()
			{
				GDALDataset* poDstDS;
				poDstDS = armDriver->Create(target_name.c_str(), tilesize, tilesize, bandCount, GDT_Byte, nullptr);
				if (nullptr == poDstDS) {
					return;
				}
				//设置放射变换参数			
				if (nullptr != pProjection) {
					poDstDS->SetProjection(pProjection);
				}

				double startX = curX * tilesize*level;
				double startY = y * tilesize*level;
				double xx, yy;
				TDRasterCommon::ImageRowCol2Projection(m_adfGeoTransform, startX, startY, xx, yy);
				double updateGeoTransfrom[6] = {0.0};
				poDstDS->SetGeoTransform(UpdateGeoTransfrom(m_adfGeoTransform, xx, yy, level, updateGeoTransfrom)); //设置图像参数

				GByte *pStart = new GByte[tileSizeX*tileSizeY*bandCount];
				
				memset(pStart, 0, tileSizeX*tileSizeY*bandCount);

				//计算原始影像一行瓦片的长度
				size_t rowTileWidth = storeWidth * tilesize;
				//计算N行瓦片的长度
				size_t nRowTileWidth = rowTileWidth * y;

				for (size_t iBand = 0;iBand < bandCount;++iBand) {
					//计算数据瓦片的波段起始位置 
					size_t dstStart = tileSizeX * tileSizeY * iBand;
					//计算读取的原始影像的影像的起始位置
					size_t srcStart = storeWidth * storeHeight * iBand;

					for (size_t j = 0; j < tileSizeY; ++j) {
						memcpy(pStart + dstStart + j * tileSizeX, imgBuf + srcStart + nRowTileWidth + j* storeWidth + i * tilesize, tileSizeX);
					}
				}

				poDstDS->RasterIO(GF_Write, 0, 0, tileSizeX, tileSizeY, pStart, tileSizeX, tileSizeY,
					GDT_Byte, bandCount, nullptr, 0, 0, 0);

				GDALClose(poDstDS);
				poDstDS = NULL;

				delete[] pStart;
			});
		}
	}

	threadPool.StopThreadPool();
	delete[] imgBuf;
	imgBuf = nullptr;
	GDALClose(srcDataset);
	srcDataset = NULL;
	end = std::chrono::steady_clock::now();
	std::cout << "handle one time is : " << std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << " s" << std::endl;
	return true;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档