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(new ActionListener() {
146 public void actionPerformed(ActionEvent e) {
147 clusterImage();
148 }
149 });
150 }
151
152
153
154 private void clusterImage() {
155 List<PixelClusterable> pixels = new ArrayList<PixelClusterable>();
156 for (int row = 0; row < referenceImage.getHeight(); row++) {
157 for (int col = 0; col < referenceImage.getWidth(); col++) {
158 pixels.add(new PixelClusterable(col, row));
159 }
160 }
161
162 int clusterSize = ((Number) clusterSizeSpinner.getValue()).intValue();
163 KMeansPlusPlusClusterer<PixelClusterable> clusterer =
164 new KMeansPlusPlusClusterer<PixelClusterable>(clusterSize);
165 List<CentroidCluster<PixelClusterable>> clusters = clusterer.cluster(pixels);
166
167 WritableRaster raster = clusterImage.getRaster();
168 for (CentroidCluster<PixelClusterable> cluster : clusters) {
169 double[] color = cluster.getCenter().getPoint();
170 for (PixelClusterable pixel : cluster.getPoints()) {
171 raster.setPixel(pixel.x, pixel.y, color);
172 }
173 }
174
175 Display.this.repaint();
176 }
177
178
179 private class PixelClusterable implements Clusterable {
180
181
182 private final int x;
183
184
185 private final int y;
186
187
188 private double[] color;
189
190
191
192
193
194 PixelClusterable(int x, int y) {
195 this.x = x;
196 this.y = y;
197 this.color = null;
198 }
199
200
201 @Override
202 public double[] getPoint() {
203 if (color == null) {
204 color = referenceRaster.getPixel(x, y, (double[]) null);
205 }
206 return color;
207 }
208
209 }
210
211
212 private class ImagePainter extends Component {
213
214
215 private int width;
216
217
218 private int height;
219
220
221
222
223
224 ImagePainter(int width, int height) {
225 this.width = width;
226 this.height = height;
227 }
228
229
230 @Override
231 public Dimension getPreferredSize() {
232 return new Dimension(width, height);
233 }
234
235
236 @Override
237 public Dimension getMinimumSize() {
238 return getPreferredSize();
239 }
240
241
242 @Override
243 public Dimension getMaximumSize() {
244 return getPreferredSize();
245 }
246
247
248 @Override
249 public void paint(Graphics g) {
250 g.drawImage(clusterImage, 0, 0, this);
251 }
252
253 }
254
255 }
256
257
258
259
260
261 public static void main(String[] args) throws IOException {
262 ExampleUtils.showExampleFrame(new Display());
263 }
264
265 }