遥感影像降位16位到8位

2023-05-16

From: https://blog.csdn.net/shenshanxiaozhu/article/details/53224554

    常用卫星影像基本上都是16位影像,在某些应用场景下需要将16位影像降到8位影像,这样不仅减小了数据量,也便于后期处理。常用的降位方法先通过直方图进行百分比截断,然后进行拉伸包括,最简单的线性拉伸,分段拉伸以及对数变换和指数变换等。这里结合常用影像的特点使用百分比截断和指数(幂为0.7)变换将影像从16位降到8位。

    int imageprocessing::stretch_percent_16to8(const char *inFilename, const char *dstFilename)
	{
		GDALAllRegister();
		//为了支持中文路径
		CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");
		int src_height = 0; 
		int src_width = 0;
		GDALDataset *poIn = (GDALDataset *)GDALOpen(inFilename,GA_ReadOnly);   //打开影像
		//获取影像大小
		src_width = poIn ->GetRasterXSize();
		src_height = poIn ->GetRasterYSize();
		//获取影像波段数
		int InBands = poIn ->GetRasterCount();
		//获取影像格式
		GDALDataType eDataType = poIn -> GetRasterBand(1) -> GetRasterDataType();
		//定义存储影像的空间参考数组
		double adfInGeoTransform[6] = {0};
		const char *pszWKT = NULL;
		//获取影像空间参考
		poIn ->GetGeoTransform(adfInGeoTransform);
		pszWKT = poIn ->GetProjectionRef();
		//创建文件
		GDALDriver *poDriver = (GDALDriver *)GDALGetDriverByName("GTiff");
		GDALDataset *poOutputDS = poDriver -> Create(dstFilename,src_width,src_height,InBands,GDT_Byte,NULL);
 
		//设置拉伸后图像的空间参考以及地理坐标
		poOutputDS -> SetGeoTransform(adfInGeoTransform);
		poOutputDS -> SetProjection(pszWKT);
		//读取影像
 
		cout<<"16位影像降到8位影像处理..."<<endl;
		for(int iBand = 0; iBand < InBands; iBand++ )
		{
			cout<<"正在处理第 "<<iBand + 1<<" 波段"<<endl;
			//读取影像
			uint16_t *srcData = (uint16_t *)malloc(sizeof(uint16_t) *src_width * src_height *1);
			memset(srcData,0,sizeof(uint16_t ) * 1 *src_width * src_height);
			int src_max = 0, src_min = 65500;
			//读取多光谱影像到缓存
			poIn ->GetRasterBand( iBand + 1) -> RasterIO( GF_Read, 0, 0, src_width, src_height , srcData + 0 * src_width * src_height,src_width,src_height, GDT_UInt16, 0, 0 );
		//}
		//统计最大值
		for (int src_row = 0; src_row < src_height; src_row ++)
		{
			for (int src_col = 0; src_col < src_width; src_col++)
			{
				uint16_t src_temVal = *(srcData + src_row * src_width + src_col);
				if (src_temVal > src_max)
					src_max = src_temVal;
				if(src_temVal < src_min )
					src_min = src_temVal;
			}
		}
 
		double *numb_pix = (double *)malloc(sizeof(double)*(src_max+1));      //存像素值直方图,即每个像素值的个数
		memset(numb_pix,0,sizeof(double) * (src_max+1));
		//                 -------  统计像素值直方图  ------------         //
 
		for (int src_row = 0; src_row < src_height; src_row ++)
		{
			for (int src_col = 0; src_col < src_width; src_col++)
			{
				uint16_t src_temVal = *(srcData + src_row * src_width + src_col);
				*(numb_pix + src_temVal) += 1;
			}
		}
 
		double *frequency_val = (double *)malloc(sizeof(double)*(src_max+1));           //像素值出现的频率
		memset(frequency_val,0.0,sizeof(double)*(src_max+1));
 
		for (int val_i = 0; val_i <= src_max; val_i++)
		{
			*(frequency_val + val_i) = *(numb_pix + val_i) / double(src_width * src_height);
		}
 
		double *accumlt_frequency_val = (double*)malloc(sizeof(double)*(src_max+1));   //像素出现的累计频率
		memset(accumlt_frequency_val, 0.0,sizeof(double)*(src_max+1));
 
		for (int val_i = 0; val_i <= src_max; val_i ++)
		{
			for (int val_j = 0; val_j < val_i; val_j ++ )
			{
				*(accumlt_frequency_val + val_i) += *(frequency_val + val_j);
			}
		}
		//统计像素两端截断值
		int minVal = 0, maxVal = 0;
		for (int val_i = 1; val_i < src_max; val_i++)
		{
			double acc_fre_temVal0 = *(frequency_val + 0);
			double acc_fre_temVal = *(accumlt_frequency_val + val_i);
			if((acc_fre_temVal - acc_fre_temVal0) > 0.0015 )
			{	minVal = val_i;
				break;	}
		}
		for (int val_i = src_max-1; val_i > 0; val_i--)
		{
			double acc_fre_temVal0 = *(accumlt_frequency_val + src_max);
			double acc_fre_temVal = *(accumlt_frequency_val + val_i);
			if(acc_fre_temVal < (acc_fre_temVal0 - 0.00012) )
			{	maxVal = val_i;
				break;	}
		}
		
		for (int src_row = 0; src_row < src_height; src_row ++)
		{
			uint8_t *dstData = (uint8_t*)malloc(sizeof(uint8_t)*src_width);
			memset(dstData, 0, sizeof(uint8_t)*src_width);
			for (int src_col = 0; src_col < src_width; src_col++)
			{
				uint16_t src_temVal = *(srcData + src_row * src_width + src_col);
				double stre_temVal = (src_temVal - minVal) / double(maxVal - minVal) ;
				if(src_temVal < minVal)
				{
					*(dstData + src_col) = (src_temVal) *(20.0/double(minVal)) ;
				}
				else if(src_temVal > maxVal)
				{	stre_temVal = (src_temVal - src_min) / double(src_max - src_min);
					*(dstData + src_col) = 254;	}
				else
					*(dstData + src_col) = pow(stre_temVal,0.7) * 250;
 
			}
			poOutputDS->GetRasterBand(iBand + 1)->RasterIO(GF_Write, 0,src_row,src_width,1,dstData,src_width,1,GDT_Byte,0,0);
			free(dstData);
		}
 
		free(numb_pix);
		free(frequency_val);
		free(accumlt_frequency_val);
		free(srcData);
		
		}
		GDALClose(poIn);
		GDALClose(poOutputDS);
 
		return 0;
	}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

遥感影像降位16位到8位 的相关文章

  • 3、Oracle PL/SQL中Date格式及格式转换

    该文章是 PL SQL基础 xff08 3 xff09 xff1a 小专题 系列文章之一 Oracle 插入日期 xff08 时间 xff09 时报错 xff1a ORA 01861 文字与格式字符串不匹配 这是由于插入的日期格式和数据库现
  • 5、Oracle数据库insert后获取自增的ID

    该文章是 PL SQL基础 xff08 3 xff09 xff1a 小专题 系列文章之一 在 insert 后使用 select 序列名 CURRVAL from dual 可以获取 insert后自增的ID 具体 SQL 语句 xff1a
  • 解决cmd 中ping>nul语句提示命令符无法识别

    问题描述 xff1a 在批量使用chrome exe ftp data hdf amp ping n10 127 0 0 1 gt nul 下载数据时 xff0c 命令行没有因为ping命令暂停 解决 xff1a 怀疑是ping这部分命令存
  • C#控件限制输入字符数且可用退格

    对于C 控件 xff08 例如textbox xff09 的输入限制长度 xff0c 直接想到的方法是在控件的KeyPress事件时判断控件已有的字符数来限制 假设控件名称为DAForm myBox4 xff0c KeyPress事件简单的
  • XXX事件的重载均与委托"System.EventHandler"不匹配

    在给动态创建控件添加事件时容易遇到的一个错误就是 xff1a XXX事件的重载均与委托 34 System EventHandler 34 不匹配 假设控件是MovePicBox xff0c 使用如下代码添加KeyPress事件 xff0c
  • 外部启动c#窗体程序传参问题

    问题 xff1a 需要在一个软件里启动另一个独立的C 窗体软件并传入参数 xff0c 例如下面的启动语句 string language 61 34 en us 34 System Diagnostics Process Start 34
  • C#控件控制输入文本长度

    C 在控制控件输入文本的长度时要注意两个问题 xff1a 1 传递的事件参数类型要是 KeyPressEventArgs xff1b 2 对退格键 xff08 backspace xff09 做例外处理 xff0c 不然在输入到最大程度时无
  • python打印等腰三角形

    d 61 int input 39 enter an int 39 l 61 39 39 2 d 1 d 初始化列表 for i in range d l i 61 list l i 字符串转列表 x 61 i y 61 0 x 61 d
  • 7、Oracle的;与ORA-00911: invalid character

    写SQL查询 Oracle中的数据时容易遇到一个奇怪的问题 xff1a 在一般的SQL developer查询分析器中写好的SQL语句运行一切正常 xff0c 放到C 写的程序中提交 ORACLE执行就报错 错误代码如下 xff1a ORA
  • C语言变量声明加冒号的用法

    有些信息在存储时 xff0c 并不需要占用一个完整的字节 xff0c 而只需占几个或一个二进制位 例如在存放一个开关量时 xff0c 只有0和1 两种状态 xff0c 用一位二进位即可 为了节省存储空间 xff0c 并使处理简便 xff0c
  • Matlab adjust axis tick labels, limits, and tick locations

    From https cn mathworks com matlabcentral answers 92565 how do i control axis tick labels limits and axes tick locations
  • Matlab 旋转坐标轴标记文本

    在绘图中当X坐标轴标记 xff08 注意不是坐标轴名称的标签 xff09 是文本且较密集的时候我们会希望能够旋转标签以容得下所有内容 xff0c 当Y坐标轴标记是文本时 xff0c 我们也希望文本可以顺着Y轴的方向 这些都需要旋转坐标轴的标
  • Matlab - Extract values from boxplot(从箱图中获取数据)

    From http stackoverflow com questions 9728970 matlab extract values from boxplot How to extract values from built in box
  • matlab写hdf文件(含地理信息文件hdfeos)

    本文介绍matlab写hdf4和hdf5的一些方法 hdf的一些基础信息可以参考 xff1a https sanwen8 cn p 1fcFE9f html 1 matlab写hdf4文件 通常有两种方法 xff1a 1 xff09 mat
  • oracle ORA-01000: maximum open cursors exceeded问题的解决方法

    From http blog csdn net uskystars article details 46679835 项目在运行过程中 xff0c 后台报错 xff1a Java代码 ORA 01000 maximum open curso
  • emgu.cv的图像金字塔操作

    emgu cv里有三个常用的影像金字塔 xff08 重采样 xff0c 每一级倍数2 xff09 函数 xff1a 1 BuildPyramid int maxLevel 建立多级影像金字塔 C 例子 xff1a Int maxLevel
  • ENVI栅格裸数据生成shp和kml矢量文件

    ENVI栅格裸数据生成shp和kml矢量文件 生成kml文件需要用到ArcMap xff0c 但是ArcMap不能直接加载ENVI裸数据 xff0c 需要在ENVI里将栅格数据转为shp或另存为ArcViewRaster 前者生成kml文件
  • 笔记:刘未鹏思考的技术与艺术(原“学会思考”)

    在读 暗时间 这本书的时候了解到刘未鹏 xff0c 也了解到关于心理学 学会思考 的豆列 xff0c 推荐的书很棒 xff0c 体系也很完善 xff0c 特作记录 豆列的地址在 xff1a https www douban com doul
  • python文件读写的缓冲行为

    文件的io操作的缓冲行为分为 全缓冲 xff1a 同系统及磁盘块大小有关 xff0c n个字节后执行一次写入操作 行缓冲 xff1a 遇到换行符执行一次写操作 无缓冲 xff1a 立刻执行写操作 open 函数 help open Help

随机推荐