1 package com.github.celldynamics.quimp.plugin.randomwalk;
2
3 import java.awt.Color;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.List;
7 import java.util.stream.Collectors;
8 import java.util.stream.IntStream;
9
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12
13 import com.github.celldynamics.quimp.plugin.randomwalk.RandomWalkSegmentation.SeedTypes;
14
15 import ij.ImagePlus;
16 import ij.ImageStack;
17 import ij.gui.Roi;
18 import ij.plugin.ZProjector;
19 import ij.process.ByteProcessor;
20 import ij.process.ColorProcessor;
21 import ij.process.ImageProcessor;
22 import ij.process.ImageStatistics;
23
24
25
26
27
28
29
30 public class SeedProcessor {
31
32
33
34
35 static final Logger LOGGER = LoggerFactory.getLogger(SeedProcessor.class.getName());
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public static Seeds decodeSeedsfromRgb(final ImageProcessor rgb, final List<Color> fseed,
53 final Color bseed) throws RandomWalkException {
54
55 Seedsamics/quimp/plugin/randomwalk/Seeds.html#Seeds">Seeds out = new Seeds(2);
56
57 ImageProcessor background = new ByteProcessor(rgb.getWidth(), rgb.getHeight());
58
59 if (rgb.getBitDepth() != 24) {
60 throw new RandomWalkException("Unsupported seed image type");
61 }
62 List<Color> fseeds = new ArrayList<>(fseed);
63 fseeds.add(bseed);
64
65 ColorProcessor cp = (ColorProcessor) rgb;
66 for (Color color : fseeds) {
67
68 ImageProcessor foreground = new ByteProcessor(rgb.getWidth(), rgb.getHeight());
69 for (int x = 0; x < cp.getWidth(); x++) {
70 for (int y = 0; y < cp.getHeight(); y++) {
71 Color c = cp.getColor(x, y);
72 if (c.equals(color)) {
73 if (color.equals(bseed)) {
74 background.putPixel(x, y, 255);
75 } else {
76 foreground.putPixel(x, y, 255);
77 }
78 }
79 }
80 }
81 if (color.equals(bseed)) {
82 out.put(RandomWalkSegmentation.SeedTypes.BACKGROUND, background);
83 } else {
84
85 out.put(RandomWalkSegmentation.SeedTypes.FOREGROUNDS, foreground);
86 }
87 }
88
89 validateSeeds(out, SeedTypes.FOREGROUNDS);
90 validateSeeds(out, SeedTypes.BACKGROUND);
91
92 return out;
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 public static Seeds decodeSeedsfromRgb(final ImagePlus rgb, final List<Color> fseed,
111 final Color bseed) throws RandomWalkException {
112 if (rgb.getType() != ImagePlus.COLOR_RGB) {
113 throw new RandomWalkException("Unsupported image type");
114 }
115 return decodeSeedsfromRgb(rgb.getProcessor(), fseed, bseed);
116 }
117
118
119
120
121
122
123
124
125
126 public static void validateSeeds(Seeds seeds, SeedTypes type) throws RandomWalkException {
127 if (seeds.get(type) == null || seeds.get(type).isEmpty()) {
128 return;
129 }
130
131 int pixelsNum = 0;
132 int pixelHistNum = 0;
133
134 for (ImageProcessor i : seeds.get(type)) {
135 int[] histfg = i.getHistogram();
136 pixelHistNum += histfg[0];
137 pixelsNum += i.getPixelCount();
138 }
139 if (pixelHistNum == pixelsNum) {
140 throw new RandomWalkException(
141 "Seed pixels are empty, check if:\n- correct colors were used\n- all slices have"
142 + " been seeded (if stacked seed is used)\n"
143 + "- Shrink/expand parameters are not too big.");
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 public static Seeds decodeSeedsfromRoi(List<Roi> rois, String fgName, String bgName, int width,
164 int height) throws RandomWalkException {
165 Seedsamics/quimp/plugin/randomwalk/Seeds.html#Seeds">Seeds ret = new Seeds();
166
167 List<Roi> fglist = rois.stream().filter(roi -> roi.getName().startsWith(fgName))
168 .collect(Collectors.toList());
169
170 List<Roi> bglist = rois.stream().filter(roi -> roi.getName().startsWith(bgName))
171 .collect(Collectors.toList());
172
173
174 ImageProcessor bg = new ByteProcessor(width, height);
175 bg.setColor(Color.WHITE);
176 for (Roi r : bglist) {
177 r.setFillColor(Color.WHITE);
178 r.setStrokeColor(Color.WHITE);
179 bg.draw(r);
180 }
181 if (!bglist.isEmpty()) {
182 ret.put(SeedTypes.BACKGROUND, bg);
183 }
184
185 ArrayList<Integer> ind = new ArrayList<>();
186
187 for (Roi r : fglist) {
188 r.setFillColor(Color.WHITE);
189 r.setStrokeColor(Color.WHITE);
190 String name = r.getName();
191 String i = name.substring(fgName.length(), name.length());
192 Integer n = Integer.parseInt(i.substring(0, i.indexOf("_")));
193 ind.add(n);
194 }
195
196 List<Integer> norepeat = ind.stream().distinct().collect(Collectors.toList());
197 Collections.sort(norepeat);
198 for (Integer i : norepeat) {
199 ImageProcessor fg = new ByteProcessor(width, height);
200 fg.setColor(Color.WHITE);
201
202 fglist.stream().filter(roi -> roi.getName().startsWith(fgName + i))
203 .forEach(roi -> fg.draw(roi));
204 ret.put(SeedTypes.FOREGROUNDS, fg);
205 }
206
207
208 validateSeeds(ret, SeedTypes.FOREGROUNDS);
209 validateSeeds(ret, SeedTypes.BACKGROUND);
210
211
212
213
214
215
216 LOGGER.debug("Found " + norepeat.size() + " FG objects (" + fglist.size() + " total) and "
217 + bglist.size() + " BG seeds");
218 return ret;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232 public static ImageProcessor seedsToGrayscaleImage(Seeds seeds) {
233 if (seeds.get(SeedTypes.FOREGROUNDS) == null) {
234 return null;
235 }
236 ImageProcessor fg = flatten(seeds, SeedTypes.FOREGROUNDS, 1);
237 ImageStatistics stat = fg.getStats();
238 ImageProcessor bg = flatten(seeds, SeedTypes.BACKGROUND, (int) stat.max + 1);
239 ImageStack stack = new ImageStack(fg.getWidth(), fg.getHeight());
240 stack.addSlice(fg);
241 if (bg != null) {
242 stack.addSlice(bg);
243 }
244
245 ImagePlus im = new ImagePlus("", stack);
246 ZProjector z = new ZProjector(im);
247 z.setImage(im);
248 z.setMethod(ZProjector.MAX_METHOD);
249 z.doProjection();
250 ImageProcessor ret = z.getProjection().getProcessor();
251 return ret;
252 }
253
254
255
256
257
258
259
260
261
262
263 public static ImageProcessor flatten(Seeds seeds, SeedTypes type, int initialValue) {
264 if (seeds.get(type) == null) {
265 return null;
266 }
267 int currentVal = initialValue;
268
269 ImageStack stack = seeds.convertToStack(type).duplicate();
270 for (int s = 1; s <= stack.size(); s++) {
271 stack.getProcessor(s).multiply(1.0 * currentVal / 255);
272 currentVal++;
273 }
274 ImagePlus im = new ImagePlus("", stack);
275 ZProjector z = new ZProjector(im);
276 z.setImage(im);
277 z.setMethod(ZProjector.MAX_METHOD);
278 z.doProjection();
279 ImageProcessor ret = z.getProjection().getProcessor();
280 return ret;
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294 public static Seeds decodeSeedsfromGrayscaleImage(ImageProcessor im) throws RandomWalkException {
295 Seedsamics/quimp/plugin/randomwalk/Seeds.html#Seeds">Seeds ret = new Seeds(2);
296 ImageStatistics stats = im.getStats();
297 int max = (int) stats.max;
298
299
300 List<Integer> lin = IntStream.rangeClosed(1, max).boxed().collect(Collectors.toList());
301 ImageProcessor tmp = new ByteProcessor(im.getWidth(), im.getHeight());
302
303 for (int i = 0; i < max; i++) {
304 ret.put(SeedTypes.FOREGROUNDS, tmp.duplicate());
305 }
306
307 for (int r = 0; r < im.getHeight(); r++) {
308 for (int c = 0; c < im.getWidth(); c++) {
309 int pixel = (int) im.getPixelValue(r, c);
310 if (pixel > 0) {
311 ret.get(SeedTypes.FOREGROUNDS).get(pixel - 1).set(r, c, Color.WHITE.getBlue());
312
313
314 lin.remove(new Integer(pixel));
315 }
316 }
317 }
318
319 if (!lin.isEmpty()) {
320
321 Collections.reverse(lin);
322 for (Integer i : lin) {
323 ret.get(SeedTypes.FOREGROUNDS).remove(i.intValue() - 1);
324 }
325 }
326 validateSeeds(ret, SeedTypes.FOREGROUNDS);
327 return ret;
328 }
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 public static List<Seeds> decodeSeedsfromRoiStack(List<Roi> rois, String fgName, String bgName,
349 int width, int height, int slices) throws RandomWalkException {
350 ArrayList<Seeds> ret = new ArrayList<>();
351
352
353 List<Roi> col0 =
354 rois.stream().filter(roi -> roi.getPosition() == 0).collect(Collectors.toList());
355
356 for (int s = 1; s <= slices; s++) {
357 final int w = s;
358 List<Roi> col =
359 rois.stream().filter(roi -> roi.getPosition() == w).collect(Collectors.toList());
360
361 if (s == 1) {
362 col.addAll(col0);
363 }
364
365 Seeds tmpSeed = SeedProcessor.decodeSeedsfromRoi(col, fgName, bgName, width, height);
366 ret.add(tmpSeed);
367 }
368
369
370
371
372
373
374
375 return ret;
376
377 }
378 }