Find duplicate and near-duplicate 3D
.cubeLUTs by comparing the transforms they encode, not their filenames or formatting.
LUTSieve is an offline, deterministic command-line tool for colourists, editors, DITs, photographers, and pipeline developers. It validates pure 3D CUBE files, compares LUTs exported at different lattice sizes, inventories a folder into reviewable duplicate groups, and emits stable JSON plus standalone HTML evidence. It never uploads, renames, moves, or deletes source LUTs.
The same look is often exported more than once with a different title, comment, numeric precision, or lattice size. A filename or file hash sees those as different files. LUTSieve samples the transforms on one explicit grid, reports their numeric distance, and groups equivalent pairs while retaining bad-file and incompatible-domain evidence.
This is not a perceptual colour-difference claim. CUBE files do not carry the colour-space contract required for Delta E, so LUTSieve reports raw RGB output differences with the grid and tolerance attached.
Requirements: Python 3.11+ and uv.
git clone https://github.com/KanadeK/lutsieve.git
cd lutsieve
uv sync --extra dev --locked
uv run lutsieve scan examples/library --grid 5 --json report.json --html report.htmlExpected summary:
SCAN 4 valid LUTs | 1 duplicate group | 1 invalid file
Exit code 1 is intentional for this fixture: the report contains a duplicate group and a deliberately broken file. Open report.html locally or inspect report.json; the source fixtures remain unchanged.
uv run lutsieve inspect examples/library/identity-2.cube
uv run lutsieve inspect examples/library/identity-2.cube --jsonReports lattice size, declared domain, output range, out-of-range outputs, and a semantic fingerprint.
uv run lutsieve compare examples/library/identity-2.cube examples/library/identity-3.cube --grid 5 --json
uv run lutsieve compare examples/library/identity-2.cube examples/library/warm-2.cube --grid 5 --tolerance 0.000001 --html comparison.htmlThe first pair is equivalent even though the native grids differ. The second exits 1 and reports maximum/mean absolute difference, RMSE, p95, per-channel maxima, and a stable worst input.
uv run lutsieve scan path/to/luts --recursive --grid 17 --tolerance 0.000001 --json inventory.json --html inventory.htmlDiscovery and report ordering are deterministic. Every compatible pair is compared; incompatible declared domains and invalid files are reported separately. Equivalent edges are combined into connected duplicate groups.
| Code | Meaning |
|---|---|
0 |
Valid inspection, equivalent comparison, or clean inventory. |
1 |
Different comparison, or inventory containing duplicates/invalid files. This is a review result, not a crash. |
2 |
Invalid input, incompatible comparison domains, unreadable input, or unwritable report path. |
- JSON uses schema version
1, stable keys, deterministic ordering, UTF-8, and no timestamps. - HTML is a single UTF-8 file with inline CSS and no JavaScript or external assets.
- Metrics are raw numeric RGB differences on the declared sample grid, not Delta E.
- A sampled match is evidence at that grid and tolerance, not proof of equality at every continuous input.
- Semantic fingerprints include the domain, grid, and quantized sampled outputs; titles, comments, whitespace, and native lattice size do not affect them when the sampled transforms match.
v0.1 accepts UTF-8 pure 3D CUBE files with optional BOM/comments and these directives: TITLE, LUT_3D_SIZE, DOMAIN_MIN, DOMAIN_MAX. It enforces red-fastest row order, size 2..65, finite triples, a valid domain, and exactly size³ rows.
It deliberately rejects 1D LUTs, combined shaper files, unknown directives, duplicate directives, non-finite values, and missing/extra rows with file and line evidence. Output values outside 0..1 are valid and reported.
LUTSieve runs locally with no runtime dependencies or network calls. A scan compares every compatible pair, so comparison work is quadratic in the number of valid LUTs and cubic in --grid. Start with the default grid for an audit; use a larger grid only when the extra sampling cost is justified.
The tool only writes paths explicitly supplied through --json or --html. It never rewrites source LUTs.
uv sync --extra dev --locked
uv run --extra dev --locked python -m pytest -q
uv run --extra dev --locked python -m ruff check .
uv run --extra dev --locked python -m ruff format --check .
uv run --extra dev --locked python -m mypy
uv run --extra dev --locked python scripts/verify.pyThe release gate covers branch coverage (minimum 90%), static checks, dependency audit, wheel/sdist construction, archive inspection, clean-environment wheel installation, and real inspect/compare/scan exit paths. See Troubleshooting when a command fails.
Adjacent tools apply, generate, or visually preview LUTs. LUTSieve focuses on strict validation plus transform-level collection inventory. The research is bounded evidence, not a claim that no related project exists anywhere.
LUTSieve 是一个完全离线的 3D .cube LUT 审计工具:它比较 LUT 实际编码的数值变换,而不是文件名或文本哈希;能够识别不同网格尺寸但效果相同的 LUT,保留损坏文件和输入域不兼容证据,并输出稳定 JSON 与无脚本 HTML。工具不会上传、移动、重命名或删除原始 LUT。示例验收命令与退出码含义见上方 Quick start 和 Exit codes;常见失败处理见排障文档。
See CONTRIBUTING.md for the test-first workflow. Please report security issues through the private route in SECURITY.md, not a public issue.