在 GIMP 中使用 python-fu 缩放图像比通过 built-in GUI 更慢

Scaling an image with python-fu in GIMP slower then via built-in GUI

我在 OS X 上使用 GIMP 2.8.14 中的 Python-Fu 来自动化我的游戏资产管道生产。

但我注意到,与 build-in 功能 "Image > Scale Image... ".

相比,当我从我的脚本中执行方法 pdb.gimp_image_scale 时,速度较慢

通过脚本将白色图像从 8000x8000 缩小到 2000x2000 需要 6.8 秒,而通过 GUI 需要 1.7 秒。这并不是那么关键,但通过脚本缩小我的资产需要 3 分 47 秒,而通过 GUI 则需要 40 秒。

我的 Activity Monitor 告诉我,当我执行我的脚本时 CPU 的使用率只达到了大约 30%,而 built-in GUI 缩放使用了 100%,这意味着在 OS X 上,单个 CPU 内核的运行速度尽可能快

有没有人知道我该如何改变这种行为?

奇怪的是:这个接缝只是因为 gimp_image_scale。 gimp_image_select_contiguous_color、gimp_selection_grow、gimp_selection_feather 和 gimp_edit_bucket_fill_full 等其他操作将 CPU 使用率提高到 100%。

在 Windows 上是一样的,但实际上并没有那么糟糕:通过脚本 1 分 28 秒,通过 build-in GUI 33 秒。

from gimpfu import *

def scale_image(scale):
    image = gimp.image_list()[0]
    w = image.width
    h = image.height

    pdb.gimp_progress_init("Scaling Image...",None)
    pdb.gimp_context_set_interpolation(INTERPOLATION_LANCZOS)
    pdb.gimp_image_scale(image, w/scale, h/scale)
pass

register(
         "jeanluc_scale_image",
         "Scale Image",
         "Scale Image",
         "JeanLuc",
         "JeanLuc",
         "2015",
         "Scale Image...",
         "*",
         [
          (PF_INT, "scale", "Scale of Image", 1)
          ],
         [],
         scale_image,
         menu="<Image>/JeanLuc"
)

main()

更新 1: 我发现 Activity Monitor 具有 "CPU History" 功能,我发现我的假设是错误的:100% 不在 1 个核心上,而是 25% 分布在 4 个核心上。

那么,为什么在这两种情况下都只有 运行 达到 25%?为什么 gimp_image_scale 不是多线程的?

通过 GUI 进行多线程缩放(左侧)与通过脚本进行单线程缩放(右侧)

更新 2: 当我 运行 我的脚本来自 "Filters>Python-Fu>Console" 时,它实际上是多线程的并且速度很快。

更新 3: 当我 运行 我的脚本没有输入值(例如比例)并对值进行硬编码时,它 运行 也是多线程的并且速度很快。它接缝当从对话框触发缩放时它是单线程的。

我找到了一个 hacky 解决方法 从新线程执行 gimp_image_scale。 现在只需 24 秒,而不是 3 分 37 秒,因此实际上比内置 GUI 解决方案更快,后者需要 40 秒。

如果有人知道或找到合适的解决方案,我会接受它作为答案。

#!/usr/bin/env python

from threading import Thread
import time
from gimpfu import *

def scale_image(scale):
    pdb.gimp_progress_init("Scaling Image...",None)
    time.sleep(0.5)
    thread = Thread(target = thread_scale_image, args = (scale, ))
    thread.start()
    thread.join()
pass

def thread_scale_image(scale):
    image = gimp.image_list()[0]
    w = image.width
    h = image.height
    pdb.gimp_context_set_interpolation(INTERPOLATION_LANCZOS)
    pdb.gimp_image_scale(image, w/scale, h/scale)
pass

register(
         "jeanluc_scale_image",
         "Scale Image",
         "Scale Image",
         "JeanLuc",
         "JeanLuc",
         "2015",
         "Scale Image...",
         "RGB*",
         [
          (PF_INT, "scale", "Scale of Image", 4)
          ],
         [],
         scale_image,
         menu="<Image>/JeanLuc"
)

main()

作为提示,这不会影响这个问题,但应该可以帮助其他人解决执行多个(数百个)像素级操作的脚本的性能问题,例如画笔描边或创建选择和填充:UNDO 系统拖动一切都结束了,即使正确分组了 UNDO 步骤。

因此,密集脚本的提示是复制 (pdb.gimp_image_duplicate) 图像,调用 pdb.gimp_image_undo_disable在副本上,在那里执行操作,并在完成时,pdb.gimp_edit_copypdb.gimp_edit_paste将相关drawables转移到原始图像。