【问题标题】:Python PILLOW library uses CPU for Image Processing, can it be done on GPU?Python PILLOW 库使用 CPU 进行图像处理,可以在 GPU 上完成吗?
【发布时间】:2017-01-24 10:20:46
【问题描述】:

我为自己制作了一个小型 Python 3.x 应用程序,该应用程序将文件夹中所有图像的大小调整为某个给定百分比。

该应用支持多核 CPU,因为它将工作拆分到与 CPU 一样多的线程上。

这里的瓶颈是 CPU,因为在运行期间我的 RAM 内存保持 40% 可用,而我的 HDD 使用率为 3%,但所有 CPU 内核都接近 100%。

有没有办法在 GPU 上处理图像?我认为这会大大提高性能,因为 GPU 有超过 4 个内核。

这里有一些关于如何完成处理的代码:

def worker1(file_list, percentage, thread_no):
    """thread class"""
    global counter
    save_dir = askdir_entry.get() + '/ResizeImage/'
    for picture in file_list:
        image = Image.open(picture, mode='r')
        image_copy = image.copy()
        (width, height) = image.size
        filename = os.path.split(picture)[1]
        image_copy.thumbnail((width * (int(percentage) / 100), height * (int(percentage) / 100)))
        info_area.insert('end', '\n' + filename)
        info_area.see(tkinter.END)
        image_copy.save(save_dir + filename)
        counter += 1
        if counter % 3 == 0:
            update_counter(1, thread_no)
    update_counter(0, thread_no)


def resize():
    global start_time
    start_time = timeit.default_timer()
    percentage = percentage_textbox.get()
    if not percentage:
        info_area.insert('end', 'Please write a percentage!')
        return
    askdir_entry.config(state='disabled')
    percentage_textbox.config(state='disabled')
    file_list = glob.glob(askdir_entry.get() + '/*.jp*g')
    info_area.insert('end', 'Found ' + str(len(file_list)) + ' pictures.\n')
    cpu = multiprocessing.cpu_count()
    info_area.insert('end', 'Number of threads: ' + str(cpu))
    info_area.insert('end', '\nResizing pictures..\n\n')
    if not os.path.exists(askdir_entry.get() + '/ResizeImage'):
        os.makedirs(askdir_entry.get() + '/ResizeImage')
    counter_label.config(text='-')
    for i in range(0, cpu):
        file_list_chunk = file_list[int(i * len(file_list) / cpu):int((i + 1) * len(file_list) / cpu)]
        threading.Thread(target=worker1, args=(file_list_chunk, percentage, i + 1)).start()

【问题讨论】:

  • 我原以为从另一个线程调用 tkinter 函数是不行的。我还建议全局解释器锁可能会扼杀您希望从多个线程中获得的任何好处,请使用进程!我不认为 Pillow 支持 gpu 但也许 numpy/scipy 可以work.
  • 嗯,我在使用多线程时确实得到了 50% 的改进,尽管理论上我的 4 核 CPU 应该得到 200% 的改进。然而在单个线程上,只有 1 个 CPU 内核在工作,而现在所有 4 个都接近 100%,这可能表明多线程工作(?)。感谢您的意见。
  • 许多 ImageMagick 命令可以通过 OpenCL 使用 GPU(包括调整大小 --- 请参阅 imagemagick.org/script/opencl.php)或通过 OpenMP 使用多线程 CPU(请参阅 imagemagick.org/script/architecture.php#threads)。 OpenCV(Python 或 C++)也可以使用 GPU。

标签: python image-processing tkinter pillow


【解决方案1】:

图像调整大小实际上并不是很占用 CPU。你会发现你的大部分时间都花在了图像解码和编码库上,而 GPU 帮助不大。

一个简单的事情是尝试将 PIL 换成pillow-simd。它与枕头兼容,但许多内部循环已替换为手写矢量代码。您通常可以期待a 6x to 10x speedup for the image resizing step

libjpeg 支持非常快速的加载收缩。作为图像解码的一部分,它可以进行 x2、x4 或 x8 缩小——您可以轻松地获得 20 倍的大尺寸缩小速度。您需要研究如何在枕头中启用此功能。

您也可以考虑使用其他图像处理库。 libvips 有一个快速且低内存的图像缩小命令行工具vipsthumbnail。结合GNU parallel,您可以轻松获得巨大的加速。

例如,我可以制作一个包含 1000 张大型 JPG 图片的目录:

$ vipsheader ../nina.jpg 
../nina.jpg: 6048x4032 uchar, 3 bands, srgb, jpegload
$ for i in {1..1000}; do cp ../nina.jpg $i.jpg; done

然后像这样用 imagemagick 缩小:

$ time for i in {1..1000}; do convert $i.jpg -resize 128x128 tn_$i.jpg; done
real    6m43.627s
user    31m29.894s
sys 1m51.352s

或者像这样使用 GNU parallelvipsthumbnail

$ time parallel vipsthumbnail -s 128 ::: *.jpg
real    0m11.940s
user    1m15.820s
sys 0m11.916s

大约快 33 倍。

您可以将convertparallel 一起使用,但每个convert 进程需要大约400mb 的内存和6k x 4k JPG 图像,因此很容易填满内存。你可能需要稍微调整一下。 vipsthumbnail 只需要几 mb 的内存,因此您可以一次安全地运行多个实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 2018-05-26
    • 2015-07-16
    • 2023-03-05
    相关资源
    最近更新 更多