compression op• 데이터 종류: image2d × image2d → scalar
• 호출: import fullseye as fs; fs.ledger.ncd(a, b, compressor='lzma', levels=None, data_range=None, symmetric=True)(구현을 직접 호출하려면 import imgmetrics; imgmetrics.ncd(a, b, compressor='lzma', levels=None, data_range=None, symmetric=True), 원장에서 가져오려면 opsimgmetrics.get("ncd"))
정규화 압축 거리(Li, Chen, Li, Ma & Vitányi, IEEE TIT 50(12), 2004).
NCD(x,y) = (C(xy) - min(C(x),C(y))) / max(C(x),C(y)). 같은 것이면 0에 가까워지고, 무관하면 1에 가까워진다 -- 단 실제 압축기는이상적인 Kolmogorov 복잡도가 아니므로, 같은 입력이라도 엄밀히 0이 되지는 않는다(헤더만큼의 덧값이 있다). 그 덧값의 실측값은 테스트에 남겨 두었다.
날것의 float 배열은 받지 않는다. 압축기는 바이트열의 반복을 보므로, 값이 아주 조금만 달라도 float의 가수부가 통째로 바뀌어, 비슷한 2장이라도공통의 바이트열이 사라진다. 실측(2026-09-02, linspace의 그라디언트와그것에 +0.02 한 그림, PSNR 34.0 dB = 매우 비슷함):
• float64 그대로: 8바이트 워드의 공유율 0.02 % → NCD 1.0959 ("전혀 무관"으로 읽히는 값. 게다가 1을 넘는다)
• 256 단계로 양자화: NCD 0.1290(올바르게 "매우 비슷함")
• 정말로 무관한 2장: NCD 0.9981
즉 float 그대로 재면 예외 없이 반대의 결론이 나온다. 따라서 float에는 levels의 명시를 요구한다(levels=256이면 data_range를 256 단계로양자화한 뒤 잰다). 정수 dtype은 그대로 잴 수 있다.
symmetric=True(기본값)는 양방향을 재서 평균한다. 압축기는 앞에서부터 차례로사전을 만들므로 C(xy) != C(yx)가 되며, 소박하게 구현하면 "거리"를 자칭하면서인수의 순서로 값이 바뀐다(실측: 세로 줄무늬와 가로 줄무늬에서 0.571429 대 0.595238, 상대 4 %). 균일 난수끼리는 차이 0.000e+00이 되므로, 난수로 시험하는한 알아챌 수 없다 -- 구조가 있는 실데이터에서 비로소 드러나는 유형의 결함.
• image_difference_metrics 패밀리 가이드
• 샘플 데이터 카탈로그(DL URL / 라이선스) —— 2-D 는 skimage.data(BSD/public)+ 합성, 3-D 는 실데이터 소스(Stanford/PDS 등)의 DL URL.
• 연산자의 내력·참고문헌 —— 이 연산자 족의 바탕이 된 연구/기법의 출처.
• 알고리즘의 정전(저자·연도)과 용도는 위의 패밀리 사용 가이드에 적혀 있습니다.
• image_quality_metrics — py -3.11 examples/image_quality_metrics.py
scalar 를 입력으로 받는 것)luma_limited_u8 · rank_data · tid2013_index
compression)*Provenance: imgmetrics.py — IMGMETRICS 연산자 레지스트리. 이 op 노트는 tools/opdocs.py md 가 자동 생성합니다(직접 편집하지 마세요).*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.