要编程才能进行的图像镶嵌拼接工作肯定是因为文件多,工作量大,手工操作几乎无法完成。
前辈们已经编写过用IDL/ENVI进行图像镶嵌的程序,粘贴了几个来试用后总感觉得到的结果赶不上用ENVI手工操作的结果,虽然这些程序也使用了ENVI的mosaic_doit方法。ENVI中的mosaicing到底是不是用mosaic_doit来做的啊?不管那么多,既然ENVI能做得好,搬用它的套路来做吧。
用mosaic_doit最麻烦的是参数设置,一大堆,IDL编程主要是获取这些参数。要获得跟ENVI手工拼出的图像一样的图形,其实思路很简单:用ENVI的参数!手工做一幅,这些参数就基本全了。所以,过程就是:
1、用ENVI手工拼一幅图,保存图像(用于提取地图信息)
2、在Map based Mosaic窗口的file菜单下保存拼接工作为模板(用于提取x0, y0坐标)
3、IDL简单编程,使用上面获得的地图和坐标信息进行拼接
得到的图像和ENVI手工拼接的完全一样。
pro MODIS_mosaicing
compile_opt idl2
envi,/restore_base_save_files
envi_batch_init
;
;设置路径,按情况修改
path = 'E:\D_RSensing\MODIS.NDV\NDV.original\'
outpath = 'E:\D_RSensing\MODIS.NDV\NDV.mosaic\'
;====================================================================
;- 先用envi手工拼接一幅图像mosaic.model.img作为结果模板
;- 从模板文件中获取 envi_doit需要的很多信息------------
modfile = path + "mosaic.model.img"
envi_open_file, modfile, r_fid=fid
envi_file_query,fid, dims=dims, ns=ns, nl=nl, data_type=data_type
map_info = envi_get_map_info(fid=fid) ;envi_doit参数
envi_file_mng,id=fid,/remove
pixel_size = map_info.ps[0:1] ;envi_doit参数
xsize = ns*map_info.ps[0] ;envi_doit参数
ysize = nl*map_info.ps[1] ;envi_doit参数
;
;====================================================================
;- 由于windows的限制,用dialog_pickfile不能选择太多的文件,
;- 要批量处理以万计的文件得先建好文件名解析的列表文件,这个需要自己去做
openr,lun,path + '0.datelist.txt', /get_lun
datelist = ''
thedate = ''
while not eof(lun) do begin & $
readf,lun, thedate & $
datelist = [datelist, thedate]
endwhile
free_lun, lun
close,lun
openr,lun,path + '0.loclist.txt', /get_lun
loclist = ''
theloc = ''
while not eof(lun) do begin & $
readf,lun, theloc & $
loclist = [loclist, theloc]
endwhile
free_lun, lun
close,lun
datelist = datelist[1:*]
loclist = loclist[1:*]
ndate = size(datelist, /n_elements) ;文件名中的日期信息,modis原样
nloc = size(locList, /n_elements) ;文件名中的坐标信息,以字符开头
;
;下面这个是从ENVI手工拼接保存的模板文件中提取的信息
openr,lun,path + '0.x0y0.txt', /get_lun
x0y0 = fltarr(2, nloc)
readf,lun, x0y0
free_lun, lun
close,lun
x0 = reform(x0y0[0,*]) ;envi_doit参数
y0 = reform(x0y0[1,*]) ;envi_doit参数
;
;====================================================================
;NDVI/EVI图像只能按相同日期进行拼接,只好按日期进行循环了
for datendx=0, ndate-1 do begin
ndv_files = path + 'NDVI.' + datelist[datendx] + '.' + loclist + '.tif'
result_file = outpath + 'NDVI.' + datelist[datendx] + '.img'
see_throuth_files = lonarr(nloc) + 1L
see_throuth_value = fltarr(nloc) ;按自己图像的背景值设定
background = see_throuth_value[0]
dims=lonarr(5, nloc) ;envi_doit参数
pos = lonarr(1,nloc) ;envi_doit参数,不用赋值,因为每个文件都是一个波段pos=0
fids = lonarr(nloc) ;envi_doit参数
for i=0,nloc-1 do begin
envi_open_file, ndv_files[i], r_fid=fidx
envi_file_query,fidx,ns=nsx,nl=nlx
mapinfo = envi_get_map_info(fid=fidx)
fids[i]=fidx
dims[*,i]=[-1,0, nsx-1,0, nlx-1]
endfor
;
envi_doit, 'mosaic_doit', fid=fids, out_name=result_file, $
dims=dims, pos=pos, xsize=xsize, ysize=ysize, $
x0=x0, y0=y0, pixel_size=pixel_size, $
out_dt=4, background=background, georef=1, map_info=map_info, $
see_through_val=see_throuth_value, use_see_through=see_throuth_files
;
for i=0, nloc-1 do envi_file_mng,id=fids[i],/remove
endfor; loops of datendx
;
envi_batch_exit
dlg = dialog_message("work done!")
end
顺便贴出用到的三个数据文件的生成代码(R语言脚本):
#tiff文件名应该包含经纬度和日期信息,否则不好批量处理
setwd(choose.dir(default = "D:/", caption = "选择tif文件所在文件夹"))
tif.files <- list.files('.', pattern="NDVI.*\\.tif$") #如果不是NDVI文件,改前缀就可以了
n <- length(tif.files)
dateList <- NULL
locList <- NULL
#我的NDVI文件命名模式是:NDVI.Axxxxxx.NExxxx.tif
#点号分隔第二部分为MODIS影像日期,第三部分是添加的经纬度信息
#日期和经纬度就可以用下面循环代码提取
for(i in 1:n){
fileinfo <- unlist(strsplit(tif.files[i], '.', fixed=T))
dateList <- c(dateList, fileinfo[2])
locList <- c(locList, fileinfo[3])
}
dateList <- sort(unique(dateList))
locList <- sort(unique(locList))
write(dateList, "0.datelist.txt", ncolumns = 1)
write(locList, "0.loclist.txt", ncolumns = 1)
#选择预先拼接和保存的模板文件,从中读取出x0y0信息
the.filter <- matrix(c(".mos", "*.mos", "All (*.*)", "*.*"), ncol = 2, byrow = T)
mosfile <- choose.files(caption = "Select mos file", filters = the.filter, index = 1)
model <- readLines(mosfile)
locs <- model[grepl("^File.+", model)]
locs <- gsub(".+(NE\\d+)\\.tif$", "\\1", locs)
xy <- model[grepl("^Info.+", model)]
xy <- gsub("^Info.*\\((.+)\\).+", "\\1", xy)
names(xy) <- locs
xy <- xy[locList]
write.table(xy, "0.x0y0.txt", row.names = F, col.names = F, quote=F)
winDialog(type="ok", message="Done")
如果手头没有合适的文件批量重命名工具,可以使用下面的R语言代码进行文件批量更名。警告:使用时先拷贝几个文件到新文件夹试试,以免出错后无法恢复原信息!
setwd(choose.dir(default = "D:/", caption = "选择tif文件所在文件夹"))
#下面是图像的经纬度标识,要添加到文件名中。每个MODIS压缩文件应解压到独立文件夹
lonlat <- "NE360955"
#下面语句选择要更名的文件,根据数据类型做相应修改(“NDVI”改成相应的名称)
orifiles <- list.files('.', pattern=".*NDVI.*\\.tif$")
#提取每个文件的日期信息,根据MODIS产品类型修改前缀(MOD13Q1部分)
dateinfo <- gsub("MOD13Q1\\.([^\\.]+)\\..+$", "\\1", orifiles)
#产生新的文件名,自己改吧
finals <- paste("NDVI", dateinfo, lonlat, "tif", sep=".")
n <- length(orifiles)
#文件重命名的代码
for(i in 1:n){
if(file.exists(finals[i])){
print(paste("文件", finals[i], "已存在,未修改!")
next
}
file.rename(orifiles[i], finals[i])
}
winDialog(type="ok", message="Done")