public static Mat getCCH(Mat image) {
    ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
    Mat hierarchy = new Mat();
    Imgproc.findContours(
        image, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE);

    Mat chainHistogram = Mat.zeros(1, 8, CvType.CV_32F);
    int n = 0;
    MatOfPoint2f approxCurve = new MatOfPoint2f();
    for (MatOfPoint contour : contours) {

      // get the freeman chain code from the contours
      int rows = contour.rows();
      // System.out.println("\nrows"+rows+"\n"+contour.dump());
      int direction = 7;
      Mat prevPoint = contours.get(0).row(0);
      n += rows - 1;
      for (int i = 1; i < rows; i++) {
        // get the current point
        double x1 = contour.get(i - 1, 0)[1];
        double y1 = contour.get(i - 1, 0)[0];

        // get the second point
        double x2 = contour.get(i, 0)[1];
        double y2 = contour.get(i, 0)[0];

        if (x2 == x1 && y2 == y1 + 1) direction = 0;
        else if (x2 == x1 - 1 && y2 == y1 + 1) direction = 1;
        else if (x2 == x1 - 1 && y2 == y1) direction = 2;
        else if (x2 == x1 - 1 && y2 == y1 - 1) direction = 3;
        else if (x2 == x1 && y2 == y1 - 1) direction = 4;
        else if (x2 == x1 + 1 && y2 == y1 - 1) direction = 5;
        else if (x2 == x1 + 1 && y2 == y1) direction = 6;
        else if (x2 == x1 + 1 && y2 == y1 + 1) direction = 7;
        else System.out.print("err");
        double counter = chainHistogram.get(0, direction)[0];
        chainHistogram.put(0, direction, ++counter);
        System.out.print(direction);
      }
    }
    System.out.println("\n" + chainHistogram.dump());
    Scalar alpha = new Scalar(n); // the factor
    Core.divide(chainHistogram, alpha, chainHistogram);
    System.out.println("\nrows=" + n + " " + chainHistogram.dump());
    return chainHistogram;
  }