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