transform op• 数据种类:image2d → image2d
• 调用:import photoncount; photoncount.anscombe_transform(image, gain=1.0, read_sigma=0.0, offset=0.0, clip=False)(或 opsphoton.get("anscombe_transform"))
Anscombe 方差稳定化变换:泊松计数 -> 方差约为 1。
> 以下的详细说明为原文 —— 摘要与标题已翻译。
Photon-limited data has signal-dependent noise, which every classical
denoiser (Gaussian, bilateral, NLM, wavelet, BM3D) assumes away. The Anscombe
transform `A(x) = 2*sqrt(x + 3/8)` makes the variance approximately 1
*independently of the signal*, so the standard route is transform -> denoise
with a unit-sigma Gaussian denoiser -> :func:anscombe_inverse.
The generalised form (Starck/Murtagh/Bijaoui) also absorbs the sensor's
analogue chain, and takes exactly the parameters
:func:backends_aug.aug_read_noise injects::
A(x) = (2/g) * sqrt(g*(x - offset) + (3/8)*g^2 + sigma_r^2)
with *gain* `g` in ADU per photon, *read_sigma* the Gaussian read noise in
ADU and *offset* the black level in ADU. The defaults ``g=1, sigma_r=0,
offset=0`` reduce it to the classical form exactly.
Measured stabilisation — `var(A(X)) for X ~ Poisson(lambda)`, computed
exactly by summing the Poisson pmf (no sampling, so anyone can reproduce
these; `tests/test_photoncount.py` pins them and the sampled versions):
======== ========
lambda var(A)
======== ========
1 0.717443
2 0.924297
4 0.998754
10 1.000910
100 1.000006
======== ========
So "variance 1" is true from about 4 photons/pixel upward and **false below
it** — at 1 photon/pixel the variance is 0.717, a 28% shortfall, which is
the honest statement of the transform's low-count limit. Below a few photons
an exact Poisson method (or the exact unbiased inverse, see
:func:anscombe_inverse) is required.
It does not help a linear smoother, and the tests say so. Measured on a
two-level scene (4 and 64 photons/pixel, seed 5): a plain Gaussian filter
applied to the raw counts reaches RMSE 2.387, and the same filter through
the Anscombe route reaches 2.459 — i.e. *slightly worse*. That is expected:
averaging is already the right thing to do to Poisson counts, so stabilising
the variance first buys nothing. The transform pays off for denoisers whose
parameter is an absolute noise scale — thresholds, sigma filters,
wavelet shrinkage, NLM, BM3D — because that parameter becomes one constant
instead of a per-pixel function. Measured with a 5x5 sigma filter at a
3-sigma threshold on that same scene: 1.191 through the transform against
2.307 in the raw domain using the same 3-sigma rule with a globally
estimated sigma. (An *oracle* raw threshold, swept against ground truth one
does not have in practice, reaches 1.080 — so the honest headline is
"one principled constant instead of a tuned guess", not "always better".)
Returns a float64 array of the same shape as *image*.
Raises `ValueError`: non-finite *image*, non-positive *gain*, negative
*read_sigma*, and — unless `clip=True` — any pixel whose argument under the
square root is negative (which can happen for real read-noise data dipping
below the black level). `clip=True` floors the argument at 0 and is the
documented, opt-in behaviour; the default refuses rather than quietly
manufacturing a value.
• 示例数据目录(下载 URL / 许可证) —— 2-D 用 skimage.data(BSD/公有领域)加合成图,3-D 给出真实数据源(Stanford/PDS 等)的下载 URL。
• 算子来历与参考文献 —— 该算子族所依据的研究/方法出处。
• 算法的正典(作者・年份)与用途见上面的族使用指南。
• photon_timeresolved — py -3.11 examples/photon_timeresolved.py
image2d 作为输入)photon_sample · photon_statistics · photon_uncertainty · anscombe_inverse
transform)*Provenance: photoncount.py — PHOTON 算子登记表。本条目由 tools/opdocs.py md 自动生成(请勿手工编辑)。*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.