1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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);
}
}