content: import java.util.ArrayList;
  import java.util.List;
  
  import org.opencv.core.Core;
  import org.opencv.core.CvType;
  import org.opencv.core.Mat;
  import org.opencv.core.MatOfPoint;
  import org.opencv.core.Point;
  import org.opencv.core.Scalar;
  import org.opencv.highgui.HighGui;
  import org.opencv.imgcodecs.Imgcodecs;
  import org.opencv.imgproc.Imgproc;
  
  //This program demonstrates how to use OpenCV PCA to extract the orientation of an object.
  class IntroductionToPCA {
      private void drawAxis(Mat img, Point p_, Point q_, Scalar colour, float scale) {
          Point p = new Point(p_.x, p_.y);
          Point q = new Point(q_.x, q_.y);
          //! [visualization1]
          double angle = Math.atan2(p.y - q.y, p.x - q.x); // angle in radians
          double hypotenuse = Math.sqrt((p.y - q.y) * (p.y - q.y) + (p.x - q.x) * (p.x - q.x));
  
          // Here we lengthen the arrow by a factor of scale
          q.x = (int) (p.x - scale * hypotenuse * Math.cos(angle));
          q.y = (int) (p.y - scale * hypotenuse * Math.sin(angle));
          Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);
  
          // create the arrow hooks
          p.x = (int) (q.x + 9 * Math.cos(angle + Math.PI / 4));
          p.y = (int) (q.y + 9 * Math.sin(angle + Math.PI / 4));
          Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);
  
          p.x = (int) (q.x + 9 * Math.cos(angle - Math.PI / 4));
          p.y = (int) (q.y + 9 * Math.sin(angle - Math.PI / 4));
          Imgproc.line(img, p, q, colour, 1, Imgproc.LINE_AA, 0);
          //! [visualization1]
      }
  
      private double getOrientation(MatOfPoint ptsMat, Mat img) {
          List<Point> pts = ptsMat.toList();
          //! [pca]
          // Construct a buffer used by the pca analysis
          int sz = pts.size();
          Mat dataPts = new Mat(sz, 2, CvType.CV_64F);
          double[] dataPtsData = new double[(int) (dataPts.total() * dataPts.channels())];
          for (int i = 0; i < dataPts.rows(); i++) {
              dataPtsData[i * dataPts.cols()] = pts.get(i).x;
              dataPtsData[i * dataPts.cols() + 1] = pts.get(i).y;
          }
          dataPts.put(0, 0, dataPtsData);
  
          // Perform PCA analysis
          Mat mean = new Mat();
          Mat eigenvectors = new Mat();
          Mat eigenvalues = new Mat();
          Core.PCACompute2(dataPts, mean, eigenvectors, eigenvalues);
          double[] meanData = new double[(int) (mean.total() * mean.channels())];
          mean.get(0, 0, meanData);
  
          // Store the center of the object
          Point cntr = new Point(meanData[0], meanData[1]);
  
          // Store the eigenvalues and eigenvectors
          double[] eigenvectorsData = new double[(int) (eigenvectors.total() * eigenvectors.channels())];
          double[] eigenvaluesData = new double[(int) (eigenvalues.total() * eigenvalues.channels())];
          eigenvectors.get(0, 0, eigenvectorsData);
          eigenvalues.get(0, 0, eigenvaluesData);
          //! [pca]
  
          //! [visualization]
          // Draw the principal components
          Imgproc.circle(img, cntr, 3, new Scalar(255, 0, 255), 2);
          Point p1 = new Point(cntr.x + 0.02 * eigenvectorsData[0] * eigenvaluesData[0],
                  cntr.y + 0.02 * eigenvectorsData[1] * eigenvaluesData[0]);
          Point p2 = new Point(cntr.x - 0.02 * eigenvectorsData[2] * eigenvaluesData[1],
                  cntr.y - 0.02 * eigenvectorsData[3] * eigenvaluesData[1]);
          drawAxis(img, cntr, p1, new Scalar(0, 255, 0), 1);
          drawAxis(img, cntr, p2, new Scalar(255, 255, 0), 5);
  
          double angle = Math.atan2(eigenvectorsData[1], eigenvectorsData[0]); // orientation in radians
          //! [visualization]
  
          return angle;
      }
  
      public void run(String[] args) {
          //! [pre-process]
          // Load image
          String filename = args.length > 0 ? args[0] : "../data/pca_test1.jpg";
          Mat src = Imgcodecs.imread(filename);
  
          // Check if image is loaded successfully
          if (src.empty()) {
              System.err.println("Cannot read image: " + filename);
              System.exit(0);
          }
  
          Mat srcOriginal = src.clone();
          HighGui.imshow("src", srcOriginal);
  
          // Convert image to grayscale
          Mat gray = new Mat();
          Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
  
          // Convert image to binary
          Mat bw = new Mat();
          Imgproc.threshold(gray, bw, 50, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
          //! [pre-process]
  
          //! [contours]
          // Find all the contours in the thresholded image
          List<MatOfPoint> contours = new ArrayList<>();
          Mat hierarchy = new Mat();
          Imgproc.findContours(bw, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);
  
          for (int i = 0; i < contours.size(); i++) {
              // Calculate the area of each contour
              double area = Imgproc.contourArea(contours.get(i));
              // Ignore contours that are too small or too large
              if (area < 1e2 || 1e5 < area)
                  continue;
  
              // Draw each contour only for visualisation purposes
              Imgproc.drawContours(src, contours, i, new Scalar(0, 0, 255), 2);
              // Find the orientation of each shape
              getOrientation(contours.get(i), src);
          }
          //! [contours]
  
          HighGui.imshow("output", src);
  
          HighGui.waitKey();
          System.exit(0);
      }
  }
  
  public class IntroductionToPCADemo {
      public static void main(String[] args) {
          // Load the native OpenCV library
          System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
  
          new IntroductionToPCA().run(args);
      }
  }
  