def labelMontage(imp, lLabels, cols, rows, w0=12, h0=2, font=24, col=Color.WHITE):
  """labelMontage(imp, lLabels, cols, rows, w0=12, h0=2, font=24, col=Color.WHITE)
  Label a montage in the overlay
  Inputs:
  imp     - the ImagePlus of the montage to label
  lLabels - a list of labels to write into the overlay
  cols    - the number of columns in the montage
  rows    - the number of rows in the montage
  w0      - the x offset for the label (defaults to 12 px)
  h0      - the y offset for the label (defaults to  2 px)
  font    - the size of the font (pts, defaults to 24)
  col     - color of text. Default to Color.WHITE
  Returns
  an ImagePlus with a labeled, duplicate of the input image
  """
  print(cols,rows)
  wBase = imp.getWidth()/cols
  hBase = imp.getHeight()/rows
  print(wBase, hBase)
  l = len(lLabels)
  xt = 0
  y = 0
  # make a copy
  res = imp.duplicate()
  # let's create an array of text rois
  ol = Overlay()
  for i in range(l):
    x = (i % cols+1)-1
    if x < xt:
      y += 1
    xt = x
    xL = x * wBase + w0
    yL = y * hBase + h0
    print(xL,yL)
    tr = TextRoi(xL, yL, lLabels[i])
    tr.setColor(col)
    tr.setFont("SanSerif", font, 1) 
    tr.setJustification(TextRoi.CENTER)
    tr.setAntialiased(True)
    ol.add(tr)
  res.show()
  res.setOverlay(ol)
  res.updateAndRepaintWindow()
  return res
def measureFeatureLength(imp, lw = 2, csvPath=None, bAppend=True,
                         offset = -30, digits = 3,
                         font = 18, linCol = Color.YELLOW,
                         labCol = Color.WHITE,
                         bDebug = False):
    """
    measureFeatureLength(imp, lw = 2, csvPath=None, bAppend=True,
                         offset = -30, digits = 3,
                         font = 18, linCol = Color.YELLOW,
                         labCol = Color.WHITE,
                         bDebug = False)

    Manually measure the length of a feature in a calibrated ImagePlus
    and write the results to the overlay.

    Version of 2016-08-04

    Parameters
    ----------

    imp: ImagePlus
        The image to process
    lw: int (2)
        The linewidth for the line
    csvPath: string (None)
        The path to a csv file to write measurements
    bAppend: Boolean (True)
        A flag. If True new results are appended to the file 
    offset: int (-30)
        The Y offset for the label. If negative, the label will
        be written above the measurement, if positive below.
    digits: int (3)
        Round the output (in calibrated units) to this number of decimal
        points.
    font: int (18)
        The font size for the measurement.
    linCol: A color constant (Color.YELLOW)
        The color for the line in the overlay.
    labCol: A color constant (Color.WHITE)
        The color for the label
    bDebug: A Boolean (False)
        A flag to print diagnostic incormation

    Returns
    -------
    None - it does draw in the overlay of the image and write an
           optional .csv file.

    Known Issues
    ------------
    With large line widths the length of the drawn line appears lw 
    pixels too long.
    """

    # First define some convenience functions
    def resetLastMeasureCount():
        Prefs.set("JRM.meas.counter", 0)

    def GetLastMeasureCount():
        myCount = Prefs.get("JRM.meas.counter", int(-1))
        if myCount < 0:
            # it was not set, so set it to zero
            resetLastMeasureCount()
            return 0
        else:
            myCount = int(myCount)
            return myCount

    def setLastMeasureCount(count):
        count = int(count)
        Prefs.set("JRM.meas.counter", count)


    imp = IJ.getImage()
    if imp == None:
        print("You need an image...")
        return
    else:
        roi = imp.getRoi()
        if roi != None:
            if roi.getType() == Roi.LINE:
                # print(roi)
                cal = imp.getCalibration()
                # print(cal)
                unit = cal.getUnits()
                width = cal.pixelWidth
                height = cal.pixelHeight
                x1 = roi.x1 * width
                y1 = roi.y1 * height
                x2 = roi.x2 * width
                y2 = roi.y2 * height
                length = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
                if bDebug:
                    sOut = "X1: %d Y1 %d X2 %d Y2 %d" % (roi.x1, roi.y1,
                                                         roi.x2, roi.y2)
                    print(sOut)
                    print(length, unit)
                    
                ip = imp.getProcessor()
                ip.setColor(linCol)
                oldLW = ip.getLineWidth()
                ip.setLineWidth(lw)
                ip.drawLine(roi.x1, roi.y1, roi.x2, roi.y2)
                ip.setLineWidth(oldLW)
                imp.updateAndDraw()
                ol = imp.getOverlay()
                if ol == None:
                    ol = Overlay()
                res = imp.duplicate()
                # first a dummy text ROI to set the font
                tr = TextRoi(10, 10, "Foo")
                tr.setColor(labCol)
                tr.setFont("SanSerif", font, 1) 
                tr.setJustification(TextRoi.CENTER)
                tr.setAntialiased(True)
                # explicitly save preferences
                Prefs.savePreferences()
                xL = roi.x1 + roi.x2
                xL /= 2
                if offset < 0:
                    yL = min(roi.y1, roi.y2)
                    yL += offset
                else:
                    yL = max(roi.y1, roi.y2)
                    yL += offset
                length = round(length, 3)
                label = "%g %s" % (length, unit)
                tr = TextRoi(xL, yL, label)
                tr.setColor(labCol)
                tr.setFont("SanSerif", font, 1) 
                tr.setJustification(TextRoi.CENTER)
                tr.setAntialiased(True)
                ol.add(tr)
                imp.setOverlay(ol)
                imp.show()
                if csvPath != None:
                    if bAppend:
                        if os.path.isfile(csvPath):
                            theCount = GetLastMeasureCount() + 1
                            f=open(csvPath, 'a')
                        else:
                            f=open(csvPath, 'w')
                            resetLastMeasureCount()
                            theCount = 1
                            strLine = 'img, num, length (%s)\n' % unit
                            f.write(strLine)
                    else:
                        f=open(csvPath, 'w')
                        resetLastMeasureCount()
                        theCount = 1
                        strLine = 'img, num, length (%s)\n' % unit
                        f.write(strLine)
                    strLine = "%s, %d, %.6f\n" % (imp.getShortTitle(), theCount, length)
                    f.write(strLine)
                    f.close()
                    setLastMeasureCount(theCount)
                strMsg = "measured %s count = %d" % (imp.getShortTitle(), theCount)
                print(strMsg)

            else:
                print("You need a line ROI")

            # finally deselect
            IJ.run("Select None")