Skip to content

Commit 5b57e1e

Browse files
committed
Added watershed operation
2 parents 1d2e359 + 30e97a8 commit 5b57e1e

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

core/src/main/java/edu/wpi/grip/core/operations/Operations.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ public static void addOperations(EventBus eventBus) {
4545
eventBus.post(new OperationAddedEvent(new PublishVideoOperation()));
4646
eventBus.post(new OperationAddedEvent(new DistanceTransformOperation()));
4747
eventBus.post(new OperationAddedEvent(new NormalizeOperation()));
48+
eventBus.post(new OperationAddedEvent(new WatershedOperation()));
4849
}
4950
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
2+
package edu.wpi.grip.core.operations.composite;
3+
4+
import com.google.common.eventbus.EventBus;
5+
6+
import edu.wpi.grip.core.InputSocket;
7+
import edu.wpi.grip.core.Operation;
8+
import edu.wpi.grip.core.OutputSocket;
9+
import edu.wpi.grip.core.SocketHint;
10+
import edu.wpi.grip.core.SocketHints;
11+
12+
import static org.bytedeco.javacpp.opencv_core.*;
13+
import static org.bytedeco.javacpp.opencv_imgproc.*;
14+
15+
/**
16+
* GRIP {@link Operation} for
17+
* {@link org.bytedeco.javacpp.opencv_imgproc#watershed}.
18+
*/
19+
public class WatershedOperation implements Operation {
20+
21+
private final SocketHint<Mat> srcHint = SocketHints.Inputs.createMatSocketHint("Input", false);
22+
private final SocketHint<ContoursReport> contoursHint = new SocketHint.Builder<>(ContoursReport.class)
23+
.identifier("Contours")
24+
.initialValueSupplier(ContoursReport::new)
25+
.build();
26+
27+
private final SocketHint<Mat> outputHint = SocketHints.Inputs.createMatSocketHint("Output", true);
28+
29+
@Override
30+
public String getName() {
31+
return "Watershed";
32+
}
33+
34+
@Override
35+
public String getDescription() {
36+
return "Isolates overlapping objects from the background and each other";
37+
}
38+
39+
@Override
40+
public InputSocket<?>[] createInputSockets(EventBus eventBus) {
41+
return new InputSocket<?>[]{
42+
new InputSocket<>(eventBus, srcHint),
43+
new InputSocket<>(eventBus, contoursHint)
44+
};
45+
}
46+
47+
@Override
48+
public OutputSocket<?>[] createOutputSockets(EventBus eventBus) {
49+
return new OutputSocket<?>[]{
50+
new OutputSocket<>(eventBus, outputHint)
51+
};
52+
}
53+
54+
@Override
55+
public void perform(InputSocket<?>[] inputs, OutputSocket<?>[] outputs) {
56+
final Mat input = (Mat) inputs[0].getValue().get();
57+
if (input.type() != CV_8UC3) {
58+
throw new IllegalArgumentException("Watershed only works on 8-bit, 3-channel images");
59+
}
60+
61+
final ContoursReport contourReport = (ContoursReport) inputs[1].getValue().get();
62+
final MatVector contours = contourReport.getContours();
63+
64+
final OutputSocket<Mat> outputSocket = (OutputSocket<Mat>) outputs[0];
65+
final Mat markers = new Mat(input.size(), CV_32SC1, new Scalar(0.0));
66+
final Mat output = new Mat(markers.size(), CV_8UC1, new Scalar(0.0));
67+
68+
// draw foreground markers (these have to be different colors)
69+
for (int i = 0; i < contours.size(); i++) {
70+
drawContours(markers, contours, i, Scalar.all((i + 1) * (255 / contours.size())), CV_FILLED, LINE_8, null, 2, null);
71+
}
72+
73+
// draw background marker a different color from the foreground markers
74+
// TODO maybe make this configurable? There may be something in the corner
75+
circle(markers, new Point(5, 5), 3, Scalar.WHITE, -1, LINE_8, 0);
76+
77+
watershed(input, markers);
78+
markers.convertTo(output, CV_8UC1);
79+
bitwise_not(output, output); // watershed inverts colors; invert them back
80+
81+
outputSocket.setValue(output);
82+
83+
// make sure that the working mat is freed to avoid a memory leak
84+
markers.release();
85+
}
86+
87+
}

0 commit comments

Comments
 (0)