Program: 22714
Project: 22714
Buggy source:
/** 
 * Calculate the Rand index between to 3D clusters, as described by William M. Rand \cite{Rand71}, but pruning out the zero component of the ground truth, which leads to an asymmetric index. The input images  must be 16-bit. BibTeX: <pre> &#64;article{Rand71, author    = {William M. Rand}, title     = {Objective criteria for the evaluation of clustering methods}, journal   = {Journal of the American Statistical Association}, year      = {1971}, volume    = {66}, number    = {336}, pages     = {846--850}, doi       = {10.2307/2284239) } </pre>
 * @param originalLabels ground truth, 3D segmented image (objects are labeled with different numbers) 
 * @param proposedLabels prediction, 3D segmented image (objects are labeled with different numbers)
 * @return adapted Rand index value and prediction statistics
 */
public static ClassificationStatistics adaptedRandIndexStats3D(ImagePlus originalLabels,ImagePlus proposedLabels){
  if (originalLabels.getImageStack().getProcessor(1) instanceof ShortProcessor == false || proposedLabels.getImageStack().getProcessor(1) instanceof ShortProcessor == false)   return null;
  IJ.log("String_Node_Str");
  int nSlices=originalLabels.getImageStackSize();
  int maxIDGroundTruth=0;
  int maxIDProposal=0;
  for (int slice=1; slice <= nSlices; slice++) {
    ImageProcessor gt=originalLabels.getImageStack().getProcessor(slice);
    gt.resetMinAndMax();
    if (maxIDGroundTruth < gt.getMax())     maxIDGroundTruth=(int)gt.getMax();
    ImageProcessor proposal=proposedLabels.getImageStack().getProcessor(slice);
    proposal.resetMinAndMax();
    if (maxIDProposal < proposal.getMax())     maxIDProposal=(int)proposal.getMax();
  }
  double nPairsStack=0;
  double agreements=0;
  double tp=0;
  double fp=0;
  double tn=0;
  double fn=0;
  for (int slice=1; slice <= nSlices; slice++) {
    IJ.log("String_Node_Str" + slice + "String_Node_Str");
    ShortProcessor cluster1=(ShortProcessor)originalLabels.getImageStack().getProcessor(slice);
    ShortProcessor cluster2=(ShortProcessor)proposedLabels.getImageStack().getProcessor(slice);
    final short[] pixels1=(short[])cluster1.getPixels();
    final short[] pixels2=(short[])cluster2.getPixels();
    double nPixels=pixels1.length;
    double n=0;
    int[][] cont=new int[maxIDGroundTruth + 1][maxIDProposal + 1];
    for (int i=0; i < nPixels; i++) {
      cont[pixels1[i]][pixels2[i]]++;
      if (pixels1[i] > 0)       n++;
    }
    double[] ni=new double[cont.length];
    for (int i=1; i < cont.length; i++)     for (int j=0; j < cont[0].length; j++) {
      ni[i]+=cont[i][j];
    }
    double[] nj=new double[cont[0].length];
    for (int j=1; j < cont[0].length; j++)     for (int i=1; i < cont.length; i++) {
      nj[j]+=cont[i][j];
    }
    double truePositives=0;
    for (int j=1; j < cont[0].length; j++)     for (int i=1; i < cont.length; i++)     truePositives+=cont[i][j] * (cont[i][j] - 1.0) / 2.0;
    double nPairsTotal=n * (n - 1.0) / 2.0;
    double nPosTrue=0;
    for (int k=0; k < ni.length; k++)     nPosTrue+=ni[k] * (ni[k] - 1.0) / 2.0;
    double nPosActual=0;
    for (int k=0; k < nj.length; k++)     nPosActual+=nj[k] * (nj[k] - 1.0) / 2.0;
    double trueNegatives=nPairsTotal + truePositives - nPosTrue - nPosActual;
    IJ.log("String_Node_Str" + (truePositives + trueNegatives));
    agreements+=truePositives + trueNegatives;
    nPairsStack+=nPairsTotal;
    double falsePositives=nPosActual - truePositives;
    double nNegActual=nPairsTotal - nPosActual;
    double falseNegatives=nNegActual - trueNegatives;
    tp+=truePositives;
    tn+=trueNegatives;
    fp+=falsePositives;
    fn+=falseNegatives;
  }
  double randIndex=agreements / nPairsStack;
  return new ClassificationStatistics(tp,tn,fp,fn,randIndex);
}

Fixed version (ground truth):
/** 
 * Calculate the Rand index between to 3D clusters, as described by William M. Rand \cite{Rand71}, but pruning out the zero component of the ground truth, which leads to an asymmetric index. The input images  must be 16-bit. BibTeX: <pre> &#64;article{Rand71, author    = {William M. Rand}, title     = {Objective criteria for the evaluation of clustering methods}, journal   = {Journal of the American Statistical Association}, year      = {1971}, volume    = {66}, number    = {336}, pages     = {846--850}, doi       = {10.2307/2284239) } </pre>
 * @param originalLabels ground truth, 3D segmented image (objects are labeled with different numbers) 
 * @param proposedLabels prediction, 3D segmented image (objects are labeled with different numbers)
 * @return adapted Rand index value and prediction statistics
 */
public static ClassificationStatistics adaptedRandIndexStats3D(ImagePlus originalLabels,ImagePlus proposedLabels){
  if (originalLabels.getImageStack().getProcessor(1) instanceof ShortProcessor == false || proposedLabels.getImageStack().getProcessor(1) instanceof ShortProcessor == false)   return null;
  IJ.log("String_Node_Str");
  int nSlices=originalLabels.getImageStackSize();
  int maxIDGroundTruth=0;
  int maxIDProposal=0;
  for (int slice=1; slice <= nSlices; slice++) {
    ImageProcessor gt=originalLabels.getImageStack().getProcessor(slice);
    gt.resetMinAndMax();
    if (maxIDGroundTruth < gt.getMax())     maxIDGroundTruth=(int)gt.getMax();
    ImageProcessor proposal=proposedLabels.getImageStack().getProcessor(slice);
    proposal.resetMinAndMax();
    if (maxIDProposal < proposal.getMax())     maxIDProposal=(int)proposal.getMax();
  }
  double nPairsStack=0;
  double agreements=0;
  double tp=0;
  double fp=0;
  double tn=0;
  double fn=0;
  for (int slice=1; slice <= nSlices; slice++) {
    ShortProcessor cluster1=(ShortProcessor)originalLabels.getImageStack().getProcessor(slice);
    ShortProcessor cluster2=(ShortProcessor)proposedLabels.getImageStack().getProcessor(slice);
    final short[] pixels1=(short[])cluster1.getPixels();
    final short[] pixels2=(short[])cluster2.getPixels();
    double nPixels=pixels1.length;
    double n=0;
    int[][] cont=new int[maxIDGroundTruth + 1][maxIDProposal + 1];
    for (int i=0; i < nPixels; i++) {
      cont[pixels1[i]][pixels2[i]]++;
      if (pixels1[i] > 0)       n++;
    }
    double[] ni=new double[cont.length];
    for (int i=1; i < cont.length; i++)     for (int j=0; j < cont[0].length; j++) {
      ni[i]+=cont[i][j];
    }
    double[] nj=new double[cont[0].length];
    for (int j=1; j < cont[0].length; j++)     for (int i=1; i < cont.length; i++) {
      nj[j]+=cont[i][j];
    }
    double truePositives=0;
    for (int j=1; j < cont[0].length; j++)     for (int i=1; i < cont.length; i++)     truePositives+=cont[i][j] * (cont[i][j] - 1.0) / 2.0;
    double nPairsTotal=n * (n - 1.0) / 2.0;
    double nPosTrue=0;
    for (int k=0; k < ni.length; k++)     nPosTrue+=ni[k] * (ni[k] - 1.0) / 2.0;
    double nPosActual=0;
    for (int k=0; k < nj.length; k++)     nPosActual+=nj[k] * (nj[k] - 1.0) / 2.0;
    double trueNegatives=nPairsTotal + truePositives - nPosTrue - nPosActual;
    agreements+=truePositives + trueNegatives;
    nPairsStack+=nPairsTotal;
    double falsePositives=nPosActual - truePositives;
    double nNegActual=nPairsTotal - nPosActual;
    double falseNegatives=nNegActual - trueNegatives;
    tp+=truePositives;
    tn+=trueNegatives;
    fp+=falsePositives;
    fn+=falseNegatives;
  }
  double randIndex=agreements / nPairsStack;
  return new ClassificationStatistics(tp,tn,fp,fn,randIndex);
}