自从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, '一个点扩展总用时')