Program: 150901
Project: 150901
Buggy source:
/** 
 * Finds blobs in the binary image.  Then looks for blobs that meet size and shape requirements.  See code below for the requirements.  Those that remain are considered to be target candidates.
 */
private void findCandidateShapes(T gray,ImageUInt8 binary){
  int maxSidesConsider=(int)Math.ceil(maxSides * 1.2);
  fitPolygon.setAbortSplits(2 * maxSides);
  contourFinder.process(binary,labeled);
  FastQueue<Contour> blobs=contourFinder.getContours();
  for (int i=0; i < blobs.size; i++) {
    Contour c=blobs.get(i);
    if (c.external.size() >= minimumContour) {
      if (touchesBorder(c.external))       continue;
      if (toUndistorted != null) {
        removeDistortionFromContour(c.external);
      }
      if (!fitPolygon.process(c.external)) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
        continue;
      }
      GrowQueue_I32 splits=fitPolygon.getSplits();
      if (splits.size() > maxSidesConsider) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
      }
      if (!improveContour.fit(c.external,splits)) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
        continue;
      }
      boolean wasPruned=pruner.fit(c.external,splits,pruned);
      splits=pruned;
      if (!expectedNumberOfSides(splits)) {
        if (verbose)         System.out.println("String_Node_Str" + splits.size() + "String_Node_Str"+ c.external.size());
        continue;
      }
      if (wasPruned && !improveContour.fit(c.external,splits)) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
        continue;
      }
      if (helper != null) {
        if (!helper.filterPolygon(c.external,splits)) {
          if (verbose)           System.out.println("String_Node_Str");
          continue;
        }
      }
      workPoly.vertexes.resize(splits.size());
      for (int j=0; j < splits.size(); j++) {
        Point2D_I32 p=c.external.get(splits.get(j));
        workPoly.get(j).set(p.x,p.y);
      }
      if (helper != null) {
        helper.adjustBeforeOptimize(workPoly);
      }
      if (convex && !UtilPolygons2D_F64.isConvex(workPoly)) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      double area=Area2D_F64.polygonSimple(workPoly);
      if (area < minimumArea) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      if (checkEdgeBefore && differenceScore != null && !differenceScore.validate(workPoly)) {
        if (verbose)         System.out.println("String_Node_Str" + differenceScore.getAverageEdgeIntensity());
        continue;
      }
      Polygon2D_F64 refined=found.grow();
      refined.vertexes.resize(splits.size);
      boolean success;
      if (refinePolygon != null) {
        refinePolygon.setImage(gray);
        success=refinePolygon.refine(workPoly,c.external,splits,refined);
        if (verbose)         System.out.println("String_Node_Str");
      }
 else {
        refined.set(workPoly);
        success=true;
      }
      if (!checkEdgeBefore && differenceScore != null && !differenceScore.validate(refined)) {
        if (verbose)         System.out.println("String_Node_Str" + differenceScore.getAverageEdgeIntensity());
        continue;
      }
      if (outputClockwise == refined.isCCW())       refined.flip();
      if (success) {
        c.id=found.size();
        foundContours.add(c);
      }
 else {
        found.removeTail();
      }
    }
  }
}

Fixed version (ground truth):
/** 
 * Finds blobs in the binary image.  Then looks for blobs that meet size and shape requirements.  See code below for the requirements.  Those that remain are considered to be target candidates.
 */
private void findCandidateShapes(T gray,ImageUInt8 binary){
  int maxSidesConsider=(int)Math.ceil(maxSides * 1.5);
  fitPolygon.setAbortSplits(2 * maxSides);
  contourFinder.process(binary,labeled);
  FastQueue<Contour> blobs=contourFinder.getContours();
  for (int i=0; i < blobs.size; i++) {
    Contour c=blobs.get(i);
    if (c.external.size() >= minimumContour) {
      System.out.println("String_Node_Str" + c.external.size());
      if (touchesBorder(c.external)) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      if (toUndistorted != null) {
        removeDistortionFromContour(c.external);
      }
      if (!fitPolygon.process(c.external)) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
        continue;
      }
      GrowQueue_I32 splits=fitPolygon.getSplits();
      if (splits.size() > maxSidesConsider) {
        if (verbose)         System.out.println("String_Node_Str" + splits.size() + "String_Node_Str"+ c.external.size());
        continue;
      }
      if (!improveContour.fit(c.external,splits)) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
        continue;
      }
      boolean wasPruned=pruner.fit(c.external,splits,pruned);
      splits=pruned;
      if (!expectedNumberOfSides(splits)) {
        if (verbose)         System.out.println("String_Node_Str" + splits.size() + "String_Node_Str"+ c.external.size());
        continue;
      }
      if (wasPruned && !improveContour.fit(c.external,splits)) {
        if (verbose)         System.out.println("String_Node_Str" + c.external.size());
        continue;
      }
      if (helper != null) {
        if (!helper.filterPolygon(c.external,splits)) {
          if (verbose)           System.out.println("String_Node_Str");
          continue;
        }
      }
      workPoly.vertexes.resize(splits.size());
      for (int j=0; j < splits.size(); j++) {
        Point2D_I32 p=c.external.get(splits.get(j));
        workPoly.get(j).set(p.x,p.y);
      }
      if (helper != null) {
        helper.adjustBeforeOptimize(workPoly);
      }
      if (convex && !UtilPolygons2D_F64.isConvex(workPoly)) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      double area=Area2D_F64.polygonSimple(workPoly);
      if (area < minimumArea) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      if (checkEdgeBefore && differenceScore != null && !differenceScore.validate(workPoly)) {
        if (verbose)         System.out.println("String_Node_Str" + differenceScore.getAverageEdgeIntensity());
        continue;
      }
      Polygon2D_F64 refined=found.grow();
      refined.vertexes.resize(splits.size);
      boolean success;
      if (refinePolygon != null) {
        refinePolygon.setImage(gray);
        success=refinePolygon.refine(workPoly,c.external,splits,refined);
        if (verbose && !success)         System.out.println("String_Node_Str");
      }
 else {
        refined.set(workPoly);
        success=true;
      }
      if (!checkEdgeBefore && differenceScore != null && !differenceScore.validate(refined)) {
        if (verbose)         System.out.println("String_Node_Str" + differenceScore.getAverageEdgeIntensity());
        continue;
      }
      if (outputClockwise == refined.isCCW())       refined.flip();
      if (success) {
        System.out.println("String_Node_Str");
        c.id=found.size();
        foundContours.add(c);
      }
 else {
        found.removeTail();
      }
    }
  }
}