public void configure(int numCols, int numRows) {
    ConfigChessboard config = new ConfigChessboard(numCols, numRows, 30);

    alg = FactoryPlanarCalibrationTarget.detectorChessboard(config).getAlg();

    alg.setUserBinaryThreshold(config.binaryGlobalThreshold);
    alg.setUserAdaptiveBias(config.binaryAdaptiveBias);
    alg.setUserAdaptiveRadius(config.binaryAdaptiveRadius);
  }
  private synchronized void renderOutput() {
    switch (calibGUI.getSelectedView()) {
      case 0:
        workImage.createGraphics().drawImage(input, null, null);
        break;

      case 1:
        VisualizeBinaryData.renderBinary(alg.getBinary(), false, workImage);
        break;

      case 2:
        renderClusters();
        break;

      default:
        throw new RuntimeException("Unknown mode");
    }
    Graphics2D g2 = workImage.createGraphics();
    if (foundTarget) {
      if (calibGUI.isShowBound()) {
        //				Polygon2D_I32 bounds =  alg.getFindBound().getBoundPolygon();
        //				drawBounds(g2, bounds);
      }

      if (calibGUI.isShowNumbers()) {
        drawNumbers(g2, alg.getCalibrationPoints(), null, 1);
      }
      calibGUI.setSuccessMessage("FOUND", true);
    } else {
      if (calibGUI.isShowBound()) {
        //				Polygon2D_I32 bounds =  alg.getFindBound().getBoundPolygon();
        //				drawBounds(g2, bounds);
      }

      calibGUI.setSuccessMessage("FAILED", false);
    }

    if (calibGUI.isShowPoints()) {
      List<Point2D_F64> candidates = alg.getCalibrationPoints();
      for (Point2D_F64 c : candidates) {
        VisualizeFeatures.drawPoint(g2, (int) (c.x + 0.5), (int) (c.y + 0.5), 1, Color.RED);
      }
    }

    if (calibGUI.doShowGraph) {
      System.out.println("Maybe I should add this back in with the new detector some how");
    }

    gui.setBufferedImage(workImage);
    gui.setScale(calibGUI.getScale());
    gui.repaint();

    processed = true;
  }
  private void renderClusters() {

    Graphics2D g2 = workImage.createGraphics();

    FastQueue<Polygon2D_F64> squares = alg.getFindSeeds().getDetectorSquare().getFound();

    for (int i = 0; i < squares.size(); i++) {
      Polygon2D_F64 p = squares.get(i);
      g2.setColor(Color.black);
      g2.setStroke(new BasicStroke(4));
      VisualizeShapes.drawPolygon(p, true, g2, true);
      g2.setColor(Color.white);
      g2.setStroke(new BasicStroke(2));
      VisualizeShapes.drawPolygon(p, true, g2, true);
    }

    List<SquareGrid> grids = alg.getFindSeeds().getGrids().getGrids();

    for (int i = 0; i < grids.size(); i++) {
      SquareGrid g = grids.get(i);
      int a = grids.size() == 1 ? 0 : 255 * i / (grids.size() - 1);

      int rgb = a << 16 | (255 - a) << 8;

      g2.setStroke(new BasicStroke(3));

      for (int j = 0; j < g.nodes.size() - 1; j++) {
        double fraction = j / ((double) g.nodes.size() - 1);
        fraction = fraction * 0.6 + 0.4;

        int lineRGB = (int) (fraction * a) << 16 | (int) (fraction * (255 - a)) << 8;

        g2.setColor(new Color(lineRGB));
        SquareNode p0 = g.nodes.get(j);
        SquareNode p1 = g.nodes.get(j + 1);
        g2.drawLine((int) p0.center.x, (int) p0.center.y, (int) p1.center.x, (int) p1.center.y);
      }

      g2.setColor(new Color(rgb));
      for (int j = 0; j < g.nodes.size(); j++) {
        SquareNode n = g.nodes.get(j);
        VisualizeShapes.drawPolygon(n.corners, true, g2, true);
      }
    }
  }
  private synchronized void detectTarget() {
    if (calibGUI.isManual()) alg.setUserBinaryThreshold(calibGUI.getThresholdLevel());
    else alg.setUserBinaryThreshold(-1);

    foundTarget = alg.process(gray);
  }