我正在使用Numpy执行图像处理,特别是运行标准差拉伸。这读入X列,找到标准差,并执行百分比线性拉伸。然后迭代到下一个列“组”,并执行相同的操作。输入图像是一个1GB,32位,单波段光栅,需要相当长的时间来处理(小时)。下面是代码。
我意识到我有3个嵌套的for循环,这可能是瓶颈出现的地方。如果我在“盒子”中处理图像,也就是说加载一个[500,500]的数组并迭代图像处理时间相当短。不幸的是,相机错误要求我在极长的条带(52,000 x 4)(y,x)中迭代,以避免条带化。
如有任何关于加快这一进程的建议,我们将不胜感激:
def box(dataset, outdataset, sampleSize, n):
quiet = 0
sample = sampleSize
#iterate over all of the bands
for j in xrange(1, dataset.RasterCount + 1): #1 based counter
band = dataset.GetRasterBand(j)
NDV = band.GetNoDataValue()
print "Processing band: " + str(j)
#define the interval at which blocks are created
intervalY = int(band.YSize/1)
intervalX = int(band.XSize/2000) #to be changed to sampleSize when working
#iterate through the rows
scanBlockCounter = 0
for i in xrange(0,band.YSize,intervalY):
#If the next i is going to fail due to the edge of the image/array
if i + (intervalY*2) < band.YSize:
numberRows = intervalY
else:
numberRows = band.YSize - i
for h in xrange(0,band.XSize, intervalX):
if h + (intervalX*2) < band.XSize:
numberColumns = intervalX
else:
numberColumns = band.XSize - h
scanBlock = band.ReadAsArray(h,i,numberColumns, numberRows).astype(numpy.float)
standardDeviation = numpy.std(scanBlock)
mean = numpy.mean(scanBlock)
newMin = mean - (standardDeviation * n)
newMax = mean + (standardDeviation * n)
outputBlock = ((scanBlock - newMin)/(newMax-newMin))*255
outRaster = outdataset.GetRasterBand(j).WriteArray(outputBlock,h,i)#array, xOffset, yOffset
scanBlockCounter = scanBlockCounter + 1
#print str(scanBlockCounter) + ": " + str(scanBlock.shape) + str(h)+ ", " + str(intervalX)
if numberColumns == band.XSize - h:
break
#update progress line
if not quiet:
gdal.TermProgress_nocb( (float(h+1) / band.YSize) )
以下是最新情况:在没有使用profile模块的情况下,因为我不想把代码的一小部分打包成函数,所以我使用了print和exit语句的混合来大致了解哪些行占用了最多的时间,幸运的是(我确实理解我有多幸运)有一行把所有的东西都拖了下来。
outRaster = outdataset.GetRasterBand(j).WriteArray(outputBlock,h,i)#array, xOffset, yOffset
GDAL在打开输出文件和写出数组时效率很低,考虑到这一点,我决定将修改后的数组“outBlock”添加到python列表中,然后写出块,下面是我修改的部分:
outputBlock刚刚被修改...
#Add the array to a list (tuple)
outputArrayList.append(outputBlock)
#Check the interval counter and if it is "time" write out the array
if len(outputArrayList) >= (intervalX * writeSize) or finisher == 1:
#Convert the tuple to a numpy array. Here we horizontally stack the tuple of arrays.
stacked = numpy.hstack(outputArrayList)
#Write out the array
outRaster = outdataset.GetRasterBand(j).WriteArray(stacked,xOffset,i)#array, xOffset, yOffset
xOffset = xOffset + (intervalX*(intervalX * writeSize))
#Cleanup to conserve memory
outputArrayList = list()
stacked = None
finisher=0
Finisher只是一个处理边缘的标志。它花了一些时间来弄清楚如何从列表中构建一个数组。其中,使用numpy.array创建了一个三维数组(有人愿意解释一下为什么吗?)而write array需要一个二维数组。总处理时间现在从不到2分钟到5分钟不等。你知道为什么会存在这个时间范围吗?
非常感谢每个发帖的人!下一步是真正进入Numpy,学习矢量化以进行额外的优化。
3条答案
按热度按时间6ie5vjzr1#
加快
numpy
数据操作的一种方法是使用vectorize
。实际上,vectorize接受一个函数f
,并创建一个新函数g
,该函数将f
Map到一个数组a
上。g
的调用如下:g(a)
.在没有可用数据的情况下,我不能肯定这是否有用,但也许你可以将上面的代码重写为一组可以是
vectorized
的函数,也许在这种情况下,你可以将索引数组向量化为ReadAsArray(h,i,numberColumns, numberRows)
,下面是一个潜在好处的例子:15倍的加速!还要注意numpy slicing对
ndarray
s的边缘处理得很好:因此,如果可以将
ReadAsArray
数据放入ndarray
,就不必进行任何边缘检查。关于您关于整形的问题--整形根本不会改变数据,它只是改变了
numpy
索引数据的"步幅",当您调用reshape
方法时,返回的值是数据的新视图;根本不复制或更改数据,也不复制或更改包含旧步幅信息的旧视图。sqougxex2#
已按要求答复。
如果IO受限,则应将读/写分块。尝试将约500 MB的数据转储到一个ndarray,处理所有数据,将其写出,然后获取下一个约500 MB的数据。确保重用ndarray。
wvmv3b1j3#
我不想完全理解你在做什么,但我注意到你没有使用任何numpy slice或数组广播,这两种方法都可以加快代码的速度,或者至少可以使代码更可读。如果这些与你的问题无关,我很抱歉。