【问题标题】:Rotating hundreds of JPEGs in seconds rather than hours在几秒钟而不是几小时内旋转数百个 JPEG
【发布时间】:2012-07-09 14:16:03
【问题描述】:

我们的计算机一次获取数百张图像,我们需要尽可能快地旋转和调整它们的大小。 旋转 90、180 或 270 度。

目前我们正在使用命令行工具GraphicsMagick 来旋转图像。旋转图像 (5760*3840 ~ 22MP) 大约需要 4 到 7 秒。

以下python code 可悲地给了我们相同的结果

import cv
img = cv.LoadImage("image.jpg")
timg = cv.CreateImage((img.height,img.width), img.depth, img.channels) # transposed image

# rotate counter-clockwise
cv.Transpose(img,timg)
cv.Flip(timg,timg,flipMode=0)
cv.SaveImage("rotated_counter_clockwise.jpg", timg)

有没有更快的方法来利用显卡的力量来旋转图像?想到 OpenCL 和 OpenGL,但我们想知道性能提升是否会很明显。

我们使用的硬件相当有限,因为设备应该尽可能小。

该软件是带有官方(闭源)radeon 驱动程序的 debian 6。

【问题讨论】:

  • 在阅读这个问题时,我在想:这个操作的每个部分花费了多少时间? JPEG 编码与实际旋转操作有多少等待?有多少等待来自磁盘 IO?这些问题的答案可能会对您的优化产生影响。
  • 只使用 jpeg tran,作为一个很好的副作用,不会影响质量。
  • 您能否为您粘贴的代码的每一部分(加载后、转置后、翻转后、保存后)提供时间?

标签: opengl graphics opencv opencl image-rotation


【解决方案1】:

您可以执行无损旋转,只修改 EXIF 部分。这将使您的图片旋转得更快。

并查看执行无损 jpeg 修改的 jpegtran 实用程序。 https://linux.die.net/man/1/jpegtran

【讨论】:

  • 更改 Exif 方向标签可能是最快的方法。然而,并非所有的图像查看器都尊重它。 jpegtran 似乎是一个很好的解决方案。它只会部分重新压缩您的图像,这应该仍然很快。
  • 如果图像宽度/高度是 8 的倍数,您可以通过简单地重新排序组件而不重新压缩来旋转 90/180/270 度
  • @MartinBeckett:请注意,大多数 JPEG 图像存储为 8 维的倍数,然后才应用裁剪,因此 jpegtran 应该能够为大多数图像重新排序组件。
【解决方案2】:

irfanview 有一个 jpeg no-recompression 插件,IIRC 可以在不重新压缩的情况下旋转和调整图像大小(以简单的方式),它还可以运行图像目录 - 这应该快得多

GPU 可能无济于事,你几乎可以肯定在 opencv 中 I/O 受限,它并不是真正适合高速文件访问

【讨论】:

  • 在这里你会发现更多的实用程序可以无损地进行旋转,而无需再次解压缩和压缩图像:jpegclub.org/losslessapps.html
  • 对于大量图像,缓冲和/或异步内存传输可以缓解 I/O 瓶颈 - 所以我不会说基于 GPU 的实现没有帮助。
  • @ananthonline - 如果 jpeg 只是旋转 90 的倍数,那么您只需要重新调整每个 8x8 块中的压缩值。 GPU 在那里并没有真正的帮助,并且在随机内存读/写时通常很慢,即使您在卡上有数据也是如此。如果你重新压缩它可能会更快,尽管带有 SSE2 的 DCT 非常快
  • 嗯 - 你必须重新压缩某些块,因为图像大小改变了,不是吗?对于大图像,即使是那些也将受益于 GPU 的大规模并行性。使用 GPU 时,解码 + 有损旋转选项变得可行。
【解决方案3】:

我不是 jpeg 和压缩主题方面的专家,但由于您的问题几乎与 I/O 一样受限(假设您可以在没有繁重的解码/编码相关计算的情况下旋转),您可能不会能够在你拥有的 GPU 上加速它。 (Un)幸运的是,您的参考资料是一个相当慢的 Atom CPU。

我假设 Radeon 有独立的主内存。这意味着数据需要通过 PCI-E 进行通信,与 CPU 执行相比,这是额外的延迟,并且在不隐藏的情况下,您可以确定它是瓶颈。这是您在 GPU 上使用 OpenCV 的代码很慢的最可能原因(除了您执行两个内存绑定操作,转置和翻转,而不是一个)。

关键是通过使用multiple-buffering 尽可能多地隐藏计算的 PCI-E 传输时间。仅当相关卡具有双 DMA 引擎(如 high-end RadeonsNVIDIA Quadro/Tesla cards)时,才能通过利用 PCI-E 的全双工功能将 GPU 与 GPU 之间的传输重叠传输——我高度评价这一点怀疑。

如果您的 GPU 计算时间(GPU 进行旋转所需的时间)低于传输所需的时间,您将无法完全重叠。 HD 4530 有一个相当慢的内存接口,只有12.8 Gb/s 峰值,并且旋转内核应该非常受内存限制。但是,我只能猜测,但我想说的是,如果您达到约 1.5 Gb/s(4x PCI-E AFAIK)的峰值 PCI-E 传输速率,计算内核将比传输快几倍,而您将能够重叠很少。 您可以简单地分别对各个部分进行计时,而无需复杂的异步代码,并且您可以估计获得具有最佳重叠的事物的速度。

您可能需要考虑的一件事是获得不会将 PCI-E 视为瓶颈的硬件,例如:

  • 基于AMD APU 的系统。在这些平台上,您将能够页面锁定内存并直接从 GPU 使用它;
  • 与主机共享主内存的集成 GPU;
  • 快速低功耗 CPU,例如移动式 Intel Ivy Bridge,例如i5-3427U 消耗几乎与 Atom D525 一样少,但支持 AVX,应该快几倍。

【讨论】:

    猜你喜欢
    • 2014-04-12
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-15
    相关资源
    最近更新 更多