Skip to content

Commit 0af9919

Browse files
chore: add benchmark
1 parent df75440 commit 0af9919

29 files changed

+2634
-0
lines changed

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
**/.*
22
test/
33
coverage/
4+
benchmark

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ perception. It is created specially for the needs of visual regression testing
77
for [`testplane`](http://github.com/gemini-testing/testplane) utility, but can be used
88
for other purposes.
99

10+
## Benchmark
11+
12+
Benchmark is presented in the corresponding directory.
13+
14+
- [Benchmark description](./benchmark/README.md)
15+
- [Benchmark results](./benchmark/results.md)
16+
1017
## Supported image formats
1118

1219
JPEG, PNG, WebP, GIF, AVIF, TIFF and SVG images are supported.

benchmark/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# looks-same Benchmark
2+
3+
This benchmark evaluates the performance of four npm packages for image comparison: [`looks-same`](https://github.com/gemini-testing/looks-same), [`pixelmatch`](https://github.com/mapbox/pixelmatch), [`resemblejs`](https://github.com/rsmbl/Resemble.js), and [`blink-diff`](https://github.com/yahoo/blink-diff).
4+
It focuses on execution speed across diverse test cases, including real-world web comparisons and synthetic examples.
5+
6+
---
7+
8+
## Test Cases
9+
10+
### Web-Based Averages
11+
12+
- **Web Avg Diff (672x623)**:
13+
Aggregates **failed web page comparisons** from our production projects using [Testplane](https://testplane.io/) for e2e testing.
14+
Represents 103,142 real-world UI mismatches (e.g., layout shifts, rendering errors).
15+
- **Web Avg Success (656x547)**:
16+
Derived from 6,282,752 successful comparisons in production.
17+
Tests speed for "no difference" scenarios common in regression testing workflows.
18+
19+
### Synthetic Comparisons
20+
21+
- **Equal Images (1000x1000)**: Baseline test with identical images.
22+
- **1% Invisible Diff (1000x1000)**:
23+
Differences are **visually imperceptible** (ΔE < 2.3 in [CIEDE2000](https://en.wikipedia.org/wiki/Color_difference#CIEDE2000)), simulating subtle changes like anti-aliasing variations.
24+
- **1% Visible Diff (1000x1000)**:
25+
Human-noticeable differences (ΔE ≥ 2.3) in RGB values.
26+
- **5% Invisible/Visible Diff (1000x1000)**:
27+
Larger-scale variations with the same perceptual thresholds.
28+
- **Full Max Diff (1000x1000)**:
29+
All pixels altered (maximum difference) to stress-test worst-case performance.
30+
31+
### Realistic Example
32+
33+
- **Demonstrative Example (896×784)**:
34+
Real-world UI comparison with an 8% visible difference: a button intentionally recolored to a human-noticeable shade.
35+
Provides visual intuition for typical failure scenarios.
36+
<details>
37+
<summary>Uses the following images (from ./fixtures)</summary>
38+
39+
<table>
40+
<tr>
41+
<td><img src="./fixtures/reference.png" alt="Image 1" style="width: 100%;"/></td>
42+
<td><img src="./fixtures/actual.png" alt="Image 2" style="width: 100%;"/></td>
43+
</tr>
44+
</table>
45+
</details>
46+
47+
48+
---
49+
50+
## Results
51+
52+
See [**results.md**](./results.md) for execution times across all test cases.
53+
54+
## Running the benchmark
55+
56+
1. Clone the repository:
57+
```bash
58+
git clone [email protected]:gemini-testing/looks-same.git
59+
```
60+
2. Navigate to "benchmark" directory:
61+
```bash
62+
cd looks-same/benchmark
63+
```
64+
3. Install dependencies:
65+
```bash
66+
npm ci
67+
```
68+
4. Run the benchmark:
69+
```bash
70+
npm start
71+
```

benchmark/constants.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
exports.PACKAGES = {
2+
LOOKS_SAME: 'looks-same',
3+
PIXELMATCH: 'pixelmatch',
4+
RESEMBLE_JS: 'resemblejs',
5+
BLINK_DIFF: 'blink-diff'
6+
};
7+
8+
exports.CASES = {
9+
WEB_AVG_DIFF: 'web avg diff (672x623)',
10+
WEB_AVG_SUCCESS: 'web avg success (656x547)',
11+
EQUAL_IMAGES: 'equal images (1000x1000)',
12+
ONE_PERCENT_INVISIBLE_DIFF: '1% invisible diff (1000x1000)',
13+
ONE_PERCENT_VISIBLE_DIFF: '1% visible diff (1000x1000)',
14+
FIVE_PERCENTS_INVISIBLE_DIFF: '5% invisible diff (1000x1000)',
15+
FIVE_PERCENTS_VISIBLE_DIFF: '5% visible diff (1000x1000)',
16+
FULL_MAX_DIFF: 'full max diff (1000x1000)',
17+
DEMONSTRATIVE_EXAMPLE: 'demonstrative example visible 8% diff (896×784)'
18+
};

benchmark/fixtures/actual.png

65.6 KB
Loading

benchmark/fixtures/reference.png

65.6 KB
Loading
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
exports.CHANNELS_COUNT = 3;
2+
exports.JND = 2.3; // CIEDE2000 just noticeable difference
3+
4+
exports.REFERENCE_COLOR = [100, -38, -38]; // CIE-L*ab
5+
exports.CONSTRAST_REFERENCE_COLOR = [0, 128, 128]; // CIE-L*ab
6+
7+
exports.AVERAGE_FAILED_HIST_BUCKETS = [
8+
// in ["a", "b", "c"] tuples, "c" part of the pixels have ciede2000 diff befween "a" (inc.) and "b" (exc.)
9+
[0, 5e-324, 0.9163583710631669],
10+
[5e-324, 0.2, 0.0006867712475951489],
11+
[0.2, 0.5, 0.0021610446606488607],
12+
[0.5, 1, 0.005987159508767972],
13+
[1, 1.6, 0.011063733707154652],
14+
[1.6, 1.73, 0.0015331092837601974],
15+
[1.73, 1.8765, 0.0006625396213279764],
16+
[1.8765, 2, 0.0018387428611124819],
17+
[2, 2.3, 0.0013118358358049037],
18+
[2.3, 2.4, 0.00022329552469749336],
19+
[2.4, 2.5, 0.00036489135695552325],
20+
[2.5, 2.7, 0.008824595373243259],
21+
[2.7, 4, 0.003404259594068377],
22+
[4, 6, 0.0042124825492642895],
23+
[6, 8, 0.0030169690455660605],
24+
[8, 10, 0.0015209692289468576],
25+
[10, 12, 0.001571573898168484],
26+
[12, 14.26, 0.0011032068046126686],
27+
[14.26, 15.5, 0.000604997805480533],
28+
[15.5, 16.7, 0.0006418838778879667],
29+
[16.7, 25, 0.0032761913664942494],
30+
[25, 30, 0.004046992111565813],
31+
[30, 40, 0.008427973959907584],
32+
[40, 50, 0.004921414959461223],
33+
[50, 60, 0.0019655582362449707],
34+
[60, 70, 0.0021172710822109477],
35+
[70, 80, 0.0011398025313718967],
36+
[80, 90, 0.0027750423615150576],
37+
[90, 125, 0.004237320542997875]
38+
].sort((a, b) => b[2] - a[2]);
39+
40+
exports.AVERAGE_SUCCESS_HIST_BUCKETS = [
41+
// in ["a", "b", "c"] tuples, "c" part of the pixels have ciede2000 diff befween "a" (inc.) and "b" (exc.)
42+
[0, 5e-324, 0.9731894137187758],
43+
[5e-324, 0.2, 0.0007293636735490286],
44+
[0.2, 0.5, 0.0022950691047618353],
45+
[0.5, 1, 0.006358473318051954],
46+
[1, 1.6, 0.01174988831881833],
47+
[1.6, 1.73, 0.0016281902060853782],
48+
[1.73, 1.8765, 0.0007036292415788792],
49+
[1.8765, 2, 0.0019527786764358484],
50+
[2, 2.3, 0.0013931937419429665]
51+
].sort((a, b) => b[2] - a[2]);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const {labToRgb} = require('./utils');
2+
const {CONSTRAST_REFERENCE_COLOR} = require('./constants');
3+
const {ImageGenerator} = require('./image-generator');
4+
5+
exports.ContrastToReferenceGenerator = class ContrastToReferenceGenerator extends ImageGenerator {
6+
constructor(width, height) {
7+
const colors = new Array(width * height).fill(labToRgb(CONSTRAST_REFERENCE_COLOR));
8+
9+
super(width, height, colors);
10+
}
11+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const {JND} = require('./constants');
2+
const {HistCieDiffColorsGenerator} = require('./hist-cie-diff-colors-generator');
3+
const {ImageGenerator} = require('./image-generator');
4+
5+
exports.FixedInvisibleDiffAmountGenerator = class FixedInvisibleDiffAmountGenerator extends ImageGenerator {
6+
constructor(width, height, diffPercent) {
7+
const colorsGenerator = new HistCieDiffColorsGenerator([
8+
[0, Number.MIN_VALUE, 1 - diffPercent],
9+
[Number.MIN_VALUE, JND, diffPercent]
10+
]);
11+
const colors = new Array(width * height).fill(null).map(() => colorsGenerator.getRandomRgbColor());
12+
13+
super(width, height, colors);
14+
}
15+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const {JND} = require('./constants');
2+
const {HistCieDiffColorsGenerator} = require('./hist-cie-diff-colors-generator');
3+
const {ImageGenerator} = require('./image-generator');
4+
5+
exports.FixedVisibleDiffAmountGenerator = class FixedVisibleDiffAmountGenerator extends ImageGenerator {
6+
constructor(width, height, diffPercent) {
7+
const colorsGenerator = new HistCieDiffColorsGenerator([
8+
[0, Number.MIN_VALUE, 1 - diffPercent],
9+
[JND, 100, diffPercent]
10+
]);
11+
const colors = new Array(width * height).fill(null).map(() => colorsGenerator.getRandomRgbColor());
12+
13+
super(width, height, colors);
14+
}
15+
};

0 commit comments

Comments
 (0)