#! /usr/bin/python3 # Last edited on 2019-08-26 02:05:51 by jstolfi import js_sample_IMP # This module defines functions to convert between float-valued samples # and integer-valued samples by simple affine (first-degree) mappings # The precise mapping is defined by a positive integer parameter {maxval} and # a boolean parameter {isMask}. # # In general, {isMask} should be false when all integer sample values, # including 0 and maxval, are quantized measurements, with the same # uncertainty. # # In general, {isMask} should be true when the integer values 0 # and {maxval} encode for the float values 0 # and 1, exclusively, which have special meanings. This is the case, # for example, when the samples are opacity values, where 0 means # fully transparent and {maxval} means fully opaque (or vice versa). # This setting may be approriate also if the samples are probabilities, where # 0 means 'impossible' and 1 means 'certain'; or for sample weights, # where 0 means 'ignore'. def quantize(fval, maxval, isMask): "Converts a float sample {fval} to an integer sample {ival} in {0..maxval}.\n\n" \ " If {fval} is {None} or {math.nan}, the result is {None}. Otherwise," \ " if {fval <= 0.0} the result is 0; if {fval >= 1.0} the result is" \ " {maxval}.\n" \ "\n" \ " Otherwise, if {maxval} is 1, the result is a simple binary" \ " thresholding: namely, 0 if {fval<0.5}, and" \ " 1 if {fval>= 0.5}.\n" \ "\n" \ " Otherwise, the real" \ " number range {(0_1)} is divided into a certain number of equal" \ " intervals,and the result is the index of the interval that" \ " contains {fval}, with ties broken arbitrarily.\n" \ "\n" \ " Specifically, if {isMask} is false, the range {(0_1)} is" \ " split into {maxval+1} intervals, indexed from 0 to {maxval}. If" \ " {isMask} is true, that range is split into" \ " {maxval-1} intervals, indexed from 1 to {maxval-1}." return js_sample_IMP.quantize(fval, maxval, isMask) # ---------------------------------------------------------------------- def floatize(ival, maxval, isMask): "Converts an integer sample {ival} in {0..maxval} to a" \ "\ float value {fval} in {[0_1]}, by an affine function.\n" \ "\n" \ " If {isMask} is false, the range {[0_1]} is " \ " conceptually divided into {maxval+1} equal intervals, and" \ " the result {fval} is the center of the interval" \ " with index {ival} (from 0). That is, {ival} is" \ " mapped to {(ival+0.5)/(maxval+1)} Note that" \ " the input 0 returns {0.5*d} and {maxval}" \ " returns {1.0 - 0.5*d}, where {d = 1/(maxval+1)}.\n" \ "\n" \ " If {isMask} is true, any input {ival <= 0} is mapped" \ " to 0.0, and {ival >= maxval} is mapped" \ " to 1.0. Otherwise, the range {(0_1)} is conceptually divided into" \ " {maxval-1} equal intervals, and the result {fval} is the center of the" \ " interval with index {ival} (counting from 1). That is, the function" \ " returns {(ival-0.5)/(maxval-1)} Note that 1 returns {0.5*d} and" \ " {maxval-1} returns {1 - 0.5*d}, where {d = 1/(maxval-1)}.\n" \ "\n" \ " The parameter {maxval} must be positive. If {ival} is" \ " {None}, the result will be {math.nan}." return js_sample_IMP.floatize(ival, maxval, isMask) # ----------------------------------------------------------------------