使用GDAL对DEM进行彩色渲染

    在之前的博客中,我们已经看到了gdal对dem数据的强大的处理功能,其中除了坡度坡向等,还有一个比较厉害的,就是使用DEM生成一个彩色的图像。之前关于这方面也翻译了几篇博客,详见《使用GDAL对DEM渲染处理流程》、《使用阿富汗和巴基斯坦地区的SRTM数据生成山体阴影和彩色地形图》和《使用gdaldem创建彩色地形图和坡度阴影——thematicmapping.org译文(三)》,不过这些都是使用的说明。

把gdaldem的源代码进行了整理,整理了一个使用dem数据生成彩色图像的函数,函数的定义如下。关于第四个参数,sColorMode是个枚举值,一共有三个值,默认的是使用线性插值方式,还有两个是最邻近和严格插值。线性插值就是根据你指定的颜色映射关系,把没有指定的高程值,使用颜色映射关系中最近的两个颜色按照线性插值进行处理,得到最后的颜色;而最邻近就是找到最近的一个颜色,而严格插值就是所有的高程数据都必须对应一个颜色值,要不然就是黑色的。

	/**
	* @brief DEM Color Relief(DEM颜色渲染)
	* @param pszSrcFilename		输入文件路径
	* @param pszColorTextFile	输入颜色映射文件
	* 颜色映射文件的格式是:“高程值 red green blue”,如:“1022 255 125 32”
	* @param pszDstFilename		输出文件路径
	* @param sColorMode			颜色插值模式,默认为COLOR_SELECTION_INTERPOLATE
	* @param bAddAlpha			是否添加Alpha通道,默认为不加
	* @param bComputeAtEdges	是否计算边界,默认为不计算
	* @param pszFormat			输出文件格式,详细参考GDAL支持数据类型
	* @param pProcess			进度条指针
	* @return 返回值,表示计算过程中出现的各种错误信息
	*/
	int IMGALG_API DemColorRelief(const char* pszSrcFilename, const char* pszColorTextFile, const char* pszDstFilename, 
		ColorSelectionMode sColorMode = COLOR_SELECTION_INTERPOLATE, bool bAddAlpha = false,
		bool bComputeAtEdges = false, const char *pszFormat = "GTiff", CProcessBase* pProcess = NULL);
下面是源代码,是从gdal\apps\gdaldem.cpp中摘的,不想用下面的,自己可以去这个文件里面自己去找。具体的代码如下:
#pragma region GDALColorRelief
/************************************************************************/
/*                      GDALColorRelief()                               */
/************************************************************************/

/**
* @brief 颜色结构体
*/
typedef struct
{
	/*! 值 */
	double dfVal;
	/*! R */
	int nR;
	/*! G */
	int nG;
	/*! B */
	int nB;
	/*! A */
	int nA;
} ColorAssociation;

static int GDALColorReliefSortColors(const void* pA, const void* pB)
{
	ColorAssociation* pC1 = (ColorAssociation*)pA;
	ColorAssociation* pC2 = (ColorAssociation*)pB;
	return (pC1->dfVal < pC2->dfVal) ? -1 :
		(pC1->dfVal == pC2->dfVal) ? 0 : 1;
}


static int GDALColorReliefGetRGBA (ColorAssociation* pasColorAssociation,
								   int nColorAssociation,
								   double dfVal,
								   ColorSelectionMode eColorSelectionMode,
								   int* pnR,
								   int* pnG,
								   int* pnB,
								   int* pnA)
{
	int i;
	int lower = 0;
	int upper = nColorAssociation - 1;
	int mid;

	/* Find the index of the first element in the LUT input array that */
	/* is not smaller than the dfVal value. */
	while(TRUE)
	{
		mid = (lower + upper) / 2;
		if (upper - lower <= 1)
		{
			if (dfVal < pasColorAssociation[lower].dfVal)
				i = lower;
			else if (dfVal < pasColorAssociation[upper].dfVal)
				i = upper;
			else
				i = upper + 1;
			break;
		}
		else if (pasColorAssociation[mid].dfVal >= dfVal)
		{
			upper = mid;
		}
		else
		{
			lower = mid;
		}
	}

	if (i == 0)
	{
		if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
			pasColorAssociation[0].dfVal != dfVal)
		{
			*pnR = 0;
			*pnG = 0;
			*pnB = 0;
			*pnA = 0;
			return FALSE;
		}
		else
		{
			*pnR = pasColorAssociation[0].nR;
			*pnG = pasColorAssociation[0].nG;
			*pnB = pasColorAssociation[0].nB;
			*pnA = pasColorAssociation[0].nA;
			return TRUE;
		}
	}
	else if (i == nColorAssociation)
	{
		if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
			pasColorAssociation[i-1].dfVal != dfVal)
		{
			*pnR = 0;
			*pnG = 0;
			*pnB = 0;
			*pnA = 0;
			return FALSE;
		}
		else
		{
			*pnR = pasColorAssociation[i-1].nR;
			*pnG = pasColorAssociation[i-1].nG;
			*pnB = pasColorAssociation[i-1].nB;
			*pnA = pasColorAssociation[i-1].nA;
			return TRUE;
		}
	}
	else
	{
		if (eColorSelectionMode == COLOR_SELECTION_EXACT_ENTRY &&
			pasColorAssociation[i-1].dfVal != dfVal)
		{
			*pnR = 0;
			*pnG = 0;
			*pnB = 0;
			*pnA = 0;
			return FALSE;
		}

		if (eColorSelectionMode == COLOR_SELECTION_NEAREST_ENTRY &&
			pasColorAssociation[i-1].dfVal != dfVal)
		{
			int index;
			if (dfVal - pasColorAssociation[i-1].dfVal <
				pasColorAssociation[i].dfVal - dfVal)
				index = i -1;
			else
				index = i;

			*pnR = pasColorAssociation[index].nR;
			*pnG = pasColorAssociation[index].nG;
			*pnB = pasColorAssociation[index].nB;
			*pnA = pasColorAssociation[index].nA;
			return TRUE;
		}

		double dfRatio = (dfVal - pasColorAssociation[i-1].dfVal) /
			(pasColorAssociation[i].dfVal - pasColorAssociation[i-1].dfVal);
		*pnR = (int)(0.45 + pasColorAssociation[i-1].nR + dfRatio *
			(pasColorAssociation[i].nR - pasColorAssociation[i-1].nR));
		if (*pnR < 0) *pnR = 0;
		else if (*pnR > 255) *pnR = 255;
		*pnG = (int)(0.45 + pasColorAssociation[i-1].nG + dfRatio *
			(pasColorAssociation[i].nG - pasColorAssociation[i-1].nG));
		if (*pnG < 0) *pnG = 0;
		else if (*pnG > 255) *pnG = 255;
		*pnB = (int)(0.45 + pasColorAssociation[i-1].nB + dfRatio *
			(pasColorAssociation[i].nB - pasColorAssociation[i-1].nB));
		if (*pnB < 0) *pnB = 0;
		else if (*pnB > 255) *pnB = 255;
		*pnA = (int)(0.45 + pasColorAssociation[i-1].nA + dfRatio *
			(pasColorAssociation[i].nA - pasColorAssociation[i-1].nA));
		if (*pnA < 0) *pnA = 0;
		else if (*pnA > 255) *pnA = 255;

		return TRUE;
	}
}

/* dfPct : percentage between 0 and 1 */
static double GDALColorReliefGetAbsoluteValFromPct(GDALRasterBandH hSrcBand,
												   double dfPct)
{
	double dfMin, dfMax;
	int bSuccessMin, bSuccessMax;
	dfMin = GDALGetRasterMinimum(hSrcBand, &bSuccessMin);
	dfMax = GDALGetRasterMaximum(hSrcBand, &bSuccessMax);
	if (!bSuccessMin || !bSuccessMax)
	{
		double dfMean, dfStdDev;
		fprintf(stderr, "Computing source raster statistics...\n");
		GDALComputeRasterStatistics(hSrcBand, FALSE, &dfMin, &dfMax,
			&dfMean, &dfStdDev, NULL, NULL);
	}
	return dfMin + dfPct * (dfMax - dfMin);
}

/**
* @brief 名称颜色
*/
typedef struct
{
	/*! 名称 */
	const char *name;
	/*! RGB颜色R */
	float r;
	/*! RGB颜色G */
	float g;
	/*! RGB颜色B */
	float b;
} NamedColor;

static const NamedColor namedColors[] = {
	{ "white",   1.00, 1.00, 1.00 },
	{ "black",   0.00, 0.00, 0.00 },
	{ "red",     1.00, 0.00, 0.00 },
	{ "green",   0.00, 1.00, 0.00 },
	{ "blue",    0.00, 0.00, 1.00 },
	{ "yellow",  1.00, 1.00, 0.00 },
	{ "magenta", 1.00, 0.00, 1.00 },
	{ "cyan",    0.00, 1.00, 1.00 },
	{ "aqua",    0.00, 0.75, 0.75 },
	{ "grey",    0.75, 0.75, 0.75 },
	{ "gray",    0.75, 0.75, 0.75 },
	{ "orange",  1.00, 0.50, 0.00 },
	{ "brown",   0.75, 0.50, 0.25 },
	{ "purple",  0.50, 0.00, 1.00 },
	{ "violet",  0.50, 0.00, 1.00 },
	{ "indigo",  0.00, 0.50, 1.00 },
};				 

static
int GDALColorReliefFindNamedColor(const char *pszColorName, int *pnR, int *pnG, int *pnB)
{
	unsigned int i;

	*pnR = *pnG = *pnB = 0;
	for (i = 0; i < sizeof(namedColors) / sizeof(namedColors[0]); i++)
	{
		if (EQUAL(pszColorName, namedColors[i].name))
		{
			*pnR = (int)(255. * namedColors[i].r);
			*pnG = (int)(255. * namedColors[i].g);
			*pnB = (int)(255. * namedColors[i].b);
			return TRUE;
		}
	}
	return FALSE;
}

static
ColorAssociation* GDALColorReliefParseColorFile(GDALRasterBandH hSrcBand,
												const char* pszColorFilename,
												int* pnColors)
{
	FILE* fpColorFile = VSIFOpenL(pszColorFilename, "rt");
	if (fpColorFile == NULL)
	{
		CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s", pszColorFilename);
		*pnColors = 0;
		return NULL;
	}

	ColorAssociation* pasColorAssociation = NULL;
	int nColorAssociation = 0;

	int bSrcHasNoData = FALSE;
	double dfSrcNoDataValue = GDALGetRasterNoDataValue(hSrcBand, &bSrcHasNoData);

	const char* pszLine;
	while ((pszLine = CPLReadLineL(fpColorFile)) != NULL)
	{
		char** papszFields = CSLTokenizeStringComplex(pszLine, " ,\t:", 
			FALSE, FALSE );
		/* Skip comment lines */
		int nTokens = CSLCount(papszFields);
		if (nTokens >= 2 &&
			papszFields[0][0] != '#' &&
			papszFields[0][0] != '/')
		{
			pasColorAssociation =
				(ColorAssociation*)CPLRealloc(pasColorAssociation,
				(nColorAssociation + 1) * sizeof(ColorAssociation));
			if (EQUAL(papszFields[0], "nv") && bSrcHasNoData)
				pasColorAssociation[nColorAssociation].dfVal = dfSrcNoDataValue;
			else if (strlen(papszFields[0]) > 1 && papszFields[0][strlen(papszFields[0])-1] == '%')
			{
				double dfPct = atof(papszFields[0]) / 100.;
				if (dfPct < 0.0 || dfPct > 1.0)
				{
					CPLError(CE_Failure, CPLE_AppDefined,
						"Wrong value for a percentage : %s", papszFields[0]);
					CSLDestroy(papszFields);
					VSIFCloseL(fpColorFile);
					CPLFree(pasColorAssociation);
					*pnColors = 0;
					return NULL;
				}
				pasColorAssociation[nColorAssociation].dfVal =
					GDALColorReliefGetAbsoluteValFromPct(hSrcBand, dfPct);
			}
			else
				pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);

			if (nTokens >= 4)
			{
				pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
				pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
				pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
				pasColorAssociation[nColorAssociation].nA =
					(CSLCount(papszFields) >= 5 ) ? atoi(papszFields[4]) : 255;
			}
			else
			{
				int nR, nG, nB;
				if (!GDALColorReliefFindNamedColor(papszFields[1], &nR, &nG, &nB))
				{
					CPLError(CE_Failure, CPLE_AppDefined,
						"Unknown color : %s", papszFields[1]);
					CSLDestroy(papszFields);
					VSIFCloseL(fpColorFile);
					CPLFree(pasColorAssociation);
					*pnColors = 0;
					return NULL;
				}
				pasColorAssociation[nColorAssociation].nR = nR;
				pasColorAssociation[nColorAssociation].nG = nG;
				pasColorAssociation[nColorAssociation].nB = nB;
				pasColorAssociation[nColorAssociation].nA =
					(CSLCount(papszFields) >= 3 ) ? atoi(papszFields[2]) : 255;
			}

			nColorAssociation ++;
		}
		CSLDestroy(papszFields);
	}
	VSIFCloseL(fpColorFile);

	if (nColorAssociation == 0)
	{
		CPLError(CE_Failure, CPLE_AppDefined,
			"No color association found in %s", pszColorFilename);
		*pnColors = 0;
		return NULL;
	}

	qsort(pasColorAssociation, nColorAssociation,
		sizeof(ColorAssociation), GDALColorReliefSortColors);

	*pnColors = nColorAssociation;
	return pasColorAssociation;
}

static
GByte* GDALColorReliefPrecompute(GDALRasterBandH hSrcBand,
								 ColorAssociation* pasColorAssociation,
								 int nColorAssociation,
								 ColorSelectionMode eColorSelectionMode,
								 int* pnIndexOffset)
{
	GDALDataType eDT = GDALGetRasterDataType(hSrcBand);
	GByte* pabyPrecomputed = NULL;
	int nIndexOffset = (eDT == GDT_Int16) ? 32768 : 0;
	*pnIndexOffset = nIndexOffset;
	int nXSize = GDALGetRasterBandXSize(hSrcBand);
	int nYSize = GDALGetRasterBandXSize(hSrcBand);
	if (eDT == GDT_Byte ||
		((eDT == GDT_Int16 || eDT == GDT_UInt16) && nXSize * nYSize > 65536))
	{
		int iMax = (eDT == GDT_Byte) ? 256: 65536;
		pabyPrecomputed = (GByte*) VSIMalloc(4 * iMax);
		if (pabyPrecomputed)
		{
			int i;
			for(i=0; i
上面这部分代码就是渲染的核心函数,下面就是函数的实现代码。下面的代码中如果有函数或者变量没有找到定义,请参考我之前的博客中的内容。
int DemColorRelief(const char* pszSrcFilename, const char* pszColorTextFile, const char* pszDstFilename, 
				   ColorSelectionMode sColorMode, bool bAddAlpha, bool bComputeAtEdges , 
				   const char *pszFormat, CProcessBase* pProcess)
{
	if(pProcess != NULL)
	{
		pProcess->ReSetProcess();
		pProcess->SetMessage("正在计算颜色渲染...");
	}

	int nBand = 1;
	double  adfGeoTransform[6];

	char **papszCreateOptions = NULL;

	GDALDatasetH hSrcDataset = NULL;
	GDALDatasetH hDstDataset = NULL;
	GDALRasterBandH hSrcBand = NULL;
	GDALRasterBandH hDstBand = NULL;
	GDALDriverH hDriver = NULL;

	GDALProgressFunc pfnProgress = ALGTermProgress;
	string strColorFile = "";

	int nXSize = 0;
	int nYSize = 0;

	if( pszSrcFilename == NULL )
	{
		if(pProcess != NULL)
			pProcess->SetMessage("源文件路径为空!");

		return RE_FILENOTEXIST;
	}

	if( pszColorTextFile == NULL || EQUAL(pszColorTextFile, ""))
	{
		const char* pszGDAL_Data = CPLGetConfigOption("GDAL_DATA", "data");	//获取GDAL_DATA目录
		strColorFile = string(pszGDAL_Data) + "/dem_color_relief.clr";
	}
	else
		strColorFile = pszColorTextFile;

	if( pszDstFilename == NULL )
	{
		if(pProcess != NULL)
			pProcess->SetMessage("输出文件路径为空!");

		return RE_FILENOTEXIST;
	}

	if(FileIsUsed(pszDstFilename, pProcess))
		return RE_FILEISUESED;

	GDALAllRegister();

	//打开图像
	hSrcDataset = GDALOpen( pszSrcFilename, GA_ReadOnly );
	if( hSrcDataset == NULL )
	{
		if(pProcess != NULL)
			pProcess->SetMessage("输入文件不能打开!");

		return RE_FILENOTEXIST;
	}

	nXSize = GDALGetRasterXSize(hSrcDataset);
	nYSize = GDALGetRasterYSize(hSrcDataset);

	if( nBand <= 0 || nBand > GDALGetRasterCount(hSrcDataset) )
	{
		if(pProcess != NULL)
			pProcess->SetMessage("指定计算的波段不正确!");

		return RE_PARAMERROR;
	}

	hSrcBand = GDALGetRasterBand( hSrcDataset, nBand );
	GDALGetGeoTransform(hSrcDataset, adfGeoTransform);

	hDriver = GDALGetDriverByName(pszFormat);
	if( hDriver == NULL)
	{
		if(pProcess != NULL)
			pProcess->SetMessage("不能创建制定类型的文件,请检查该文件类型GDAL是否支持创建!");

		GDALClose( hSrcDataset );

		return RE_FILENOTSUPPORT;
	}

	//设置输出文件数据类型
	GDALDataType eDstDataType = GDT_Byte;

	int nDstBands = (bAddAlpha) ? 4 : 3;

	hDstDataset = GDALCreate(hDriver,
		pszDstFilename,
		nXSize,
		nYSize,
		nDstBands,
		eDstDataType,
		papszCreateOptions);

	if( hDstDataset == NULL )
	{
		if(pProcess != NULL)
			pProcess->SetMessage("创建输出文件失败,请检查文件路径是否正确!");

		GDALClose( hSrcDataset );

		return RE_CREATEFAILED;	//创建图像失败
	}

	hDstBand = GDALGetRasterBand( hDstDataset, 1 );

	GDALSetGeoTransform(hDstDataset, adfGeoTransform);
	GDALSetProjection(hDstDataset, GDALGetProjectionRef(hSrcDataset));

	if (GDALColorRelief (hSrcBand, 
		GDALGetRasterBand(hDstDataset, 1),
		GDALGetRasterBand(hDstDataset, 2),
		GDALGetRasterBand(hDstDataset, 3),
		(bAddAlpha) ? GDALGetRasterBand(hDstDataset, 4) : NULL,
		strColorFile.c_str(),
		sColorMode,
		pfnProgress, pProcess) != CE_None)
	{
		if(pProcess!=NULL)
		{
			if(!pProcess->m_bIsContinue)
			{
				GDALClose(hSrcDataset);
				GDALClose(hDstDataset);

				GDALDeleteDataset(hDstDataset, pszDstFilename);	//删除结果文件

				CSLDestroy( papszCreateOptions );

				return RE_USERCANCEL;
			}
		}

		GDALClose(hSrcDataset);
		GDALClose(hDstDataset);

	GDALDeleteDataset(hDstDataset, pszDstFilename);	//删除结果文件
        CSLDestroy( papszCreateOptions);
		return RE_FAILED;
	}

	GDALClose(hSrcDataset);
	GDALClose(hDstDataset);

	CSLDestroy( papszCreateOptions );

	return RE_SUCCESS;
}
这里需要说明的是,上面的代码中,DEM渲染的颜色文件是一个可选的参数,因为我自己写了一个颜色映射文件,放在GDAL的data目录下面了。通过这个例子,大家也可以学习怎么使用gdal的data目录里的文件了。

dem_color_relief.clr的内容如下,其实就是之前翻译的那篇文章里面的颜色映射,URL为“http://blog.csdn.net/liminlu0314/article/details/8550410”。

0 110 220 110
900 240 250 160
1300 230 220 170
1900 220 220 220
2500 250 250 250
至此,使用上面的函数就可以对一个DEM数据进行渲染了,下面贴一下处理的结果。使用上面的颜色映射渲染的结果如图2所示;下面还有一组颜色映射,这个颜色更鲜艳一些,渲染后的图如图3所示。
100%	255	0	0	255
45.5%	255	255	0	255
20.5%	0	255	0	255
6.7%	0	250	255	255
3.5%	0	128	255	255
1.7%	0	64	255	255
0%	0	10	255	255
nv	0	0	0	0


图1 原始DEM数据

图2 颜色渲染后的结果

图3 颜色渲染后的结果2

转载于:https://www.cnblogs.com/xiaowangba/archive/2013/03/18/6313973.html

你可能感兴趣的:(使用GDAL对DEM进行彩色渲染)