docstr: Finds the Costes Automatic Threshold for colocalization using a bisection algorithm.
  Candidate thresholds are selected from within a window of possible intensities,
  this window is narrowed based on the R value of each tested candidate.
  We're looking for the first point below 0, and R value can become highly variable
  at lower thresholds in some samples. Therefore the candidate tested in each
  loop is 1/6th of the window size below the maximum value (as opposed to the midpoint).
docstr_tok: ["Finds","the","Costes","Automatic","Threshold","for","colocalization","using","a","bisection","algorithm",".","Candidate","thresholds","are","selected","from","within","a","window","of","possible","intensities",",","this","window","is","narrowed","based","on","the","R","value","of","each","tested","candidate",".","We","'re","looking","for","the","first","point","below","0",",","and","R","value","can","become","highly","variable","at","lower","thresholds","in","some","samples",".","Therefore","the","candidate","tested","in","each","loop","is","1\/6th","of","the","window","size","below","the","maximum","value","(","as","opposed","to","the","midpoint",")","."]
code: def bisection_costes(self, fi, si, scale_max=255):
      """
      Finds the Costes Automatic Threshold for colocalization using a bisection algorithm.
      Candidate thresholds are selected from within a window of possible intensities,
      this window is narrowed based on the R value of each tested candidate.
      We're looking for the first point below 0, and R value can become highly variable
      at lower thresholds in some samples. Therefore the candidate tested in each
      loop is 1/6th of the window size below the maximum value (as opposed to the midpoint).
      """
  
      non_zero = (fi > 0) | (si > 0)
      xvar = numpy.var(fi[non_zero], axis=0, ddof=1)
      yvar = numpy.var(si[non_zero], axis=0, ddof=1)
  
      xmean = numpy.mean(fi[non_zero], axis=0)
      ymean = numpy.mean(si[non_zero], axis=0)
  
      z = fi[non_zero] + si[non_zero]
      zvar = numpy.var(z, axis=0, ddof=1)
  
      covar = 0.5 * (zvar - (xvar + yvar))
  
      denom = 2 * covar
      num = (yvar - xvar) + numpy.sqrt(
          (yvar - xvar) * (yvar - xvar) + 4 * (covar * covar)
      )
      a = num / denom
      b = ymean - a * xmean
  
      # Initialise variables
      left = 1
      right = scale_max
      mid = ((right - left) // (6 / 5)) + left
      lastmid = 0
      # Marks the value with the last positive R value.
      valid = 1
  
      while lastmid != mid:
          thr_fi_c = mid / scale_max
          thr_si_c = (a * thr_fi_c) + b
          combt = (fi < thr_fi_c) | (si < thr_si_c)
          if numpy.count_nonzero(combt) <= 2:
              # Can't run pearson with only 2 values.
              left = mid - 1
          else:
              try:
                  costReg, _ = scipy.stats.pearsonr(
                      fi[combt], si[combt]
                  )
                  if costReg < 0:
                      left = mid - 1
                  elif costReg >= 0:
                      right = mid + 1
                      valid = mid
              except ValueError:
                  # Catch misc Pearson errors with low sample numbers
                  left = mid - 1
          lastmid = mid
          if right - left > 6:
              mid = ((right - left) // (6 / 5)) + left
          else:
              mid = ((right - left) // 2) + left
  
      thr_fi_c = (valid - 1) / scale_max
      thr_si_c = (a * thr_fi_c) + b
  
      return thr_fi_c, thr_si_c
  
imports: import numpy
  import scipy.ndimage
  import scipy.stats
  from cellprofiler_core.constants.measurement import COLTYPE_FLOAT
  from cellprofiler_core.module import Module
  from cellprofiler_core.setting import Divider, Binary, ValidationError
  from cellprofiler_core.setting.choice import Choice
  from cellprofiler_core.setting.subscriber import LabelListSubscriber, ImageListSubscriber
  from cellprofiler_core.setting.text import Float
  from cellprofiler_core.utilities.core.object import size_similarly
  from centrosome.cpmorphology import fixup_scipy_ndimage_result
  from scipy.linalg import lstsq
label_desc: Use image node_id 13 for calling the MeasureColocalization obj's underlying member method code with example usage: obj.bisection_costes(fi, si, scale_max) and returns: thr_fi_c,  thr_si_c