Program: 150919
Project: 150919
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){
  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);
      }
      double splitTolerance=splitDistanceFraction * c.external.size();
      fitPolygon.setToleranceSplit(splitTolerance);
      fitPolygon.process(c.external);
      GrowQueue_I32 splits=fitPolygon.getSplits();
      if (!expectedNumberOfSides(splits)) {
        if (verbose)         System.out.println("String_Node_Str" + splits.size());
        continue;
      }
      if (!improveContour.fit(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);
      }
      boolean workOrigCCW=workPoly.isCCW();
      if (workOrigCCW) {
        workPoly.flip();
      }
      if (!UtilPolygons2D_F64.isConvex(workPoly)) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      double area=Area2D_F64.polygonConvex(workPoly);
      if (area < minimumArea) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      Polygon2D_F64 refined=found.grow();
      refined.vertexes.resize(splits.size);
      boolean success;
      if (refineCorner != null) {
        refineCorner.setImage(gray);
        success=refineCorner.refine(c.external,splits,refined) >= 3;
        if (workOrigCCW) {
          refined.flip();
        }
      }
 else       if (refineLine != null) {
        refineLine.setImage(gray);
        success=refineLine.refine(workPoly,refined);
      }
 else {
        refined.set(workPoly);
        success=true;
      }
      if (!outputClockwise)       refined.flip();
      if (success) {
        c.id=found.size();
        foundContours.add(c);
      }
 else {
        found.removeTail();
        if (verbose)         System.out.println("String_Node_Str");
      }
    }
  }
}

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){
  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);
      }
      double splitTolerance=splitDistanceFraction * c.external.size();
      fitPolygon.setToleranceSplit(splitTolerance);
      fitPolygon.process(c.external);
      GrowQueue_I32 splits=fitPolygon.getSplits();
      if (!expectedNumberOfSides(splits)) {
        if (verbose)         System.out.println("String_Node_Str" + splits.size());
        continue;
      }
      if (!improveContour.fit(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 (!UtilPolygons2D_F64.isConvex(workPoly)) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      double area=Area2D_F64.polygonConvex(workPoly);
      if (area < minimumArea) {
        if (verbose)         System.out.println("String_Node_Str");
        continue;
      }
      boolean workOrigCCW=workPoly.isCCW();
      if (workOrigCCW) {
        workPoly.flip();
        if (workPoly.isCCW()) {
          throw new RuntimeException("String_Node_Str");
        }
      }
      Polygon2D_F64 refined=found.grow();
      refined.vertexes.resize(splits.size);
      boolean success;
      if (refineCorner != null) {
        refineCorner.setImage(gray);
        success=refineCorner.refine(c.external,splits,refined) >= 3;
        if (workOrigCCW) {
          refined.flip();
        }
      }
 else       if (refineLine != null) {
        refineLine.setImage(gray);
        success=refineLine.refine(workPoly,refined);
      }
 else {
        refined.set(workPoly);
        success=true;
      }
      if (!outputClockwise)       refined.flip();
      if (success) {
        c.id=found.size();
        foundContours.add(c);
      }
 else {
        found.removeTail();
        if (verbose)         System.out.println("String_Node_Str");
      }
    }
  }
}