High quality image resizing: ImageMagick vs libplacebo
This is an operation I've spent a lot of CPU heat on during the last decade, mainly to convert mangas for use with my e-reader (rotate, scale, posterize and dither), album cover art for DAPs and finally this website's images. And I've always used ImageMagick to do it.
The reasons is simple: if you wanted high quality image resampling as informed by the work of Nicolas Robidoux which was then followed by mpv's autistic weeb devs (in short: downscaling in linear light and upscaling in a sigmoidized color space using balanced EWA kernels), you only had ImageMagick to get you there.
But after suffering many of its bugs, I've had the misfortune of gazing into its C code which gazed back hard enough to frighten me: this was one of the first programs I decided to always sandbox alongside FFmpeg and mupdf.
The latest straws that broke the camel's back: lossless AVIF not really lossless and finally accepting literal paths after a few decades of pain. Thank you for your long years of unpaid services, but so long.
So what were the alternatives I considered? pyvips required too much elbow grease for my taste (well, work in progress) and Python's startup time matters here. Same with Vapoursynth I already used to get access to various filters like NNEDI3 and BM3D. zimg through FFmpeg's zscale filter was attractive, but I've yet to find how to apply the desired sigmoidization…
But then something happened this year: I upgraded from my feeble RX 580 (4GB) to a 9070 XT which unlocked realistic OpenCL/Vulkan compute (and ROCm once it gets its shit together, though NCNN is already there). Which is why mpv's Vulkan image processing library - libplacebo - suddenly made a lot of sense!
After an evening of experimentation to ensure I got the same output as ImageMagick, I decided to properly benchmark the speed difference; using only one thread (aimed at batch processing) and also including lavapipe in the comparison, for GPU-less environments and Science™. Here's the bench script and results I got with a Blu-Ray screenshot:
┌──────────────────────────────────────────────────────────────────────────────┐ │ Input: PNG 1920x1038 8-bit sRGB 1.96405MiB │ │ Kernel: Linux 6.18.35-gentoo-r1 #1 SMP PREEMPT Fri Jun 12 17:41:27 CEST 2026 │ │ CPU: AMD Ryzen 9 5900X 12-Core Processor │ │ Software versions: │ │ media-video/ffmpeg-8.1.2 │ │ media-libs/libplacebo-7.360.1 │ │ media-gfx/imagemagick-7.1.2.18 │ │ media-libs/mesa-26.0.7 │ │ sys-devel/gcc-15.3.0 │ │ sys-libs/glibc-2.43-r2 │ │ GPU listing: │ │ 0: AMD Radeon RX 9070 XT (RADV GFX1201) (discrete) (0x7550) │ │ 1: llvmpipe (LLVM 22.1.8, 256 bits) (software) (0x0) │ └──────────────────────────────────────────────────────────────────────────────┘ ==== Enlarge to 200% ==== Benchmark 1: ImageMagick Time (mean ± σ): 3.295 s ± 0.026 s [User: 3.134 s, System: 0.160 s] Range (min … max): 3.250 s … 3.334 s 10 runs Benchmark 2: libplacebo RADV Time (mean ± σ): 258.2 ms ± 3.4 ms [User: 192.4 ms, System: 66.6 ms] Range (min … max): 250.8 ms … 265.0 ms 11 runs Benchmark 3: libplacebo lavapipe Time (mean ± σ): 1.924 s ± 0.025 s [User: 1.815 s, System: 0.117 s] Range (min … max): 1.901 s … 1.992 s 10 runs ==== Shrink to 50% ==== Benchmark 1: ImageMagick Time (mean ± σ): 317.5 ms ± 5.1 ms [User: 279.6 ms, System: 37.7 ms] Range (min … max): 312.1 ms … 329.6 ms 10 runs Benchmark 2: libplacebo RADV Time (mean ± σ): 246.2 ms ± 5.7 ms [User: 195.5 ms, System: 49.5 ms] Range (min … max): 237.8 ms … 257.0 ms 12 runs Benchmark 3: libplacebo lavapipe Time (mean ± σ): 476.2 ms ± 11.7 ms [User: 410.8 ms, System: 66.0 ms] Range (min … max): 465.7 ms … 505.7 ms 10 runs
I don't know about you but I was surprised! Didn't expect lavapipe to trounce IM for enlarging nor did I think my Radeon wouldn't even feel the difference between the two operations. In any case, I can safely enjoy my replacement and FFmpeg's much saner CLI (yes, I'm not joking), now. Together with waifu2x-ncnn-vulkan, I'll soon be able to finally use my e-reader conversion script during summer!
PS: I do wonder if 24 parallel resizing jobs on the GPU will scale linearly or not at all…