Program: 46620
Project: 46620
Buggy source:
/** 
 * Get the perforation series, smoother and with interpolated missing frames
 * @param maxY Maximum Y coordinate of the scanned strip
 * @return List of perforations
 */
public List<Perforation> getPerforations(int maxY){
  List<Perforation> ret=new ArrayList<Perforation>();
  Perforation lastPerf=null;
  for (  Perforation p : perforations) {
    if (lastPerf != null) {
      if (p.y - lastPerf.y > PERF_DISTANCE + Y_TOLERANCE) {
        int addCount=(p.y - lastPerf.y + 2 * Y_TOLERANCE) / PERF_DISTANCE;
        int dy=(p.y - lastPerf.y) / addCount;
        int dx=(p.x - lastPerf.x) / addCount;
        System.out.println(String.format("String_Node_Str",addCount,dx,dy));
        for (int n=1; n < addCount; n++) {
          Perforation newP=new Perforation();
          newP.x=lastPerf.x + n * dx;
          newP.y=lastPerf.y + n * dy;
          newP.series=this;
          ret.add(newP);
          System.out.println(String.format("String_Node_Str",newP.x,newP.y));
        }
      }
    }
    ret.add(p);
    System.out.println(String.format("String_Node_Str",p.x,p.y));
    lastPerf=p;
  }
  if (ret.get(0).y > PERF_DISTANCE && ret.size() > 1) {
    int dx=ret.get(1).x - ret.get(0).x;
    int dy=(ret.get(ret.size() - 1).y - ret.get(0).y) / (ret.size() - 1);
    int y=ret.get(0).y - dy;
    int x=ret.get(0).x - dx;
    System.out.println(String.format("String_Node_Str",dx,dy,x,y));
    while (y > 0) {
      Perforation p=new Perforation();
      p.x=x;
      p.y=y;
      x-=dx;
      y-=dy;
      ret.add(0,p);
    }
  }
  for (int n=0; n < ret.size(); n++) {
    int dx=0;
    int ddx=0;
    int ddy=0;
    if (n > 0) {
      dx=ret.get(n).x - ret.get(n - 1).x;
    }
    if (n > 0 && n < ret.size() - 1) {
      ddx=ret.get(n + 1).x + ret.get(n - 1).x - 2 * ret.get(n).x;
      ddy=ret.get(n + 1).y + ret.get(n - 1).y - 2 * ret.get(n).y;
    }
    ret.get(n).x+=ddx / 2;
    ret.get(n).y+=ddy / 2;
  }
  return ret;
}

Fixed version (ground truth):
/** 
 * Get the perforation series, smoother and with interpolated missing frames
 * @param maxY Maximum Y coordinate of the scanned strip
 * @return List of perforations
 */
public List<Perforation> getPerforations(int maxY){
  List<Perforation> ret=new ArrayList<Perforation>();
  Perforation lastPerf=null;
  for (  Perforation p : perforations) {
    if (lastPerf != null) {
      if (p.y - lastPerf.y > PERF_DISTANCE + Y_TOLERANCE) {
        int addCount=(p.y - lastPerf.y + 2 * Y_TOLERANCE) / PERF_DISTANCE;
        int dy=(p.y - lastPerf.y) / addCount;
        int dx=(p.x - lastPerf.x) / addCount;
        System.out.println(String.format("String_Node_Str",addCount,dx,dy));
        for (int n=1; n < addCount; n++) {
          Perforation newP=new Perforation();
          newP.x=lastPerf.x + n * dx;
          newP.y=lastPerf.y + n * dy;
          ret.add(newP);
          System.out.println(String.format("String_Node_Str",newP.x,newP.y));
        }
      }
    }
    ret.add(p);
    System.out.println(String.format("String_Node_Str",p.x,p.y));
    lastPerf=p;
  }
  if (ret.get(0).y > PERF_DISTANCE && ret.size() > 1) {
    int dx=ret.get(1).x - ret.get(0).x;
    int dy=(ret.get(ret.size() - 1).y - ret.get(0).y) / (ret.size() - 1);
    int y=ret.get(0).y - dy;
    int x=ret.get(0).x - dx;
    System.out.println(String.format("String_Node_Str",dx,dy,x,y));
    while (y > 0) {
      Perforation p=new Perforation();
      p.x=x;
      p.y=y;
      x-=dx;
      y-=dy;
      ret.add(0,p);
    }
  }
  for (int n=0; n < ret.size(); n++) {
    int dx=0;
    int ddx=0;
    int ddy=0;
    if (n > 0) {
      dx=ret.get(n).x - ret.get(n - 1).x;
    }
    if (n > 0 && n < ret.size() - 1) {
      ddx=ret.get(n + 1).x + ret.get(n - 1).x - 2 * ret.get(n).x;
      ddy=ret.get(n + 1).y + ret.get(n - 1).y - 2 * ret.get(n).y;
    }
    ret.get(n).x+=ddx / 2;
    ret.get(n).y+=ddy / 2;
  }
  return ret;
}