########################### Scalefactors and intercepts ########################### SPM Analyze and nifti1 images have *scalefactors*. nifti1 images also have *intercepts*. If ``A`` is an array in memory, and ``S`` is the array that will be written to disk, then:: R = (A - intercept) / scalefactor and ``R == S`` if ``R`` is already the data dtype we need to write. If we load the image from disk, we exactly recover ``S`` (and ``R``). To get something approximating ``A`` (say ``Aprime``) we apply the intercept and scalefactor:: Aprime = (S * scalefactor) + intercept In a perfect world ``A`` would be exactly the same as ``Aprime``. However ``scalefactor`` and ``intercept`` are floating point values. With floating point, if ``r = (a - b) / c; p = (r * c) + b`` it is not necessarily true that ``p == a``. For example: >>> import numpy as np >>> a = 10 >>> b = np.e >>> c = np.pi >>> r = (a - b) / c >>> p = (r * c) + b >>> p == a False So there will be some error in this reconstruction, even when ``R`` is the same type as ``S``. More common is the situation where ``R`` is a different type from ``S``. If ``R`` is of type ``r_dtype``, ``S`` is of type ``s_dtype`` and ``cast_function(R, dtype)`` is some function that casts ``R`` to the desired type ``dtype``, then:: R = (A - intercept) / scalefactor S = cast_function(R, s_dtype) R_prime = cast_function(S, r_dtype) A_prime = (R_prime * scalefactor) + intercept The type of ``R`` will depend on what numpy did for upcasting ``A, intercept, scalefactor``. In order that ``cast_function(S, r_dtype)`` can best reverse ``cast_function(R, s_dtype)``, the second needs to know the type of ``R``, which is not stored. The type of ``R`` depends on the types of ``A`` and of ``intercept, scalefactor``. We don't know the type of ``A`` because it is not stored. ``R`` is likely to be a floating point type because of the application of scalefactor and intercept. If ``(intercept, scalefactor)`` are not the identity (0, 1), then we can ensure that ``R`` is at minimum the type of the ``intercept, scalefactor`` by making these be at least 1D arrays, so that floating point types will upcast in ``R = (A - intercept) / scalefactor``. The cast of ``R`` to ``S`` and back to ``R_prime`` can lose resolution if the types of ``R`` and ``S`` have different resolution. Our job is to select: * scalefactor * intercept * ``cast_function`` such that we minimize some measure of difference between ``A`` and ``A_prime``.