去除小斑块功能扩展
1、背景介绍:
在做分类后,结果图中有很多小斑点,为了消除小斑点,ENVI下提供了一些去除小斑块的工具,包括Majority/Minority Analysis工具、Clump Classes工具、Sieve Classes工具。本工具主要是对其进行扩展,综合了Majority Analysis和Sieve Classes的功能,使得我们进行小斑去除时能够更加灵活的进行设置,来达到结果要求。
2、原理:
通过处理窗口内的值,使得小于阈值个数的像元值被窗口中像元个数最多的值替换。例如,设置一个窗口3x3,一共9个值;阈值为2表示在这9个值中,某一个或几个像素值的个数如果小于等于2, 将被这9个值中个数最多的值替代。该方法综合了Majority Analysis和Sieve Classes的功能,能够有效的去除孤立的小斑点。 你可以根据需求,自定义参数,得到多样的结果。
3、功能介绍:
界面上主要设置的参数有:移动窗口、阈值、步长(默认)。
“移动窗口”尽量设为奇数值,不能过大,影响结果。
“阈值”值越大,结果越平滑,小斑块消除越厉害。
“步长”表示窗口移动的像素距离;
“步长”值越大,运行越快,不超过“移动窗口”值;
“步长”值越小,运算量越大,可以按照默认的值;
“步长”值一般默认的与设置的“移动窗口”值一样(推荐使用默认值)。
4、安装:
下载链接:http://www.rayfile.com/zh-cn/files/3ea3198a-fb80-11e0-b409-0015c55db73d/
将removelittleblock.sav文件拷贝到X:\Program Files\ITT\IDL\IDLx.x\products\envix.x\save_add目录下。
5、使用:
(1)启动ENVI->classification->“去除小斑块”。
(2)选择单波段文件(分类结果),点击OK。如果没有文件供选择,可以用Open按钮来打开一单波段文件。(如下图)
(3)弹出“去除小斑块”对话框,设置参数相应的参数后,点击“确定”执行。参数设置可以查看“帮助”。(如下图)
6、处理效果:
分别对原始的分类图,进行Majority Analysis 3X3窗口处理和“去除小斑块”参数(3,3,3)处理,得到如下的对比结果。
7、总结
ENVI+IDL功能强大,能够很方便快速的进行遥感图像处理的功能扩展。ENVI提供了文件的输入输出以及众多的图像处理功能的函数。即使有些功能没有提供函数,只要知道了原理和算法,也能非常方便和快捷的利用IDL来实现,同时结合ENVI的文件输入输出函数就能够很好的进行遥感功能的扩展。
8、源码
简介:程序中包括的功能
(1)自定义菜单
(2)核心运算程序
(3)利用ENVI的分块函数效率高
;####自定义菜单
PRO RemoveLittleBlock_define_buttons, buttonInfo
ENVI_DEFINE_MENU_BUTTON, buttonInfo, VALUE = '去除小斑块', $
uValue = '', $
event_pro ='RemoveLittleBlock', $
REF_VALUE = 'Classification',position=7
;想实现在已知菜单下添加按钮,这个/SIBLING一定不能要
;并且position指定了按钮的位置
end
;####运算函数
FUNCTION similarsmooth,inputdata,threshold
compile_opt idl2
;设置阈值的默认值
IF (N_ELEMENTS(threshold) EQ 0) THEN threshold=2
a=inputdata
b1=a[sort(a)] ;排序,
b2=uniq(b1) ;找唯一值下标
b3=b1[b2] ;找唯一值
n=n_elements(b3) ;我唯一值的个数
countx=intarr(n) ;初始化 用于记录每个唯一值的个数
for i=0,n-1 do begin
aa=where(a eq b3[i],count) ;窗口中的数据和每一个唯一值进行比较,并记录其个数
countx[i]=count ;记录每个唯一值的个数
endfor
t=max(countx) ;计算某个个数最多
indmax=where(countx eq t)
indmin=where(countx le threshold,count)
; print,'indmin:',n_elements(indmin),count
if count le 0 then begin
return,a
endif else begin
muldata=b3[indmax] ;个数最多的唯一值(不止一个)
; print,'muldata:',muldata ;个数最多的值可能不止一个,所以后面赋值的时候,取第一个值 muldata[0]。
minldata=b3[indmin] ;符合条件(个数少得)的其他唯一值(不止一个)
for i=0,count-1 do begin
a[where(a eq minldata[i])]=muldata[0] ;替换成个数最多的唯一值 可能不止一个,取第一个值 muldata[0]。
endfor
return,a
endelse
end
;;;InputFile:输入文件
;;;OutFile:输出路径
;;;MoveWindow:移动窗口大小,默认3x3
;;;Threshold:移动窗口中值的阈值。默认2
;;;step:step=1表示步长按照窗口大小走, step=0表示步长按照半窗口大小走。
;####利用ENVI的分块函数 方便!
pro EliminateSpeckle,Fid,OutFile,MoveWindow,Threshold,step
compile_opt idl2
IF (N_ELEMENTS(MoveWindow) EQ 0) THEN MoveWindow=3
IF (N_ELEMENTS(threshold) EQ 0) THEN threshold=2
IF (N_ELEMENTS(step) EQ 0) THEN step=MoveWindow
;参数确认
;;求outfile路径的最后一个字符,用于判定是否指定了文件名
;;未指定文件名的路径后面有一个字符‘\’.
p=strmid(strtrim(outFile,2),0,1,REVERSE_OFFSET=1)
; print,p
pp=strcmp(p,'\');比较字符
; print,pp
IF (pp) THEN begin
; print,outfile
void=DIALOG_MESSAGE('请指定输出路径和文件名',/info,title='提示')
return
endif else begin
outname=outfile
; print,outname
ENDELSE
; ENVI,/RESTORE_BASE_SAVE_FILES
; ENVI_BATCH_INIT
;envi_open_file, InputFile[0], r_fid=fid
if fid eq -1 then begin
void=DIALOG_MESSAGE('输入文件无效,请重新选择',/info,title='提示')
return
endif
envi_file_query, fid, dims=dims, nb=nb,nl=nl,ns=ns,DATA_TYPE=DATA_TYPE,$
interleave=interleave, xstart=xstart, ystart=ystart
;只处理单波段文件
if nb ne 1 then begin
void=DIALOG_MESSAGE('请指定单波段文件',/info,title='提示')
return
endif
inherit = envi_set_inheritance(fid, dims, 0, /full)
ostr = '输出路径: ' + outname
envi_report_init, ostr, title="正在运行", base=base ;++++
;;;;;;分块处理-----------
ndvi_tile_id=ENVI_INIT_TILE(fid, 0, num_tiles=num_tiles);,OVERLAP=MoveWindow)
openw,lun,outname,/get_lun
envi_report_inc, base, num_tiles;++++
print,'num_tiles:',num_tiles
for i=0L,num_tiles-1 do begin
; t1=SYSTIME(1)
envi_report_stat,base, i, num_tiles-1 ;++++
data = envi_get_tile(ndvi_tile_id, i)
; help,data
;data=ENVI_GET_DATA(fid=fid, dims=dims, pos=0)
data1=data
;指定窗口大小和移动步长
;q=(step-1)/2
q=(MoveWindow-1)/2
; step=MoveWindow
a=size(data)
; print,a[1]
; print,a[2]
; ; return
for n=q,a[2]-q-1 ,step do begin
for m=q,a[1]-q-1,step do begin
cdata=data1[(m-q):(m+q),(n-q):(n+q)]
data[(m-q):(m+q),(n-q):(n+q)]=SIMILARSMOOTH(CDATA,threshold)
endfor
endfor
; print,SYSTIME(1)-t1
writeu, lun, data
endfor
free_lun,lun
ENVI_SETUP_HEAD, fname=outname, data_type=DATA_TYPE,$
ns=ns, nl=nl, nb=1, xstart=xstart, ystart=ystart, $
INTERLEAVE =interleave,INHERIT=inherit, $
map_info=map_info,/write,/OPEN,OFFSET=0
envi_tile_done, ndvi_tile_id
; envi_file_mng, id=fid, /remove
envi_report_init, base=base, /finish;++++
end
;####帮助文档
pro HelpButton,event
WIDGET_CONTROL,event.top,GET_UVALUE=pstate
hlptlb=WIDGET_BASE(GROUP_LEADER=event.top,title='帮助文档')
value=['说明:设置一个窗口,如3x3,一共9个值;',$
' ',$
' 阈值为2表示在这9个值中,某一个值的个数如果小于2,',$
' ',$
' 将被这9个值中,个数最多的值替代;',$
' ',$
' “步长”表示窗口移动的像素距离;',$
' ',$
' 该方法能够有效的去除孤立的小斑点。',$
' ',$
' 你可以根据需求,自定义参数,得到多样的结果。',$
' ',$
' “移动窗口”尽量设为奇数值,不能过大,影响结果。',$
' ',$
' “阈值”值越大,结果越平滑,小斑块消除越厉害。',$
' ',$
' “步长”值越大,运行越快,不超过“移动窗口”值;',$
' ',$
' “步长”值越小,运算量越大,可以按照默认的值;',$
' ',$
' “步长”值一般默认的与设置的“移动窗口”值一样;',$
' ',$
' 如有问题请联系邮箱:,putiming',$
' ',$
' 2011-10-18']
hlptxt=WIDGET_TEXT(hlptlb,value=value,ysize=(*pstate).yoff*0.08,xsize=(*pstate).xoff*0.11)
WIDGET_CONTROL,hlptlb,/REALIZE
end
;####析构函数
pro clean_up,tlb
;compile_opt idl2
WIDGET_CONTROL,tlb,get_uvalue=pstate
ptr_free,pstate
end
;####界面事件响应
pro RemoveLittleBlock_event,event
WIDGET_CONTROL,event.top,GET_UVALUE=pstate
uName = WIDGET_INFO(event.id,/uname)
;窗口关闭
if TAG_NAMES(event,/STRUCTURE_NAME) eq 'WIDGET_KILL_REQUEST' then begin
WIDGET_CONTROL,event.top,/destroy
ptr_free,pstate
RETURN
endif
case uname of
'yidong':begin
WIDGET_CONTROL,event.id,GET_VALUE=x
; if x mod 2 eq 0 then begin
; void= DIALOG_MESSAGE('“移动窗口”值需为奇数',title='提示')
; WIDGET_CONTROL,event.id,sET_VALUE=3
; (*pstate).MoveWindow=3
; t=strtrim(sindgen(3)+1,2)
; WIDGET_CONTROL,(*pstate).list1,SET_VALUE=t
; return
; endif
envi_file_query, (*pstate).fid,nl=nl,ns=ns
if (x le nl) or (x le ns) then begin
if x ne '' then begin
; t=strtrim(sindgen(x)+1,2)
t=indgen(x)
t=x-t
t=strtrim(string(t),2)
; print,t
WIDGET_CONTROL,(*pstate).list1,SET_VALUE=t
(*pstate).MoveWindow=x
endif
endif else begin
void= DIALOG_MESSAGE('“移动窗口”值超过数据的行列数,请重设',title='提示')
WIDGET_CONTROL,event.id,sET_VALUE=3
(*pstate).MoveWindow=3
t=strtrim(sindgen(3)+1,2)
WIDGET_CONTROL,(*pstate).list1,SET_VALUE=t
WIDGET_CONTROL,(*pstate).field3,SET_VALUE=2
(*pstate).Threshold=2
return
endelse
end
'yuzhi' :begin
WIDGET_CONTROL,event.id,GET_VALUE=y
if y ge (*pstate).MoveWindow*(*pstate).MoveWindow then begin
void=DIALOG_MESSAGE('“阈值”必须小于“移动窗口”值平方',title='提示')
WIDGET_CONTROL,event.id,sET_VALUE=2
return
endif else begin
(*pstate).Threshold=y
endelse
end
'buchang':begin
WIDGET_CONTROL,event.id,GET_VALUE=z
(*pstate).step=z[event.index]
end
'xuanze':Begin
out_name=Dialog_Pickfile(Path=current, /NoConfirm, $
Get_Path=path, Filter=['*.*'],title='选择输出文件名')
if out_name eq '' then return
widget_control,(*pstate).txt,set_value=out_name
(*pstate).out_name=out_name
end
'lujing':begin
WIDGET_CONTROL,event.id,get_value=outname
(*pstate).out_name=outname
end
'queding':begin
if (*pstate).out_name eq '' then begin
void=DIALOG_MESSAGE('请指定输出路径',title='警告')
return
endif
EliminateSpeckle,(*pstate).Fid,(*pstate).out_name,(*pstate).MoveWindow,(*pstate).Threshold,(*pstate).step
end
'quxiao':begin
WIDGET_CONTROL,event.top,/destroy
end
'help':begin
HelpButton,event;启动帮助文档
end
else:begin
end
endcase
end
;####主程序 界面
PRO RemoveLittleBlock,event
dim= GET_SCREEN_SIZE()
print,dim
xoff=dim[0]*0.2
yoff=dim[1]*0.1
envi_center, xoff, yoff
ENVI_SELECT, fid=fid, pos=pos, /band_only, $
/no_dims,title='选择单波段文件'
if (fid[0] eq -1) then return
tlb=WIDGET_BASE(title='去除小斑块',/COLUMN,/TLB_KILL_REQUEST_EVENTS,$
TLB_FRAME_ATTR=1,xoff=xoff,yoff=yoff)
cstlb=WIDGET_BASE(tlb,/COLUMN,/FRAME)
field1 = CW_FIELD(cstlb, TITLE = '移动窗口(奇数):', /FRAME,value='3',$
/INTEGER,/all_EVENTS,uname='yidong')
field3 = CW_FIELD(cstlb, TITLE = '阈 值:', /FRAME,value='2',$
/INTEGER,/ALL_EVENTS,uname='yuzhi')
list1=WIDGET_dropLIST(cstlb,value=['3','2','1'],xsize=200,title='步 长:',uname='buchang')
kgtlb=WIDGET_BASE(tlb,/COLUMN)
label=WIDGET_LABEL(kgtlb,value='')
ljtlb=WIDGET_BASE(tlb,/COLUMN,/FRAME)
ljtlb1=WIDGET_BASE(ljtlb,/row)
lable=WIDGET_LABEL(ljtlb1,value='输出路径和文件名:')
lable=WIDGET_LABEL(ljtlb1,value=' ')
xz=WIDGET_BUTTON(ljtlb1,value='选择',Uname='xuanze')
ljtlb2=WIDGET_BASE(ljtlb)
txt=WIDGET_TEXT(ljtlb2,uname='lujing',/EDITABLE,/ALL_EVENTS,xsize=32)
kgtlb1=WIDGET_BASE(tlb,/COLUMN)
label=WIDGET_LABEL(kgtlb1,value='')
qdtlb=WIDGET_BASE(tlb,/FRAME,/row)
qd=WIDGET_BUTTON(qdtlb,value='确定',uname='queding')
lable=widget_label(qdtlb,value=' ')
qx=WIDGET_BUTTON(qdtlb,value='取消',Uname='quxiao')
lable=widget_label(qdtlb,value=' ')
qx=WIDGET_BUTTON(qdtlb,value='帮助',Uname='help')
pstate=PTR_NEW({list1:list1,$
field3:field3,$
txt:txt, $
out_name:'' , $
Fid:fid, $
MoveWindow:3,$
Threshold:2,$
step:3 ,$
xoff:xoff ,$
yoff:yoff $
},/no_copy)
WIDGET_CONTROL,tlb,SET_UVALUE=pstate
WIDGET_CONTROL,tlb,/REALIZE
XMANAGER,'RemoveLittleBlock',tlb,/NO_BLOCK,cleanup='clean_up'
end