Skip to Content
New: ssim-native brings SSIM, MS-SSIM and Hitchhiker's to Node, and interpret-native ships diff interpretation on its own. Read more β†’
BenchmarksStructural

Structural Similarity Benchmarks

Per-window image quality comparisons (SSIM family). Image decode is excluded.

Structural summary

Read each section against its own baseline, not against the other one. The two metrics are not given the same amount of work: ssim follows MATLAB’s ssim.m and shrinks the image to ~256px on the short edge before it measures anything, while hitchhikers-ssim always runs at full resolution. On the largest fixture that is 264x573 pixels versus 3.8M.

That is also why the Rust port wins by so much more on one than the other (~15x vs ~4x). Nearly all of Hitchhiker’s time is the single full-resolution pass that builds its lookup tables, not the comparison itself β€” widening the window stride to compare 34x fewer positions moves it only 26.9ms -> 24.8ms. That pass is a running total, so it has to go pixel by pixel in order, whereas the convolutions it replaces vectorise. In JavaScript the trick is a large win because the math it avoids is slow there; in Rust it costs more than it saves.

Fast Original ( @blazediff/ssim using ssim vs ssim.js using fast algorithm) (image IO excluded)

25 iterations (3 warmup)

~31.5% performance improvement on average.

The percentage above is the JavaScript port. @blazediff/ssim-native is the Rust one, wrapping the same algorithm β€” roughly 15x faster again than the JS port, from the same decoded buffers.

Benchmarkssim.jsBlazeDiffBlazeDiff (ssim-native)BlazeDiff SavedBlazeDiff %BlazeDiff (ssim-native) SavedBlazeDiff (ssim-native) %
blazediff/196.08ms66.90ms5.57ms29.18ms30.4%90.50ms94.2%
blazediff/1 (identical)97.84ms65.96ms5.53ms31.89ms32.6%92.32ms94.4%
blazediff/238.90ms23.56ms1.64ms15.34ms39.4%37.25ms95.8%
blazediff/2 (identical)38.33ms24.37ms1.61ms13.96ms36.4%36.72ms95.8%
blazediff/3124.34ms95.98ms5.24ms28.36ms22.8%119.10ms95.8%
blazediff/3 (identical)112.10ms98.15ms5.56ms13.95ms12.4%106.54ms95.0%
blazediff/4283.99ms228.75ms13.88ms55.25ms19.5%270.12ms95.1%
blazediff/4 (identical)261.89ms224.39ms12.56ms37.50ms14.3%249.33ms95.2%
pixelmatch/129.94ms19.88ms1.66ms10.06ms33.6%28.27ms94.5%
pixelmatch/1 (identical)29.22ms19.82ms1.61ms9.40ms32.2%27.61ms94.5%
pixelmatch/215.33ms9.82ms0.79ms5.51ms35.9%14.55ms94.9%
pixelmatch/2 (identical)14.75ms9.93ms0.84ms4.82ms32.7%13.91ms94.3%
pixelmatch/328.52ms23.06ms1.67ms5.46ms19.1%26.85ms94.1%
pixelmatch/3 (identical)29.82ms19.89ms1.65ms9.93ms33.3%28.17ms94.5%
pixelmatch/420.90ms11.85ms0.80ms9.05ms43.3%20.10ms96.2%
pixelmatch/4 (identical)20.70ms12.27ms0.83ms8.43ms40.7%19.88ms96.0%
pixelmatch/514.71ms10.79ms0.79ms3.92ms26.7%13.91ms94.6%
pixelmatch/5 (identical)15.50ms9.82ms0.77ms5.68ms36.6%14.73ms95.1%
pixelmatch/614.86ms9.82ms0.79ms5.04ms33.9%14.07ms94.7%
pixelmatch/6 (identical)14.72ms9.79ms0.77ms4.94ms33.5%13.95ms94.8%
pixelmatch/728.88ms16.56ms1.16ms12.32ms42.7%27.73ms96.0%
pixelmatch/7 (identical)28.21ms16.78ms1.12ms11.42ms40.5%27.09ms96.0%

Hitchhikers SSIM SSIM (@blazediff/ssim using hitchhikers-ssim vs ssim.js using weber algorithm) (image IO excluded)

25 iterations (3 warmup)

~75.1% performance improvement on average.

The percentage above is the JavaScript port. @blazediff/ssim-native is the Rust one, wrapping the same algorithm β€” roughly 4x faster again than the JS port, from the same decoded buffers.

Benchmarkssim.jsBlazeDiffBlazeDiff (ssim-native)BlazeDiff SavedBlazeDiff %BlazeDiff (ssim-native) SavedBlazeDiff (ssim-native) %
blazediff/163.19ms12.58ms2.85ms50.61ms80.1%60.34ms95.5%
blazediff/1 (identical)63.14ms12.59ms2.88ms50.55ms80.1%60.25ms95.4%
blazediff/234.91ms10.22ms2.26ms24.68ms70.7%32.64ms93.5%
blazediff/2 (identical)34.65ms10.02ms2.28ms24.64ms71.1%32.37ms93.4%
blazediff/3134.85ms46.12ms10.96ms88.72ms65.8%123.89ms91.9%
blazediff/3 (identical)141.68ms47.06ms10.97ms94.62ms66.8%130.70ms92.3%
blazediff/4389.62ms108.01ms25.77ms281.60ms72.3%363.85ms93.4%
blazediff/4 (identical)351.85ms108.45ms25.43ms243.40ms69.2%326.42ms92.8%
pixelmatch/119.03ms3.97ms0.84ms15.06ms79.1%18.19ms95.6%
pixelmatch/1 (identical)18.49ms3.93ms0.87ms14.57ms78.8%17.63ms95.3%
pixelmatch/29.33ms1.88ms0.44ms7.45ms79.9%8.90ms95.3%
pixelmatch/2 (identical)9.34ms1.86ms0.40ms7.48ms80.1%8.94ms95.7%
pixelmatch/319.14ms3.77ms0.84ms15.37ms80.3%18.30ms95.6%
pixelmatch/3 (identical)18.42ms3.82ms0.85ms14.60ms79.3%17.58ms95.4%
pixelmatch/418.59ms5.19ms1.20ms13.40ms72.1%17.39ms93.6%
pixelmatch/4 (identical)19.22ms5.21ms1.19ms14.01ms72.9%18.03ms93.8%
pixelmatch/59.51ms1.89ms0.40ms7.62ms80.1%9.10ms95.7%
pixelmatch/5 (identical)9.35ms2.07ms0.44ms7.28ms77.9%8.90ms95.2%
pixelmatch/69.28ms2.05ms0.41ms7.22ms77.9%8.86ms95.6%
pixelmatch/6 (identical)9.44ms1.94ms0.40ms7.49ms79.4%9.04ms95.8%
pixelmatch/724.82ms7.38ms1.72ms17.44ms70.3%23.10ms93.1%
pixelmatch/7 (identical)23.29ms7.25ms1.65ms16.04ms68.9%21.64ms92.9%

Benchmarks run on MacBook Pro M1 Max, Node.js 22

Last updated on