[docs]classContrast(OptionListMixin):"""Contrast calculation technique. See :ref:`visibility`"""MICHELSON="Michelson"#:WEBER="Weber"#:RATIO="Ratio"#:RMS="Root Mean Square"#:DIFFERENCE="Difference"#:
[docs]defvisibility(array:np.ndarray,radius:float,std:float,algorithm:str)->float:"""The visual perception of CNR. Uses the model from A Rose: https://www.osapublishing.org/josa/abstract.cfm?uri=josa-38-2-196. See also here: https://howradiologyworks.com/x-ray-cnr/. Finally, a review paper here: http://xrm.phys.northwestern.edu/research/pdf_papers/1999/burgess_josaa_1999.pdf Importantly, the Rose model is not applicable for high-contrast use cases. This uses the ``contrast`` function under the hood. Consult before using. Parameters ---------- array The numpy array of the contrast ROI or a 2-element array containing the individual inputs. See ``contrast`` for more. radius The radius of the contrast ROI std Standard deviation of the array. This can sometimes be obtained from another ROI, so it is a separate parameter. algorithm The contrast method. See :class:`~pylinac.core.contrast.Contrast` for options. """c=contrast(array,algorithm)returnc*np.sqrt(radius**2*np.pi)/std
[docs]defcontrast(array:np.ndarray,algorithm:str)->float:"""Generic contrast function. Different algorithms have different inputs, so caution is advised. When possible, the exact contrast function is preferred. For Michelson and RMS algorithms, the input array can be any ordinary numpy array. For Weber and Ratio algorithms, the array is assumed to be a 2-element array. Parameters ---------- array The numpy array of the ROI or 2-element input array. This is used in combination with the method. algorithm The contrast method. See :class:`~pylinac.core.contrast.Contrast` for options. """algorithm=algorithm.lower()ifalgorithm==Contrast.MICHELSON.lower():returnmichelson(array)elifalgorithm==Contrast.WEBER.lower():ifarray.size!=2:raiseValueError("For Weber algorithm, the array must be exactly 2 elements. Consult the ``weber`` function for parameter details")returnweber(array[0],array[1])elifalgorithm==Contrast.RMS.lower():returnrms(array)elifalgorithm==Contrast.RATIO.lower():ifarray.size!=2:raiseValueError("For Ratio algorithm, the array must be exactly 2 elements. Consult the ``ratio`` function for parameter details")returnratio(array[0],array[1])elifalgorithm==Contrast.DIFFERENCE.lower():ifarray.size!=2:raiseValueError("For Difference algorithm, the array must be exactly 2 elements. Consult the ``difference`` function for parameter details")returndifference(array[0],array[1])else:raiseValueError(f"Contrast input of {algorithm} did not match any valid options: {Contrast.__dict__.values()}")
[docs]defrms(array:np.ndarray)->float:"""The root-mean-square contrast. Requires values be within 0 and 1."""ifarray.min()<0orarray.max()>1:raiseValueError("RMS calculations require the input array to be normalized. I.e. only values between 0 and 1.")returnnp.sqrt(np.mean((array-array.mean())**2))
[docs]defdifference(feature:float,background:float)->float:"""The simple absolute difference between the feature ROI and background ROI. This can be useful if the default CNR formula is desired (since pylinac CNR is based on the contrast algorithm chosen. .. seealso:: https://en.wikipedia.org/wiki/Contrast-to-noise_ratio """returnabs(feature-background)
[docs]defmichelson(array:np.ndarray)->float:"""The Michelson contrast. Used for sinusoidal patterns. Ranges from 0 to 1. .. seealso:: https://en.wikipedia.org/wiki/Contrast_(vision)#Michelson_contrast """l_max,l_min=np.nanmax(array),np.nanmin(array)return(l_max-l_min)/(l_max+l_min)
[docs]defweber(feature:float,background:float)->float:"""The Weber contrast. Used for patterns with a small feature within a large background. Ranges from 0 to infinity. For backwards compatibility with previous versions, the absolute difference is used, making the range 0 to infinity vs -1 to infinity. .. seealso:: https://en.wikipedia.org/wiki/Contrast_(vision)#Weber_contrast .. danger:: The default definition does not use the absolute value. We only use it here for backwards compatibility. """returnabs(feature-background)/background
[docs]defratio(feature:float,reference:float)->float:"""The ratio of luminescence"""returnfeature/reference