传递超过23个输入文件时gdal_calc amin失败

jba*_*ums 9 python numpy r raster gdal

我编写了一个R函数,gdal_calc.py用于计算RasterStack(一系列输入栅格文件)的像素值最小值.我这样做是因为它比raster::min大型栅格更快.该函数最多可以存储23个文件,但在传递24个或更多文件时会抛出警告,返回填充了零的输出栅格.

由于R只是准备系统调用python gdal_calc.py,这个问题不是R特有的,我鼓励python/numpy aficionados继续阅读.

这是功能.最终gdal_calc调用的结构显示在此帖子底部有问题的用法引发的警告消息中.

gdal_min <- function(infile, outfile, return_raster=FALSE, overwrite=FALSE) {
  require(rgdal)
  if(return_raster) require(raster)
  # infile:        The multiband raster file (or a vector of paths to multiple 
  #                 raster files) for which to calculate cell minima.
  # outfile:       Path to raster output file.
  # return_raster: (logical) Should the output raster be read back into R?
  # overwrite:     (logical) Should outfile be overwritten if it exists?
  gdal_calc <- Sys.which('gdal_calc.py')
  if(gdal_calc=='') stop('gdal_calc.py not found on system.')
  if(file.exists(outfile) & !overwrite) 
    stop("'outfile' already exists. Use overwrite=TRUE to overwrite.", 
         call.=FALSE)
  nbands <- sapply(infile, function(x) nrow(attr(GDALinfo(x), 'df')))
  if(length(infile) > 26 || nbands > 26) stop('Maximum number of inputs is 26.')
  if(length(nbands) > 1 & any(nbands > 1)) 
    warning('One or more rasters have multiple bands. First band used.')

  if(length(infile)==1) {
    inputs <- paste0('-', LETTERS[seq_len(nbands)], ' ', infile, ' --', 
                     LETTERS[seq_len(nbands)], '_band ', seq_len(nbands), collapse=' ')
    n <- nbands
  } else {
    inputs <- paste0('-', LETTERS[seq_along(nbands)], ' ', infile, ' --', 
                     LETTERS[seq_along(nbands)], '_band 1', collapse=' ')
    n <- length(infile)
  }

  message('Calculating minimum and writing to ', basename(outfile))
  system2('python',
          args=c(gdal_calc, inputs,
                 sprintf("--outfile=%s", outfile),
                 sprintf('--calc="amin([%s], axis=0)"', 
                         paste0(LETTERS[seq_len(n)], collapse=',')),
                 '--co="COMPRESS=LZW"',
                 if(overwrite) '--overwrite'),
          stdout=FALSE
  )
  if(return_raster) raster(outfile) else invisible(NULL)
}
Run Code Online (Sandbox Code Playgroud)

这是一个虚拟栅格网格,写入'test.tif'当前工作目录.为简单起见,为了证明问题不是由于特殊的单个栅格,我将相同的输入文件多次传递给gdal_calc,而不是传递许多不同的文件.

library(raster)
writeRaster(raster(matrix(runif(100), 10)), 'test.tif')
Run Code Online (Sandbox Code Playgroud)

该函数适用于23个输入文件:

r <- gdal_min(rep('test.tif', 23), f_out <- tempfile(fileext='.tif'),
              return_raster=TRUE)
plot(r)
Run Code Online (Sandbox Code Playgroud)

......但不是≥24:

r <- gdal_min(rep('test.tif', 24), f_out <- tempfile(fileext='.tif'),
              return_raster=TRUE)
## Calculating minimum and writing to file2310254bcc.tif
## Warning message:
## running command '"python" C:\Python33\Scripts\GDAL_C~1.PY -A test.tif --A_band 1 -B test.tif --B_band 1 -C test.tif --C_band 1 -D test.tif --D_band 1 -E test.tif --E_band 1 -F test.tif --F_band 1 -G test.tif --G_band 1 -H test.tif --H_band 1 -I test.tif --I_band 1 -J test.tif --J_band 1 -K test.tif --K_band 1 -L test.tif --L_band 1 -M test.tif --M_band 1 -N test.tif --N_band 1 -O test.tif --O_band 1 -P test.tif --P_band 1 -Q test.tif --Q_band 1 -R test.tif --R_band 1 -S test.tif --S_band 1 -T test.tif --T_band 1 -U test.tif --U_band 1 -V test.tif --V_band 1 -W test.tif --W_band 1 -X test.tif --X_band 1 --outfile=C:\Users\John\AppData\Local\Temp\RtmpK4heMM\file2310254bcc.tif --calc="amin([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X], axis=0)" --co="COMPRESS=LZW"' had status 1 
Run Code Online (Sandbox Code Playgroud)

直接从终端执行后者时给出的回溯是:

"python" C:\Python33\Scripts\GDAL_C~1.PY -A test.tif --A_band 1 -B test.tif --B_band 1 -C test.tif --C_band 1 -D test.tif --D_band 1 -E test.tif --E_band 1 -F test.tif --F_band 1 -G test.tif --G_band 1 -H test.tif --H_band 1 -I test.tif --I_band 1 -J test.tif --J_band 1 -K test.tif --K_band 1 -L test.tif --L_band 1 -M test.tif --M_band 1 -N test.tif --N_band 1 -O test.tif --O_band 1 -P test.tif --P_band 1 -Q test.tif --Q_band 1 -R test.tif --R_band 1 -S test.tif --S_band 1 -T test.tif --T_band 1 -U test.tif --U_band 1 -V test.tif --V_band 1 -W test.tif --W_band 1 -X test.tif --X_band 1 --outfile=C:\Users\John\AppData\Local\Temp\RtmpK4heMM\file2310254bcc.tif --calc="amin([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X], axis=0)" --co="COMPRESS=LZW"

0.. evaluation of calculation amin([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X], axis=0) failed
Traceback (most recent call last):
  File "c:\Python33\lib\site-packages\numpy\core\fromnumeric.py", line 2208, in amin
    amin = a.min
AttributeError: 'list' object has no attribute 'min'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python33\Scripts\GDAL_C~1.PY", line 329, in <module>
    main()
  File "C:\Python33\Scripts\GDAL_C~1.PY", line 326, in main
    doit(opts, args)
  File "C:\Python33\Scripts\GDAL_C~1.PY", line 275, in doit
    myResult = eval(opts.calc)
  File "<string>", line 1, in <module>
  File "c:\Python33\lib\site-packages\numpy\core\fromnumeric.py", line 2211, in amin
    out=out, keepdims=keepdims)
  File "c:\Python33\lib\site-packages\numpy\core\_methods.py", line 29, in _amin
    return umr_minimum(a, axis, None, out, keepdims)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)

同样,这正如我在预期删除引用时所预期的那样运行X.

我正在使用Python 3.3.5,gdal 1.11.1并且numpy 1.9.1在Win 10 x64上.

为什么会发生这种情况?

Blc*_*ght 2

您遇到的问题是X输入中的变量calc与函数中循环创建的变量发生冲突doit

for X in range(0,nXBlocks):
Run Code Online (Sandbox Code Playgroud)

看来 gdal 开发人员已经修复了这个问题(在尚未发布的代码中)。现在,它evalcalc私有命名空间(字典)中的输入,而不是函数的本地命名空间中的输入,因此X循环中的变量不再与X输入中的值发生冲突。