自适应窗口算法设计

 自从10月末、11月初写了一个有关计算SEVI的小软件,优化、便利化、实时出结果的想法,就一直回旋在脑海。
 我是这么构思的,下面分优化、心理历程的几个阶段进行阐述:

第一个阶段、初探(10月第四周)

1 思路

 f值的窗口如何选?起初我是暂定以坡度最大值格点为中心格点,以20格20格为初始窗口,也就是600m600m为初始窗口,这样应该可以同时触及到阴阳坡,如果初始窗口过小的话,可能就仅单单会涉及到阴坡或者阳坡。向外以步长为5格,60格为最大扩展半径。开始向外成上下、左右同时扩展在这里插入图片描述

2 实施

具体形成代码如下:

# 注: 已完成了阴阳坡剖分图
[max_hang,max_lie] = np.where(slope == np.max(slope))
max_hang = xi
max_lie = yi
width_pre = 10
height_pre = 10
for add in range(0,61,5):
	width = width_pre+add
	height = height_pre+add
	sum_area = 2*width*2*height
	# -------窗口参数如下--------
       win_up = max_hang-height  
       win_bottom = max_hang+height
       win_left = max_lie-width
       win_right = max_lie+width
       windows = aspect_10[int(win_up):int(win_bottom),int(win_left ):int(win_right)]   
       sum_windows1 = np.sum(windows == 1)
       ind1 = sum_windows1/windows  # 当ind1等于50%时,确认为当前最优窗口

 为什么设置指标-ind1?之前有做过验证,纯阳坡、纯阴坡、阴阳坡混合,第三种用来计算最好。这是因为,根据SEVI的“相关系数法”的计算算法,里面的皮尔逊相关系数涉及到了求累积和、累乘和。与SEVI求共线性相关性的RVI、SVI一个是为阳坡“声张”的量,一个是为阴坡“声张”的量。所以,当阴阳坡面积足够大,且被声张的力量相等时,f值的计算结果才最有意义。
通过使指标1-ind1等于50%,也就是阴阳坡像元数相等,面积相等时,被当做最佳窗口,进行计算。

3 弊端

 (1)未涉及到非矩形不规则边界的问题,如果遥感影像为非矩形,窗口很可能就会扩展到背景值。
在这里插入图片描述
 (2)窗口扩展方式很单调,有可能涉及扩不到最佳窗口的问题。假设步长为s,最大长度M,从0步长开始扩展,那么这种扩展方式一共会运算(M/s)次。

第二个阶段、改进(11月第二周及第三周前三天)

1 问题及解决方案

 知识往往都是一个循序渐进的过程,当我11月第二周刚开始感觉渐入佳境的时候,有很多实际的问题,其实都给予我了迎头痛击。
 根据第一个阶段所存在的问题,以及老师所给出的建议。想出了构建第二个指标—ind2,这个指标也是为了判断窗口的可用性,就是是否涉及到了背景值的问题。具体实现代码如下:

# 注: 表观反射率不会存在负值,以及很小可能出现0值。满足这些值就是背景值。
# 用Arcgis剪裁背景值可能会出现-38e+38这个数,是小于-5的
rs_windows = rs[int(win_up):int(win_bottom),int(win_left ):int(win_right)]   
index1 = np.where(rs_windows < 5)[0]   # 小坑,np.where返回的是一个tuple,等于2
index2 = np.where(rs_windows == 0)[0]
ind2 = index1 + index2

2 扩展方式

 左右宽度扩一次,上下高度扩12次,以此循环。假设步长为s,最大长度M,从0步长开始扩展,那么这种扩展方式一共会运算(M/s)^2次。以一个最大坡度点为中心点,代入s = 5,M = 60,共扩展244次。假设步长为1,那么一个中心点一共可扩展3600次。
 比上阶段,上下、左右同扩方式,次数多了整整一倍。
在这里插入图片描述

3 代码实现

结合窗口扩展方式的问题:

# 上下同扩、左右同扩的方案
[max_hang,max_lie] = np.where(slope == np.max(slope))
max_hang = xi
max_lie = yi
width_pre = 10
height_pre = 10
for add1 in range(0,M+1,s):  # 左右扩一次
	width = width_pre+add
	for add2 in range(0,M+1,s):   # 上下扩一次
		height = height_pre+add
		sum_area = 2*width*2*height
	       win_up = max_hang-height  
	       win_bottom = max_hang+height
	       win_left = max_lie-width
	       win_right = max_lie+width
       		# ----------指标1、2---------
	       windows = aspect_10[int(win_up):int(win_bottom),int(win_left ):int(win_right)]   
	       sum_windows1 = np.sum(windows == 1)
	       ind1 = sum_windows1/windows  # 当ind1等于50%时,确认为当前最优窗口
	       ind1 = int(ind1*100)  # float没法判断,转换为int
	       rs_windows = rs[int(win_up):int(win_bottom),int(win_left ):int(win_right)]   
		index1 = np.where(rs_windows < 5)[0]   # 小坑,np.where返回的是一个tuple,等于2
		index2 = np.where(rs_windows == 0)[0]
		ind2 = index1 + index2
		if ind1 == 50:
			if ind2 == 0 :
				#--------  f值算法----------
				pass

第三个阶段、辗转反侧(11月第三周星期四)

1 晴天转多云

  经过前两个阶段的铺垫,没有说,东西越来越明晰,反而发现了越来越多的问题,总结为一句话,如何自动化的选择最佳窗口?
(1) f值算法问题,什么样的f值才是满足情况的呢?选取满足情况的f值的最优f值?
(2)窗口遍历不完整的问题
 单单是第一个问题,就有够我们考虑的了。我们先易后难,先讨论第二个问题,其实第二个问题,不是特别难,而是具体优化的问题。

2 窗口扩展问题

 针对窗口如何扩展的问题。我们采取螺线式扩展的方法,如下边右图所示,设最大扩展长度M,则在2M这个最大扩展正方形的内部,存在((M-10)^4)-1个矩形,可以由我们的中心点进行扩展。

 对每个矩形判断上述的两个指标—ind1、ind2。事实上就能得到所有满足计算f值条件的窗口了。

# 注: 螺线式扩展法-逆时针
for add1 in range(0, M+1, s):  # 上扩一次
    win_up = now_hang-height_pre-add1  # now_hang为待扩展中心点的行坐标
    for add2 in range(0,  M + 1,  s):  # 左扩一次
        win_left = now_lie - width_pre - add2  # now_lie为待扩展中心点的列坐标
    for add3 in range(0,  M + 1,  s):  # 下扩一次
        win_bottom = now_hang + height_pre + add3
        for add4 in range(0,  M + 1,  s):  # 下扩一次
            win_right = now_lie + width_pre + add4
            # ----------指标1、2---------
            windows = aspect_10[int(win_up):int(win_bottom), int(win_left):int(win_right)]
            sum_windows1 = np.sum(windows == 1)
            sum_area = (win_bottom-win_up)*(win_right-win_left)
            ind1 = int((sum_windows1 / sum_area) * 100)  # 当ind1等于50%时,确认为当前最优窗口
            rs_wds = band4[int(win_up):int(win_bottom), int(win_left):int(win_right)]
            index1 = len(np.where(rs_wds < 5)[0])   # 小坑,np.where返回的是一个tuple,等于2
            index2 = len(np.where(rs_wds == 0)[0])
            ind2 = index1 + index2
            if ind1 == 50:
                if ind2 == 0:
                    # --------  f值算法----------
               	 pass

在这里插入图片描述

 螺线式扩展法,共扩展(M/s)^4次。以武夷山LC8的影像为例,M可以设置为影像最大边的1/2,也就是700,s可以设置为1。那每个中心点,需要测试扩展2401亿次。那么每个格点作为中心点(1400*1200个)都扩展测试一下呢?显然,这种计算方法能得到每个满足情况的窗口,也可以得到每个窗口内的最优f值。那么应该采用这么多窗口,哪个窗口下的最优f值呢?

3 测试最优f值中的最优

 常规计算一个窗口下的f值,就是让f从0开始,以0.01为步长,遍历至1。当此时的f值使SEVI_win与RVI_win、SVI_win的线性关系相近,也就是SEVI_now与RVI的皮尔逊相关系数为r1、SEVI_win与SVI_win的皮尔逊相关系数为r2,e = r1-r2 ≈0时,但是代码无法理解多少才是约等于0,所以认定最小的残差e,为此时的最优f值。代码如下:

# 常规f值算法
     for f in range(0, 1001, 1):
            if f % 500 == 0:  # 进度条 
                print('当前运行了:{}%'.format(f/10))
            f = f / 1000
            SEVI_win = RVI_win + f * SVI_win
            n = len[SEVI]*len[SEVI[0]]
            r1 = Cal_PersonCC(SEVI, RVI, n)
            r2 = Cal_PersonCC(SEVI, SVI, n)
            e = abs(r1) - abs(r2)
            list_e.append(abs(e))
            list_f.append(f)
        e_min = min(list_e)
        f_opt = list_f[list_e.index(e_min)]  # e最小情况下的,当前窗口最优f值

*. * 思考

 指标1、2是用来选择合适的窗口 , 现在我们需要新的指标来:(1)判断最优f值是否符合设计条件. (2)以及用哪个窗口的最优f值。下面流程图是为了探究,当前窗口的最优f值的可用性:
在这里插入图片描述
  注:SC_win为当前窗口下SEVI_win与COSI_win的相关系数,用来判断f值的优度。
所以,新设计两个指标如下:
ind3 = 0.001 : 观察e,如何说是接近0呢?皮尔逊相关系数主要是通过两个变量的离散程度,来判断是否有明显或者不明显的线性关系的。所以,其实当 e <= 0.001的时候,就可以认定,他们之间的线性相关性接近了。而且,没有比较真正使f从0循环到1,因为f值的改变,其实并不会实际影响到SC太大的浮动。
ind4 = 0.05 : 当SC_win小于0.05,证明当前窗口下这个最优f值可用 ,计算出来的SEVI效果较好。

4 四指标原则,最优f中选最优

 总的来说,就是ind1、ind2指标控制窗口,ind3指标控制f值,ind4控制f值可用度及优度
在这里插入图片描述

具体实现代码:

import numpy as np
import datetime
import time
from ReadTif import *
from CalSEVI_maxSlope_gai_cal_f import *
s = datetime.datetime.now()
# --------------data-----------------------
slope, im_proj, im_geotrans, im_height, im_width = GRID().Tif_ReadBands(
    'F://2014018-wys-4-wys-yq4tif.tif', 1)
aspect = GRID().Tif_ReadBands('F:/2014018-wys-4-wys-yq4tif.tif', 2)[0]
band4 = GRID().Tif_ReadBands('F://2014018-wys-4-wys-yq4tif.tif', 3)[0]
band5 = GRID().Tif_ReadBands('F://2014018-wys-4-wys-yq4tif.tif', 4)[0]
sun_azimuth = 145.80911759  
sun_zenith = 40.65020465
aspect_10 = cal_sss(sun_azimuth, aspect)
COSI = cal_cosi(sun_zenith, sun_azimuth, slope, aspect)
SVI_over = 1 / band4  # 计算SVI
RVI_over = band5 / band4  # 计算RVI
s = runTime(s, '准备工作')
# --------------windows-----------------------
M = 200
s = 5
print('共需扩展{}次'.format((M/s)**4))
now_hang = 50
now_lie = 50
height_pre = 10
width_pre = 10
width_pre = 10  # 假定初始窗口大小为20*20,然后逐步扩大
count = 0 # 记录窗口的扩展次数
for add1 in range(0, M+1, s):  # 上扩一次
    win_up = now_hang-height_pre-add1  # now_hang为待扩展中心点的行坐标
    for add2 in range(0,  M + 1,  s):  # 左扩一次
        win_left = now_lie - width_pre - add2  # now_lie为待扩展中心点的列坐标
        for add3 in range(0,  M + 1,  s):  # 下扩一次
            win_bottom = now_hang + height_pre + add3
            for add4 in range(0,  M + 1,  s):  # 下扩一次
                win_right = now_lie + width_pre + add4
                count = count + 1
                # ----------指标1、2---------
                try:
                    windows = aspect_10[int(win_up):int(win_bottom), int(win_left):int(win_right)]
                    sum_windows1 = np.sum(windows == 1)
                    sum_area = (win_bottom-win_up)*(win_right-win_left)
                    ind1 = int((sum_windows1 / sum_area) * 100)  # 当ind1等于50%时,确认为当前最优窗口
                    rs_wds = band4[int(win_up):int(win_bottom), int(win_left):int(win_right)]
                    index1 = len(np.where(rs_wds < -5)[0])   # 小坑,np.where返回的是一个tuple,等于2
                    index2 = len(np.where(rs_wds == 0)[0])
                    ind2 = index1 + index2
                    if ind1 == 50:
                        if ind2 == 0:
                            # --------  f值算法----------
                            SVI_wds = SVI_over[int(win_up):int(win_bottom), int(win_left):int(win_right)]
                            RVI_wds = RVI_over[int(win_up):int(win_bottom), int(win_left):int(win_right)]
                            cosi = COSI[int(win_up):int(win_bottom), int(win_left):int(win_right)]
                            n = len(cosi) * len(cosi[0])
                            ind3 = 0.001  # 用来判定r1与r2的小的程度
                            ind4 = 0.05  # 用来判定与cosi的近似小
                            flag1 = 0  # 跳出f
                            for f in range(0, 1001, 1):
                                if flag1 == 1:
                                    print('out')
                                    break
                                f = f / 1000
                                SEVI_wds = RVI_wds + f * SVI_wds  # 求取当前窗口SEVI
                                r1 = Cal_PersonCC(SEVI_wds, RVI_wds, len(SEVI_wds)*len(SEVI_wds[0]))  # 相关系数法
                                r2 = Cal_PersonCC(SEVI_wds, SVI_wds, len(SEVI_wds)*len(SEVI_wds[0]))
                                e = abs(abs(r1) - abs(r2))  # e要满足接近于0
                                if e <= ind3:  # 满足指标3,就是相关系数法求得的f值,若一个也没有,证明当前窗口不可用
                                    SEVI_over = RVI_over + f * SVI_over  # 求取全局SEVI
                                    SC_wds = abs(Cal_PersonCC(SEVI_wds, cosi, len(SEVI_wds)*len(SEVI_wds[0])))
                                    SC_over = abs(Cal_PersonCC(SEVI_over, COSI, len(SEVI_over)*len(SEVI_over[0])))
                                    if SC_wds < ind4:  # 满足指标4,就是优质f值
                                        print('\n\n\n**发现满足条件的:f、SC_wds、SC_over、e:\n')
                                        print(f, '\t', SC_wds, '\t', SC_over, '\t', e)
                                        print(win_up, win_bottom,win_left, win_right)
                                        print('窗口已扩展了,', count, '次\n\n\n')
                                        flag1 = 1  # 当前f值,满足了ind3,也满足了ind4,表示可用,确定为窗口内最佳
                                        break
                                    else:
                                        print('\t***满足ind1、ind2、ind3,但是不满足ind4','窗口已扩展了,', count, '次')
                                        flag1 = 1  # f值的变动其实对这个窗口内的,SEVI与COSI的关系影响不大了,不满足就立马换窗口
                                        break
                except Exception as e:
                    print(e)
                    
s = runTime(s, '一个点扩展总用时')

猜你喜欢

转载自blog.csdn.net/qq_40260867/article/details/84374342
今日推荐