前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GDAL 根据图版范围对影像进行提取 (C++篇)

GDAL 根据图版范围对影像进行提取 (C++篇)

作者头像
Freedom123
发布2024-03-29 08:28:30
840
发布2024-03-29 08:28:30
举报
文章被收录于专栏:DevOpsDevOps
代码语言:javascript
复制
bool ImageExtract::CutImageByFeature(string shpfile, string field1, string field2, string savePath)
{
	std::string message;
	
	//判断影像
	if (imageDataset == nullptr) {
		return false;
	}

	savePath += "/";

	const char* image_projection = imageDataset->GetProjectionRef();
	OGRSpatialReference image_srs;
	image_srs.importFromWkt(image_projection);
	if ((image_projection == nullptr) || !image_srs.IsProjected())
	{
		//非投影坐标系统
		return false;
	}

	GDALDataset *poDS = nullptr;
	OGRLayer *poLayer = nullptr;
	LayerPathInfoV1 feature_info;
	feature_info.drivername = "ESRI Shapefile";
	feature_info.filename = filename(shpfile);
	feature_info.filePath = shpfile;
	open_layer(feature_info, poDS, poLayer);
	if (!poDS || !poLayer) {
		return false;
	}

	OGRSpatialReference* feature_srs = poLayer->GetSpatialRef();
	if ((feature_srs == nullptr) /*|| !feature_srs->IsProjected()*/)
	{
		//非投影坐标系统
		return false;
	}

	if (!feature_srs->IsProjected())
	{
		QString newshp = QString::fromStdString(shpfile);
		QFileInfo fileinfo(newshp);
		QString newname = fileinfo.path() + "/" + fileinfo.fileName().split(".")[0] + "_new.shp";

		//地理坐标转平面坐标
		if (TransGeo2Project(poLayer, newname.toStdString(), &image_srs)) {
			is_shp_created_ = true;
			new_shpfile = newname.toUtf8().toStdString();

			//关闭好的
			if (poDS) {
				GDALClose(poDS);
				poDS = nullptr;
				poLayer = nullptr;
				feature_srs = nullptr;
			}

			feature_info.filename = filename(new_shpfile);
			feature_info.filePath = new_shpfile;
			open_layer(feature_info, poDS, poLayer);
			if (!poDS || !poLayer) {
				return false;
			}

			feature_srs = poLayer->GetSpatialRef();
			if ((feature_srs == nullptr))
			{
				return false;
			}
		}
		else {
			return false;
		}
	}

	//判断俩者坐标系相同
	if (!IsSameSrs(feature_srs, &image_srs)) {
		return false;
	}

	//判断影像与矢量相交
	double image_geomtransform[6] = { 0 };
	imageDataset->GetGeoTransform(image_geomtransform);
	int image_size_x = imageDataset->GetRasterXSize();
	int image_size_y = imageDataset->GetRasterYSize();

	OGREnvelope image_envelope;
	OGRGeometry* image_geometry = get_iamge_envlope(image_geomtransform,
		image_size_x, image_size_y, image_envelope);
	if (nullptr == image_geometry) {
		return false;
	}


	OGREnvelope *LayerEnvelope = new OGREnvelope();
	poLayer->GetExtent(LayerEnvelope);
	if (!LayerEnvelope->Intersects(image_envelope)) {
		return false;
	}

	char* wkt = nullptr;
	poLayer->GetSpatialRef()->exportToWkt(&wkt);

	//判别影像分辨率
	int Xpixels = imageDataset->GetRasterXSize();
	int Ypixels = imageDataset->GetRasterYSize();
	double xmin, ymin, xmax, ymax;
	ColRow2LatLon(adfGeoTransform, 0, 0, xmin, ymax);
	ColRow2LatLon(adfGeoTransform, Xpixels, Ypixels, xmax, ymin);

	OGRFeature *poFeature;
	poLayer->ResetReading();
	//int ccc = 0;
	int inext = 0, itotal = poLayer->GetFeatureCount();
	int iinternal = itotal / 20, ishow = 0, icur = 0;
	while ((poFeature = poLayer->GetNextFeature()) != NULL)
	{
		icur++;

		if (icur > inext && ishow <= 100) {
			inext += iinternal;
			ishow += 5;
		}

		OGREnvelope FeatureEnvelop;
		if(poFeature->GetGeometryRef() == nullptr)
			continue;

		poFeature->GetGeometryRef()->getEnvelope(&FeatureEnvelop);

		///ccc++;
		double s1 = (FeatureEnvelop.MaxX - FeatureEnvelop.MinX) / image_geomtransform[1] / defaultwid;
		double s2 = (FeatureEnvelop.MaxY - FeatureEnvelop.MinY) / image_geomtransform[1] / defaultwid;
		double s = (s1 > s2) ? s1 : s2;
		
		//合并名称
		string ccc = poFeature->GetFieldAsString(field1.c_str());
		if (ccc.length() > 6)
			ccc = ccc.substr(0, 6);

		std::string tbbh_value = poFeature->GetFieldAsString(field2.c_str());
		ccc = ccc + "_" + tbbh_value;

		if (s < 1)
		{
			//计算地理坐标
			double w = defaultwid * (xmax - xmin) / Xpixels - FeatureEnvelop.MaxX + FeatureEnvelop.MinX;
			double h = defaultheight * (ymax - ymin) / Ypixels - FeatureEnvelop.MaxY + FeatureEnvelop.MinY;
			double lx = FeatureEnvelop.MinX - w / 2;
			double rx = FeatureEnvelop.MaxX + w / 2;
			double ty = FeatureEnvelop.MinY - h / 2;
			double by = FeatureEnvelop.MaxY + h / 2;

			int c0, r0, c1, r1;
			LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);
			LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);

			int blockex_width = fabs(r1 - r0); int  blockex_height = fabs(c1 - c0);
			if (blockex_width <= 0 || blockex_height <= 0)
				continue;

			double geox = min(lx, rx), geoy = max(by, ty);
			
			//处理边界问题
			if ((r0 < 0 || c0 < 0)
				&& image_envelope.Contains(FeatureEnvelop)) {

				double w = FeatureEnvelop.MaxX - FeatureEnvelop.MinX;
				double h = FeatureEnvelop.MaxY - FeatureEnvelop.MinY;
				double extent = 0;
				if (w > h)
					extent = w * extend_factor;
				else 
					extent = h * extend_factor;
				lx = FeatureEnvelop.MinX - extent;
				rx = FeatureEnvelop.MaxX + extent;
				ty = FeatureEnvelop.MinY - extent;
				by = FeatureEnvelop.MaxY + extent;				
				LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);
				LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);

				//再次保证切片影像
				if (r0 < 0 || c0 < 0) {
					extent = w * 0;
					lx = FeatureEnvelop.MinX - extent;
					rx = FeatureEnvelop.MaxX + extent;
					ty = FeatureEnvelop.MinY - extent;
					by = FeatureEnvelop.MaxY + extent;
					LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);
					LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);
				}

				blockex_width = fabs(r1 - r0); blockex_height = fabs(c1 - c0);

				//宽度长度为0返回
				if (blockex_width <= 0 || blockex_height <= 0)
					continue;

				geox = min(lx, rx), geoy = max(by, ty);
			}

			if (blockex_width > (Xpixels - r0))
				blockex_width = Xpixels - r0;
			if (blockex_height > (Ypixels - c0))
				blockex_height = Ypixels - c0;

			CreateSubimg(poFeature->GetGeometryRef(), r0, c0, blockex_width, blockex_height, geox, geoy, wkt, ccc, savePath);

		}
		else if (s >= 1)
		{
			//计算金字塔级别
			double w = FeatureEnvelop.MaxX - FeatureEnvelop.MinX;
			double h = FeatureEnvelop.MaxY - FeatureEnvelop.MinY;
			double extent = 0;
			if (w > h)
			{
				extent = w * extend_factor;

				//左右下上
				double lx = (FeatureEnvelop.MaxX - FeatureEnvelop.MinX) / 2.0 + FeatureEnvelop.MinX - w / 2 - extent;
				double rx = (FeatureEnvelop.MaxX - FeatureEnvelop.MinX) / 2.0 + FeatureEnvelop.MinX + w / 2 + extent;
				double ty = (FeatureEnvelop.MaxX - FeatureEnvelop.MinX) / 2.0 + FeatureEnvelop.MinY - w / 2 - extent;
				double by = (FeatureEnvelop.MaxX - FeatureEnvelop.MinX) / 2.0 + FeatureEnvelop.MinY + w / 2 + extent;

				//c0:上行 r0:左列 c1:下行 r1:右列
				int c0, r0, c1, r1;
				LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);
				LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);
				
				int blockex_width = fabs(r1 - r0); int  blockex_height = fabs(c1 - c0);
				if (blockex_width <= 0 || blockex_height <= 0)
					continue;

				//判断扩展大于影像情况并且图版包含或部分包含在影像内情况
				if ((r0 < 0 || c0 < 0)
					&& image_envelope.Contains(FeatureEnvelop)) {

					extent = w * 0;
					lx = FeatureEnvelop.MinX - extent;
					rx = FeatureEnvelop.MaxX + extent;
					ty = FeatureEnvelop.MinY - extent;
					by = FeatureEnvelop.MaxY + extent;

					//c0:上行 r0:左列 c1:下行 r1:右列
					LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);
					LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);

					blockex_width = fabs(r1 - r0); 
					blockex_height = fabs(c1 - c0);
					if (blockex_width <= 0 || blockex_height <= 0)
						continue;
				}
				else {
					//影像完全包含图版或者影像没有包含图版
				}

				if (blockex_width > (Xpixels - r0))
					blockex_width = Xpixels - r0;
				if (blockex_height > (Ypixels - c0))
					blockex_height = Ypixels - c0;

				CreateSubimg(poFeature->GetGeometryRef(), r0, c0, blockex_width, blockex_height, min(lx, rx), max(by, ty), wkt, ccc, savePath);
			}
			else
			{
				extent = h * extend_factor;
				//左右下上
				double lx = (FeatureEnvelop.MaxY - FeatureEnvelop.MinY) / 2.0 + FeatureEnvelop.MinX - h / 2 - extent;
				double rx = (FeatureEnvelop.MaxY - FeatureEnvelop.MinY) / 2.0 + FeatureEnvelop.MinX + h / 2 + extent;
				double ty = (FeatureEnvelop.MaxY - FeatureEnvelop.MinY) / 2.0 + FeatureEnvelop.MinY - h / 2 - extent;
				double by = (FeatureEnvelop.MaxY - FeatureEnvelop.MinY) / 2.0 + FeatureEnvelop.MinY + h / 2 + extent;
						
				//c0:上行 r0:左列 c1:下行 r1:右列
				int c0, r0, c1, r1;
				LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);
				LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);

				int blockex_width = fabs(r1 - r0); int  blockex_height = fabs(c1 - c0);
				if(blockex_width <= 0 || blockex_height <= 0)
					continue;

				//判断扩展大于影像情况并且图版包含或部分包含在影像内情况
				if ((r0 < 0 || c0 < 0)
					&& image_envelope.Contains(FeatureEnvelop)) {

					extent = w * 0;
					lx = FeatureEnvelop.MinX - extent;
					rx = FeatureEnvelop.MaxX + extent;
					ty = FeatureEnvelop.MinY - extent;
					by = FeatureEnvelop.MaxY + extent;

					//c0:上行 r0:左列 c1:下行 r1:右列
					LatLon2ColRow(adfGeoTransform, lx, ty, c1, r0);
					LatLon2ColRow(adfGeoTransform, rx, by, c0, r1);

					blockex_width = fabs(r1 - r0);
					blockex_height = fabs(c1 - c0);
					if (blockex_width <= 0 || blockex_height <= 0)
						continue;
				}
				else {
					//影像完全包含图版或者影像没有包含图版
				}

				if (blockex_width > (Xpixels - r0))
					blockex_width = Xpixels - r0;
				if (blockex_height > (Ypixels - c0))
					blockex_height = Ypixels - c0;

				CreateSubimg(poFeature->GetGeometryRef(), r0, c0, blockex_width, blockex_height, min(lx,rx), max(by,ty), wkt, ccc, savePath);

			}


		}

		OGRFeature::DestroyFeature(poFeature);
	}

	if(poDS)
		GDALClose(poDS);

	return true;
}

bool ImageExtract::CreateSubimg(OGRGeometry *geometry, int c0, int r0, int blockex_width, int blockex_height, double minx, double maxy, const char *wkt, string ccc, string SavePath)
{
	char* blockex_1 = nullptr, *blockex_2 = nullptr, *blockex_3 = nullptr;
	bool isblockex_1 = read_block(image_band1, c0, r0, blockex_width, blockex_height, blockex_1);
	bool isblockex_2 = read_block(image_band2, c0, r0, blockex_width, blockex_height, blockex_2);
	bool isblockex_3 = read_block(image_band3, c0, r0, blockex_width, blockex_height, blockex_3);
	GDALDataset* output_dataset = nullptr;
	string name = SavePath + ccc + ".tif";
	create_rasterband("GTiff", name, 3, blockex_width, blockex_height, output_dataset);
	resadfGeoTransform[0] = minx;
	resadfGeoTransform[1] = adfGeoTransform[1];
	resadfGeoTransform[2] = 0;
	resadfGeoTransform[3] = maxy;
	resadfGeoTransform[4] = 0;
	resadfGeoTransform[5] = adfGeoTransform[5];
	output_dataset->SetGeoTransform(resadfGeoTransform);


	if (output_dataset != NULL)
		output_dataset->SetProjection(wkt);

	GDALRasterBand* merge_band1 = output_dataset->GetRasterBand(1);
	GDALRasterBand* merge_band2 = output_dataset->GetRasterBand(2);
	GDALRasterBand* merge_band3 = output_dataset->GetRasterBand(3);

	if (!merge_band1 || !merge_band2 || !merge_band3) {
		//message = "Error : get tmp image band failure, feature id :" + icur;
		//ibreak = false;

		if (output_dataset)
			GDALClose(output_dataset);

		return false;
	}
	//
	DrawGeometry(geometry, blockex_1, blockex_2, blockex_3, resadfGeoTransform, blockex_width, blockex_height);

	//
	if (GDALRasterIO(merge_band1, GF_Write, 0, 0, blockex_width, blockex_height,
		blockex_1, blockex_width, blockex_height, GDT_Byte, 0, 0) != CE_None) {
		//message = "Error : get tmp image band buffer failure, feature id :" + icur;
		// = false;

		if (output_dataset)
			GDALClose(output_dataset);

		return false;
	}

	if (GDALRasterIO(merge_band2, GF_Write, 0, 0, blockex_width, blockex_height,
		blockex_2, blockex_width, blockex_height, GDT_Byte, 0, 0) != CE_None) {
		//message = "Error : get tmp image band buffer failure, feature id :" + icur;
		//ibreak = false;

		if (output_dataset)
			GDALClose(output_dataset);

		return false;
	}

	if (GDALRasterIO(merge_band3, GF_Write, 0, 0, blockex_width, blockex_height,
		blockex_3, blockex_width, blockex_height, GDT_Byte, 0, 0) != CE_None) {
		//message = "Error : get tmp image band buffer failure, feature id :" + icur;
		//ibreak = false;

		if (output_dataset)
			GDALClose(output_dataset);

		return false;
	}

	CPLFree(blockex_1);
	CPLFree(blockex_2);
	CPLFree(blockex_3);

	//保存tif,删除tif
	if (output_dataset) {
		GDALClose(output_dataset);
		output_dataset = nullptr;
	}

	string sss = SavePath + ccc + ".tif";

	//BOOL bo = DeleteFileA(sss.c_str());
	QDir dir;
	dir.remove(QString::fromStdString(sss));
	int cc = 0;
}

void ImageExtract::DrawGeometry(OGRGeometry *geometry, char* blockex_1, char *blockex_2, char *blockex_3, double af[], int width, int height)
{
	if (geometry == nullptr) return;
	OGRwkbGeometryType   gt = geometry->getGeometryType();
	if (gt == wkbPolygon || gt == wkbPolygon25D || gt == wkbPolygonM || gt == wkbPolygonZM)
	{
		OGRPolygon *polygon = (OGRPolygon*)geometry;
		OGRLinearRing *ERing = polygon->getExteriorRing();
		int num_points = ERing->getNumPoints();
		double* arr_x = new double[num_points], *arr_y = new double[num_points];
		for (int i = 0; i < ERing->getNumPoints(); i++)
		{
			OGRPoint *pt = new OGRPoint();
			ERing->getPoint(i, pt);
			int r, c;
			this->LatLon2ColRow(af, pt->getX(), pt->getY(), r, c);
			arr_x[i] = c; arr_y[i] = r;
		}
		std::vector<OGRPoint> block_points;
		CalGeometry2Pixels(width, height, num_points, arr_x, arr_y, block_points);
		delete arr_x, arr_x = nullptr;
		delete arr_y, arr_y = nullptr;
		DrawGeometryPixels(block_points, blockex_1, blockex_2, blockex_3, width, height);
		block_points.clear();

		for (int i = 0; i < polygon->getNumInteriorRings(); i++)
		{
			OGRLinearRing *InRing = polygon->getInteriorRing(i);
			num_points = InRing->getNumPoints();
			arr_x = new double[num_points];
			arr_y = new double[num_points];

			for (int j = 0; j < InRing->getNumPoints(); j++)
			{
				OGRPoint *pt = new OGRPoint();
				InRing->getPoint(j, pt);
				int r, c;
				this->LatLon2ColRow(af, pt->getX(), pt->getY(), r, c);
				arr_x[j] = c; arr_y[j] = r;
			}
			CalGeometry2Pixels(width, width, num_points, arr_x, arr_y, block_points);
			delete arr_x, arr_x = nullptr;
			delete arr_y, arr_y = nullptr;
			DrawGeometryPixels(block_points, blockex_1, blockex_2, blockex_3, width, height);
			block_points.clear();

		}

	}
	else if (gt == wkbMultiPolygon || gt == wkbMultiPolygon25D || gt == wkbMultiPolygonM || gt == wkbMultiPolygonZM)
	{
		OGRMultiPolygon *MultPolygon = (OGRMultiPolygon*)geometry;
		for (int k = 0; k < MultPolygon->getNumGeometries(); k++)
		{
			OGRGeometry *pGeo = MultPolygon->getGeometryRef(k);
			if (pGeo->getGeometryType() == wkbPolygon)
			{
				OGRPolygon *polygon = (OGRPolygon*)pGeo;
				OGRLinearRing *ERing = polygon->getExteriorRing();
				int num_points = ERing->getNumPoints();
				double* arr_x = new double[num_points], *arr_y = new double[num_points];
				for (int i = 0; i < ERing->getNumPoints(); i++)
				{
					OGRPoint *pt = new OGRPoint();
					ERing->getPoint(i, pt);
					int r, c;
					this->LatLon2ColRow(af, pt->getX(), pt->getY(), r, c);
					arr_x[i] = c; arr_y[i] = r;
				}
				std::vector<OGRPoint> block_points;
				CalGeometry2Pixels(width, height, num_points, arr_x, arr_y, block_points);
				delete arr_x, arr_x = nullptr;
				delete arr_y, arr_y = nullptr;
				DrawGeometryPixels(block_points, blockex_1, blockex_2, blockex_3, width, height);
				block_points.clear();

				for (int i = 0; i < polygon->getNumInteriorRings(); i++)
				{
					OGRLinearRing *InRing = polygon->getInteriorRing(i);
					num_points = InRing->getNumPoints();
					arr_x = new double[num_points];
					arr_y = new double[num_points];
					for (int j = 0; j < InRing->getNumPoints(); j++)
					{
						OGRPoint *pt = new OGRPoint();
						InRing->getPoint(j, pt);
						int r, c;
						this->LatLon2ColRow(af, pt->getX(), pt->getY(), r, c);
						arr_x[j] = c; arr_y[j] = r;
					}
					CalGeometry2Pixels(width, height, num_points, arr_x, arr_y, block_points);
					delete arr_x, arr_x = nullptr;
					delete arr_y, arr_y = nullptr;
					DrawGeometryPixels(block_points, blockex_1, blockex_2, blockex_3, width, height);
					block_points.clear();

				}

			}
		}
	}
}

void ImageExtract::CalGeometry2Pixels(int nRasterXSize, int nRasterYSize, int nPartCount, double *padfX, double *padfY, std::vector<OGRPoint>& points)
{
	if (!nPartCount)
		return;

	for (int j = 1; j < nPartCount; j++) {
		int iX = static_cast<int>(floor(padfX[j - 1]));
		int iY = static_cast<int>(floor(padfY[j - 1]));

		const int iX1 = static_cast<int>(floor(padfX[j]));
		const int iY1 = static_cast<int>(floor(padfY[j]));

		double dfVariant = 0.0;
		double dfVariant1 = 0.0;

		int nDeltaX = std::abs(iX1 - iX);
		int nDeltaY = std::abs(iY1 - iY);

		// Step direction depends on line direction.
		const int nXStep = (iX > iX1) ? -1 : 1;
		const int nYStep = (iY > iY1) ? -1 : 1;

		// Determine the line slope.
		if (nDeltaX >= nDeltaY) {
			const int nXError = nDeltaY << 1;
			const int nYError = nXError - (nDeltaX << 1);
			int nError = nXError - nDeltaX;
			// == 0 makes clang -fcatch-undefined-behavior -ftrapv happy,
			// but if it is == 0, dfDeltaVariant is not really used, so any
			// value is okay.
			const double dfDeltaVariant =
				nDeltaX == 0
				? 0.0
				: (dfVariant1 - dfVariant) / static_cast<double>(nDeltaX);

			while (nDeltaX-- >= 0) {
				if (0 <= iX && iX < nRasterXSize
					&& 0 <= iY && iY < nRasterYSize)
					points.push_back(OGRPoint(iX, iY));


				dfVariant += dfDeltaVariant;
				iX += nXStep;

				if (nError > 0) {
					iY += nYStep;
					nError += nYError;
				}
				else {
					nError += nXError;
				}
			}
		}
		else {
			const int nXError = nDeltaX << 1;
			const int nYError = nXError - (nDeltaY << 1);
			int nError = nXError - nDeltaY;
			// == 0 makes clang -fcatch-undefined-behavior -ftrapv happy,
			// but if it is == 0, dfDeltaVariant is not really used, so any
			// value is okay.
			double dfDeltaVariant =
				nDeltaY == 0
				? 0.0
				: (dfVariant1 - dfVariant) / static_cast<double>(nDeltaY);

			while (nDeltaY-- >= 0) {
				if (0 <= iX && iX < nRasterXSize
					&& 0 <= iY && iY < nRasterYSize)
					points.push_back(OGRPoint(iX, iY));

				dfVariant += dfDeltaVariant;
				iY += nYStep;

				if (nError > 0) {
					iX += nXStep;
					nError += nYError;
				}
				else {
					nError += nXError;
				}
			}
		}
	}
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

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