Qt、GDAL遥感影像显示

11 篇文章 2 订阅
6 篇文章 1 订阅

影像显示原理

       显示遥感影像在业界做得比较牛逼的有ENVI,Erdas,以及ArcGIS软件。其实我并不想列举ArcGIS软件,但是ArcGIS毕竟是行业的大佬,所以。。

       遥感影像一般小到几百兆大到几个G,像这个么大的数据ENVI以及Erdas等软件是如何将它们显示出来呢!其实我一开始也比较好奇,同时也比较纳闷。这么大的数据,加载进来,软件居然一点都不卡,响应效率非常高,他们是怎么做到的。

       于是我去查看杜会建老师等团队写的idlviewer_useenvi源码,里面居然调用了IDL写好的接口,我表示很难受。居然他们把这条路堵死了,那只好我自己另寻它路。一开始我使用MFC来作为显示,GDAL读取影像,但这样的方式使得我花费了很长时间将读取出来的数据构建成图片,并将它在MFC的视图View中显示出来,于是我就寻思这样显示是不是有点问题,但是就感觉不到问题出现在哪里。知道后来我接触到了Qt,并使用了里面的QGraphicsView,才发现原来显示图像有这么好的“工具”,因为QGraphicsView自带缩放,而且平移事件只需要写一点点代码就可以完成,于是我将自己原来写的代码推翻,重新在Qt下面进行重构,最后发现原来显示图像可以这么简单。这时候,我感觉我将影像显示的部分做得很完美,因为我测试的时候仅仅使用的是ENVI里面的一个小数据进行测试,发现显示起来贼快,而且显示的效果和ENVI里面的效果一模一样,当时可把自己兴奋坏了。但是当我使用大影像去跑的时候,发现显示速度很慢,一个600M的资源卫星数据,显示出来居然要15秒,我顿时感觉自己的“成就”就是一坨屎。

       为了解决这个问题,于是我去调试分析,结果才发现我是一次性将数据全部读到内存当中,然后再显示出来。现在想想,这样不卡我名字倒着写。既然发现了问题所在,我又找解决方法,找着找着,突然灵光一闪,能不能显示多大就读取多大的数据进行初始化显示,但是这样的话又会存在一个难题,也就是平移缩放等事件都要自己去处理,而不能使用QGraphicsView原来的方法。现在也就是方法已经找到了,但是实现起来可能会有点难度,但是为了将影像显示出来,再复杂也要把它干掉。

       于是我将QGraphicsView的缩放以及平移事件都进行了重写,并利用高分数据进行测试,发现效果还可以哈!居然顺畅多了,无论是打开平移还是缩放的速度都很快,几乎感觉不到有什么卡顿的情况。但是当我加载多个数据之后(因为我想测试一下多个数据会不会有什么问题)问题又有了。那就是利用任务管理器查看程序占用的内存,发现每次打开一个数据,内存都会往上跳一个,按理来说,上升的内存不应该有这么大,于是我还是去找问题所在,找啊找,找啊找,可惜的是还是没有找到原因。

       于是去找以前MFC编写的程序,两个进行了一个对比,诶,发现了问题,我用MFC写的程序,加载数据内存增加与Qt增加的内存明显少了很多,于是我自己new了一个QGraphicsItem出来,发现原来这个东西居然耗费的内存也不小。我也真是想骂人了。没办法了,只能使用最后一招了,读取显示都用自己来写了。不能用QGraphicsView显示图像,更不能用QGraphicsItem来作为影像显示的载体了。

        只能直接在QWidget上面直接绘制影像,一开始在绘制的时候,没有考虑缩放和平移,做了一个简单的版本出来,发现效果还可以,在这个基础上,慢慢的加上了平移和缩放,但是在平移和缩放都是需要用代码来控制,这个就不容易了,一直思考这个怎么解决,但是一直都没有想到好的办法。后面我想了想,是不是自己的思路有问题,反过头来想,如果直接把设备坐标转为投影坐标,然后影像直接通过投影坐标进行显示,这样是不是就解决了,果不其然,还真是这样。将设备坐标转为投影坐标,再利用投影坐标的显示范围与图像的整个坐标范围进行求交,就可以得到影像的显示范围,在通过影像的显示范围坐标转为影像的行列号,将数据读取出来,进显示出来。

        经过自己不断努力,最终写出了一个自己还比较满意的显示影像的软件。后期就会往里面添加各种功能。在此,展示一下显示的效果:

这个图是与envi软件打开数据之后的对比,缩放比例都是1:1,可以清楚的看到显示的效果几乎一样。

        

 打开数据:

影像漫游:

影像拉伸显示:

影像保存:

软件更新:

2021年04月06号:

(1)、打开软件之后,原点默认在视口的中心;

(2)、优化坐标显示,原来是鼠标往上移动时,Y的值变小,现在改往下移动Y的值变小。这样更符合坐标系统。

(3)、优化影像打开时,默认以影像的中心与视图的中心重合;

(4)、添加软件设置,包含了

           1、保存上一次打开的路径;

           2、数据打开之后,数据管理窗口是否自动打开以及波段是否自动展开

           3、加载数据之后,数据窗口是否自动关闭

2021年10月01号:

        (1)、优化影像处理出现进度条崩溃bug;

        (2)、优化打开含有中文字符的波段出现乱码;

        (3)、优化显示的波段与图层列表中显示的不一致;

        (4)、优化读取高分3号数据失败bug; 

        (5)、添加影像拉伸(百分比拉伸,直方图均衡化);

        (6)、优化影像放大之后,出现影像不会布满全屏的白边;

        (7)、将GDAL版本从233升级到了330版本(主要是想使用坐标投影)

备注:

        此版本升级主要是优化显示,提高显示速度,并且优化构建金字塔。整体下来,显示3.3G的数据建金字塔花费了10秒不到的时间,显示更是1秒不到。而且还添加了影像拉伸等功能。

         显示不到1秒的原因主要是因为以前使用的是GDAL的影像统计,现在改为自己编写的统计方法,包括平均值,标准差,最大值以及最小值等。

2021年10月02号:

(1)、添加软件地理坐标显示,以前都是以像素行列号进行显示的;

(2)、没有投影信息的影像,那么不会显示坐标信息;

 备注:

本软件坐标图

ENVI软件坐标图​​​​

2021年10月06号:

        (1)、添加光谱曲线图,并且可以按照波段索引或者波长进行曲线图显示;

        (2)、同时可以显示多个影像的曲线图;

         (3)、在工具条中添加平移按钮(针对鼠标中键不好用的,比如我自己); 

 2021年10月18号:

(1)、添加绘制多边形感兴趣区;

(2)、添加绘制矩形感兴趣区;

(3)、优化没有坐标投影绘制感兴趣区出现漂移;

2021年10月26号:

(1)、优化没有显示的影像也会显示光谱曲线;

(2)、添加实时鼠标对应的像素值;

2021年10月31号:

(1)、优化切换ROI类型后,第一个绘制没有颜色;

(2)、添加保存ROI到txt文件;

(3)、添加读取ROI到图面;

(4)、实现目录树上移出数据功能;

 2021年11月22号:

        (1)、优化获取当前鼠标像素值(单波段会显示两个像素值);

         (2)、优化获取当前显示的波段(单波段获取显示波段时,第三个波段的值为0)

         (3)、优化ROI对话框确定和取消按钮无效

2021年12月24号:

        (1)、优化软件界面;

 2023年07月09号:

   (1)、添加透明度显示

   (2)、添加蜕化显示

   (3)、添加默认不显示无效值

2023年12月22号:

  (1)、移除自定义工具条,添加工具栏面板(更贴切ENVI界面)

  (2)、优化影像放大时读取的内存大小;

void GisEntsHelper::CalculateRasterRange(GeoPoint2d &pos, UInt2 &read, UInt2 &size, UInt2 &buf, UInt2 &show, GisDatasetRaster *pRaster, double dScale, const GeoExtents &exts)
{
	GeoMatrix3d trans; pRaster->getGeoTransform(trans);
	GeoExtents showExt = exts ^ trans;											//读取的像素范围
	size.x = ceil(showExt.width() - GisPrecision::GisEps());
	size.y = ceil(showExt.height() - GisPrecision::GisEps());
	read.x = floor(showExt.minPoint().rx()), read.y = (showExt.minPoint().ry());
	if(read.x + size.x < showExt.maxPoint().rx() - GisPrecision::GisEps()) size.x += 1;
	if(read.y + size.y < showExt.maxPoint().ry() - GisPrecision::GisEps()) size.y += 1;
	pos = GeoPoint2d(read.x, read.y) * trans;
	double xScale = fabs(trans.value(0, 0)), yScale = fabs(trans.value(1, 1));
	show.x = ceil(size.x * 1.0 / dScale * xScale);
	show.y = ceil(size.y * 1.0 / dScale * xScale);

	buf.x = dScale > 1.0 ? show.x : size.x;
	buf.y = dScale > 1.0 ? show.y : size.y;
}

  (3)、优化影像显示(改进拉伸),使得浏览速度更快

影像现在拉伸方式为(时间为0.1秒):

GisEntsHelper::GisLineStretchImage(mats1, pImpObject->histArray, sType, 0);

现在改为(时间为:0.014秒):

GisEntsHelper::GisLineStretchImageEx(mats, pImpObject->histArray, sType, 0);

 优化效率从0.1秒

  (4)、影像拉伸、蜕化、透明度设置都是针对单个影像,从而可以控制每个显示的影像状态;

  (5)、  重构底层代码;

2024年01月05号:

1、软件版本升级1.1 

        1、软件支持绘制功能区,目录树上控制是否显示。

显示感兴趣
感兴趣显示
不显示感兴趣

        2、优化影像处理接口(支持进度条显示任务名称)

        3、进度条支持多重任务进行

        4、支持执行任务时,界面还可以浏览数据

2、整理软件目录结构

 2024年01月06号:

1、添加对数拉伸

2、添加均平方根拉伸

3、优化单波段也可以进行透明度显示

透明度为72​​​​​​
透明度为0

4、优化像素值显示

Video_2024-01-06_035302

5、优化忽略无效值显示效果(之前是将每个波段的无效值赋值为255,现在改为每个波段无效值的交集作赋值为255)

6、优化输出数据时带投影信息

Video_2024-01-06_040011

 7、波段运算支持四则运算(加减乘除)

定义波段运算表达式
选择表达式对应的波段
计算结果
结果显示
envi显示效果

波段运算

 下面列出软件的svn地址以及软件运行介绍:

软件地址(SVN):软件下载地址

SVN账号:temp

SVN密码:temp

要在Python中使用GDAL库进行遥感影像配准,您可以使用以下代码示例: ```python from osgeo import gdal def image_registration(input_image_path, reference_image_path, output_image_path): # 打开需要配准的影像 src_ds = gdal.Open(input_image_path) # 打开参考影像 ref_ds = gdal.Open(reference_image_path) # 获取需要配准影像的地理转换信息 src_geo_transform = src_ds.GetGeoTransform() # 获取参考影像的地理转换信息 ref_geo_transform = ref_ds.GetGeoTransform() # 创建一个空的输出影像,用于存储配准结果 out_ds = gdal.GetDriverByName('GTiff').Create(output_image_path, src_ds.RasterXSize, src_ds.RasterYSize, src_ds.RasterCount, src_ds.GetRasterBand(1).DataType) # 设置输出影像的地理转换信息为参考影像的地理转换信息 out_ds.SetGeoTransform(ref_geo_transform) # 设置输出影像的投影信息为参考影像的投影信息 out_ds.SetProjection(ref_ds.GetProjection()) # 进行影像配准 gdal.ReprojectImage(src_ds, out_ds, src_ds.GetProjection(), ref_ds.GetProjection(), gdal.GRA_NearestNeighbour) # 关闭数据集 src_ds = None ref_ds = None out_ds = None # 调用函数进行影像配准 input_image_path = 'input_image.tif' reference_image_path = 'reference_image.tif' output_image_path = 'output_image.tif' image_registration(input_image_path, reference_image_path, output_image_path) ``` 请确保将`input_image.tif`替换为需要配准的影像路径,`reference_image.tif`替换为参考影像路径,`output_image.tif`替换为输出影像路径。 这个示例代码中的`image_registration`函数接受三个参数,分别是需要配准的影像路径、参考影像路径和输出影像路径。函数会打开需要配准的影像和参考影像,并根据参考影像的地理转换信息和投影信息创建一个空的输出影像。然后使用最近邻插值方法进行影像配准,最后关闭数据集。 希望这能对您有所帮助!如果您还有其他问题,请随时提问。
评论 108
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值