我在一个文件夹(5M+)中有很多图像文件。这些图像大小不一。我想调整这些图像到128x128的大小。
我在一个循环中使用下面的函数来使用OpenCV调整Python中的大小
def read_image(img_path):
# print(img_path)
img = cv2.imread(img_path)
img = cv2.resize(img, (128, 128))
return img
for file in tqdm(glob.glob('train-images//*.jpg')):
img = read_image(file)
img = cv2.imwrite(file, img)但它需要超过7个小时才能完成。我想知道是否有任何方法来加快这一进程。
我能否实现并行处理来高效地使用dask或其他什么。?如果是的话,怎么可能呢?
发布于 2018-11-04 10:16:08
如果你绝对想用Python来做这件事,那么请不要理会我的答案。如果你对简单而快速地完成工作感兴趣,请读下去.
我建议GNU并行,如果您有很多事情要并行做,而且随着CPU变得“胖”,有更多的核心,而不是更高的时钟速率(GHz),那么就更好了。
最简单的是,您可以在Linux、macOS和Windows中的命令行中使用ImageMagick来调整一组图像的大小:
magick mogrify -resize 128x128\! *.jpg如果您有数百张图像,您最好并行运行它,如下所示:
parallel magick mogrify -resize 128x128\! ::: *.jpg如果您有数以百万计的图像,*.jpg的扩展将使您的shell命令缓冲区溢出,因此您可以使用以下内容在stdin上输入图像名称,而不是将它们作为参数传递:
find -iname \*.jpg -print0 | parallel -0 -X --eta magick mogrify -resize 128x128\!这里有两个“技巧”:
find ... -print0和parallel -0来空终止文件名,这样它们中的空格就没有问题,parallel -X,这意味着,与其为每个映像启动一个全新的mogrify进程,GNU并行计算出了mogrify可以接受多少文件名,并给出了很多批文件。我向你推荐这两种工具。
虽然上述答案的ImageMagick方面在Windows上工作,但我不使用Windows,也不确定是否在那里使用GNU并行。我认为它可能运行在git-bash和/或Cygwin下-你可以尝试问一个单独的问题-他们是免费的!
关于ImageMagick部分,我认为您可以使用以下命令获得文件中所有JPEG文件名的列表:
DIR /S /B *.JPG > filenames.txt然后,您可能可以像这样处理它们(而不是并行的):
magick mogrify -resize 128x128\! @filenames.txt如果您了解如何在Windows上运行GNU并行,您可能可以使用如下所示并行处理它们:
parallel --eta -a filenames.txt magick mogrify -resize 128x128\!发布于 2018-11-04 06:08:49
如果这些图像存储在一个磁性硬盘上,你很可能会发现你受到读/写速度的限制(很多小的读和写在旋转磁盘上是非常慢的)。
否则,您总是可以将问题抛到处理池中,以利用多个核:
from multiprocessing.dummy import Pool
from multiprocessing.sharedctypes import Value
from ctypes import c_int
import time, cv2, os
wdir = r'C:\folder full of large images'
os.chdir(wdir)
def read_imagecv2(img_path, counter):
# print(img_path)
img = cv2.imread(img_path)
img = cv2.resize(img, (128, 128))
cv2.imwrite('resized_'+img_path, img) #write the image in the child process (I didn't want to overwrite my images)
with counter.get_lock(): #processing pools give no way to check up on progress, so we make our own
counter.value += 1
if __name__ == '__main__':
# start 4 worker processes
with Pool(processes=4) as pool: #this should be the same as your processor cores (or less)
counter = Value(c_int, 0) #using sharedctypes with mp.dummy isn't needed anymore, but we already wrote the code once...
chunksize = 4 #making this larger might improve speed (less important the longer a single function call takes)
result = pool.starmap_async(read_imagecv2, #function to send to the worker pool
((file, counter) for file in os.listdir(os.getcwd()) if file.endswith('.jpg')), #generator to fill in function args
chunksize) #how many jobs to submit to each worker at once
while not result.ready(): #print out progress to indicate program is still working.
#with counter.get_lock(): #you could lock here but you're not modifying the value, so nothing bad will happen if a write occurs simultaneously
#just don't `time.sleep()` while you're holding the lock
print("\rcompleted {} images ".format(counter.value), end='')
time.sleep(.5)
print('\nCompleted all images')由于多少为人所知问题,cv2不能很好地处理多进程,所以我们可以使用线程代替进程,将multiprocessing.Pool替换为multiprocessing.dummy.Pool。无论如何,许多openCV函数都会释放GIL,所以我们仍然应该看到一次使用多个核的计算好处。此外,这还减少了一些开销,因为线程没有进程那么重。经过一些调查后,我还没有找到一个图像库,它可以很好地处理进程。当尝试选择要发送到子进程的函数(如何将工作项发送到子进程以进行计算)时,它们似乎都失败了。
https://stackoverflow.com/questions/53138062
复制相似问题