Program: 22721
Project: 22721
Buggy source:
/** 
 * Calculate the Rand index stats 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. Note: this method is based on the N^2 normalization. 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 segA ground truth, 3D segmented image (objects are labeled with different numbers) 
 * @param segB prediction, 3D segmented image (objects are labeled with different numbers)
 * @return [ precision, recall, Rand index with n^2 normalization ]
 */
public static double[] adaptedRandIndexStats3DN2(ImagePlus segA,ImagePlus segB){
  if (segA.getImageStack().getProcessor(1) instanceof ShortProcessor == false || segB.getImageStack().getProcessor(1) instanceof ShortProcessor == false)   return null;
  int nSlices=segA.getImageStackSize();
  int nLabelsA=0;
  int nLabelsB=0;
  for (int slice=1; slice <= nSlices; slice++) {
    ImageProcessor gt=segA.getImageStack().getProcessor(slice);
    gt.resetMinAndMax();
    if (nLabelsA < gt.getMax())     nLabelsA=(int)gt.getMax();
    ImageProcessor proposal=segB.getImageStack().getProcessor(slice);
    proposal.resetMinAndMax();
    if (nLabelsB < proposal.getMax())     nLabelsB=(int)proposal.getMax();
  }
  long[][] pij=new long[nLabelsA + 1][nLabelsB + 1];
  double n=segA.getImageStackSize() * segA.getWidth() * segA.getHeight();
  for (int slice=1; slice <= nSlices; slice++) {
    ShortProcessor cluster1=(ShortProcessor)segA.getImageStack().getProcessor(slice);
    ShortProcessor cluster2=(ShortProcessor)segB.getImageStack().getProcessor(slice);
    final short[] pixels1=(short[])cluster1.getPixels();
    final short[] pixels2=(short[])cluster2.getPixels();
    double nPixels=pixels1.length;
    for (int i=0; i < nPixels; i++)     pij[pixels1[i]][pixels2[i]]++;
  }
  double[] ai=new double[pij.length];
  for (int i=1; i < pij.length; i++)   for (int j=0; j < pij[0].length; j++) {
    ai[i]+=pij[i][j];
  }
  double[] bj=new double[pij[0].length];
  for (int j=1; j < pij[0].length; j++)   for (int i=1; i < pij.length; i++) {
    bj[j]+=pij[i][j];
  }
  double[] pi0=new double[pij.length];
  double aux=0;
  for (int i=1; i < pij.length; i++) {
    pi0[i]=pij[i][0];
    aux+=pi0[i];
  }
  double sumA=0;
  for (int i=0; i < ai.length; i++)   sumA+=ai[i] * ai[i];
  double sumB=0;
  for (int j=0; j < bj.length; j++)   sumB+=bj[j] * bj[j];
  sumB+=aux / n;
  double sumAB=0;
  for (int i=1; i < pij.length; i++)   for (int j=1; j < pij[0].length; j++)   sumAB+=pij[i][j] * pij[i][j];
  sumAB+=aux / n;
  return new double[]{sumAB / sumB,sumAB / sumA,1.0 - (sumA + sumB - 2.0 * sumAB) / (n * n)};
}

Fixed version (ground truth):
/** 
 * Calculate the Rand index stats 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. Note: this method is based on the N^2 normalization. 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 segA ground truth, 3D segmented image (objects are labeled with different numbers) 
 * @param segB prediction, 3D segmented image (objects are labeled with different numbers)
 * @return [ precision, recall, Rand index with n^2 normalization ]
 */
public static double[] adaptedRandIndexStats3DN2(ImagePlus segA,ImagePlus segB){
  if (segA.getImageStack().getProcessor(1) instanceof ShortProcessor == false || segB.getImageStack().getProcessor(1) instanceof ShortProcessor == false)   return null;
  int nSlices=segA.getImageStackSize();
  int nLabelsA=0;
  int nLabelsB=0;
  for (int slice=1; slice <= nSlices; slice++) {
    ImageProcessor gt=segA.getImageStack().getProcessor(slice);
    gt.resetMinAndMax();
    if (nLabelsA < gt.getMax())     nLabelsA=(int)gt.getMax();
    ImageProcessor proposal=segB.getImageStack().getProcessor(slice);
    proposal.resetMinAndMax();
    if (nLabelsB < proposal.getMax())     nLabelsB=(int)proposal.getMax();
  }
  long[][] pij=new long[nLabelsA + 1][nLabelsB + 1];
  double n=segA.getImageStackSize() * segA.getWidth() * segA.getHeight();
  for (int slice=1; slice <= nSlices; slice++) {
    ShortProcessor cluster1=(ShortProcessor)segA.getImageStack().getProcessor(slice);
    ShortProcessor cluster2=(ShortProcessor)segB.getImageStack().getProcessor(slice);
    final short[] pixels1=(short[])cluster1.getPixels();
    final short[] pixels2=(short[])cluster2.getPixels();
    double nPixels=pixels1.length;
    for (int i=0; i < nPixels; i++)     pij[pixels1[i] & 0xffff][pixels2[i] & 0xffff]++;
  }
  double[] ai=new double[pij.length];
  for (int i=1; i < pij.length; i++)   for (int j=0; j < pij[0].length; j++) {
    ai[i]+=pij[i][j];
  }
  double[] bj=new double[pij[0].length];
  for (int j=1; j < pij[0].length; j++)   for (int i=1; i < pij.length; i++) {
    bj[j]+=pij[i][j];
  }
  double[] pi0=new double[pij.length];
  double aux=0;
  for (int i=1; i < pij.length; i++) {
    pi0[i]=pij[i][0];
    aux+=pi0[i];
  }
  double sumA=0;
  for (int i=0; i < ai.length; i++)   sumA+=ai[i] * ai[i];
  double sumB=0;
  for (int j=0; j < bj.length; j++)   sumB+=bj[j] * bj[j];
  sumB+=aux / n;
  double sumAB=0;
  for (int i=1; i < pij.length; i++)   for (int j=1; j < pij[0].length; j++)   sumAB+=pij[i][j] * pij[i][j];
  sumAB+=aux / n;
  return new double[]{sumAB / sumB,sumAB / sumA,1.0 - (sumA + sumB - 2.0 * sumAB) / (n * n)};
}