1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.samples.clustering;
23
24 import java.awt.BorderLayout;
25 import java.awt.Color;
26 import java.awt.Component;
27 import java.awt.Dimension;
28 import java.awt.FlowLayout;
29 import java.awt.Graphics;
30 import java.awt.GridLayout;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ActionListener;
33 import java.awt.image.BufferedImage;
34 import java.awt.image.Raster;
35 import java.awt.image.WritableRaster;
36 import java.io.IOException;
37 import java.util.ArrayList;
38 import java.util.List;
39
40 import javax.imageio.ImageIO;
41 import javax.swing.BorderFactory;
42 import javax.swing.Box;
43 import javax.swing.ImageIcon;
44 import javax.swing.JButton;
45 import javax.swing.JLabel;
46 import javax.swing.JPanel;
47 import javax.swing.JSpinner;
48 import javax.swing.SpinnerNumberModel;
49
50 import org.hipparchus.clustering.CentroidCluster;
51 import org.hipparchus.clustering.Clusterable;
52 import org.hipparchus.clustering.KMeansPlusPlusClusterer;
53 import org.hipparchus.samples.ExampleUtils;
54 import org.hipparchus.samples.ExampleUtils.ExampleFrame;
55
56
57
58
59
60 @SuppressWarnings("serial")
61 public class ImageClusteringExample {
62
63
64
65
66
67
68
69
70 public ImageClusteringExample() {
71
72 }
73
74
75 public static class Display extends ExampleFrame {
76
77
78 private BufferedImage referenceImage;
79
80
81 private BufferedImage clusterImage;
82
83
84 private Raster referenceRaster;
85
86
87 private ImagePainter painter;
88
89
90 private JSpinner clusterSizeSpinner;
91
92
93
94
95 public Display() throws IOException {
96 setTitle("Hipparchus: Image Clustering Example");
97 setSize(900, 350);
98
99 setLayout(new FlowLayout());
100
101 Box bar = Box.createHorizontalBox();
102
103 ClassLoader classLoader = ExampleUtils.class.getClassLoader();
104 referenceImage = ExampleUtils.resizeImage(
105 ImageIO.read(classLoader.getResourceAsStream("ColorfulBird.jpg")),
106 350,
107 240,
108 BufferedImage.TYPE_INT_RGB);
109
110 referenceRaster = referenceImage.getData();
111
112 clusterImage = new BufferedImage(referenceImage.getWidth(),
113 referenceImage.getHeight(),
114 BufferedImage.TYPE_INT_RGB);
115
116 JLabel picLabel = new JLabel(new ImageIcon(referenceImage));
117 bar.add(picLabel);
118
119 painter = new ImagePainter(clusterImage.getWidth(), clusterImage.getHeight());
120 bar.add(painter);
121
122 JPanel controlBox = new JPanel();
123 controlBox.setLayout(new GridLayout(5, 1));
124 controlBox.setBorder(BorderFactory.createLineBorder(Color.black, 1));
125
126 JPanel sizeBox = new JPanel();
127 JLabel sizeLabel = new JLabel("Clusters:");
128 sizeBox.add(sizeLabel);
129
130 SpinnerNumberModel model = new SpinnerNumberModel(3, 2, 10, 1);
131 clusterSizeSpinner = new JSpinner(model);
132
133 sizeLabel.setLabelFor(clusterSizeSpinner);
134 sizeBox.add(clusterSizeSpinner);
135 controlBox.add(sizeBox, BorderLayout.NORTH);
136
137 JButton startButton = new JButton("Cluster");
138 startButton.setActionCommand("cluster");
139 controlBox.add(startButton, BorderLayout.CENTER);
140
141 bar.add(controlBox);
142
143 add(bar);
144
145 startButton.addActionListener(e -> clusterImage());
146 }
147
148
149
150 private void clusterImage() {
151 List<PixelClusterable> pixels = new ArrayList<>();
152 for (int row = 0; row < referenceImage.getHeight(); row++) {
153 for (int col = 0; col < referenceImage.getWidth(); col++) {
154 pixels.add(new PixelClusterable(col, row));
155 }
156 }
157
158 int clusterSize = ((Number) clusterSizeSpinner.getValue()).intValue();
159 KMeansPlusPlusClusterer<PixelClusterable> clusterer =
160 new KMeansPlusPlusClusterer<>(clusterSize);
161 List<CentroidCluster<PixelClusterable>> clusters = clusterer.cluster(pixels);
162
163 WritableRaster raster = clusterImage.getRaster();
164 for (CentroidCluster<PixelClusterable> cluster : clusters) {
165 double[] color = cluster.getCenter().getPoint();
166 for (PixelClusterable pixel : cluster.getPoints()) {
167 raster.setPixel(pixel.x, pixel.y, color);
168 }
169 }
170
171 Display.this.repaint();
172 }
173
174
175 private class PixelClusterable implements Clusterable {
176
177
178 private final int x;
179
180
181 private final int y;
182
183
184 private double[] color;
185
186
187
188
189
190 PixelClusterable(int x, int y) {
191 this.x = x;
192 this.y = y;
193 this.color = null;
194 }
195
196
197 @Override
198 public double[] getPoint() {
199 if (color == null) {
200 color = referenceRaster.getPixel(x, y, (double[]) null);
201 }
202 return color;
203 }
204
205 }
206
207
208 private class ImagePainter extends Component {
209
210
211 private int width;
212
213
214 private int height;
215
216
217
218
219
220 ImagePainter(int width, int height) {
221 this.width = width;
222 this.height = height;
223 }
224
225
226 @Override
227 public Dimension getPreferredSize() {
228 return new Dimension(width, height);
229 }
230
231
232 @Override
233 public Dimension getMinimumSize() {
234 return getPreferredSize();
235 }
236
237
238 @Override
239 public Dimension getMaximumSize() {
240 return getPreferredSize();
241 }
242
243
244 @Override
245 public void paint(Graphics g) {
246 g.drawImage(clusterImage, 0, 0, this);
247 }
248
249 }
250
251 }
252
253
254
255
256
257 public static void main(String[] args) throws IOException {
258 ExampleUtils.showExampleFrame(new Display());
259 }
260
261 }