桃夭txt君子在野百度云:利用ENVI IDL去除小斑块功能扩展(附源码)

来源:百度文库 编辑:中财网 时间:2024/04/27 23:26:28
利用ENVI+IDL去除小斑块功能扩展(附源码)2011-10-21 09:36

去除小斑块功能扩展

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