11package edu .wpi .grip .core .operations .composite ;
22
3- import static org .bytedeco .javacpp .opencv_core .*;
3+ import edu .wpi .grip .core .operations .networktables .NTPublishable ;
4+ import edu .wpi .grip .core .operations .networktables .NTValue ;
5+
6+ import java .util .ArrayList ;
7+ import java .util .List ;
8+ import java .util .Optional ;
9+
10+ import static org .bytedeco .javacpp .opencv_core .MatVector ;
11+ import static org .bytedeco .javacpp .opencv_core .Rect ;
12+ import static org .bytedeco .javacpp .opencv_imgproc .boundingRect ;
13+ import static org .bytedeco .javacpp .opencv_imgproc .contourArea ;
414
515/**
616 * The output of {@link FindContoursOperation}. This stores a list of contours (which is basically a list of points) in
717 * OpenCV objects, as well as the width and height of the image that the contours are from, to give context to the
818 * points.
919 */
10- public final class ContoursReport {
11- private int rows , cols ;
12- private MatVector contours = new MatVector ();
20+ public final class ContoursReport implements NTPublishable {
21+ private final int rows , cols ;
22+ private final MatVector contours ;
23+ private Optional <List <Rect >> boundingBoxes = Optional .empty ();
1324
25+ /**
26+ * Construct an empty report. This is used as a default value for {@link edu.wpi.grip.core.Socket}s containing
27+ * ContoursReports.
28+ */
1429 public ContoursReport () {
15- this (new MatVector (), - 1 , - 1 );
30+ this (new MatVector (), 0 , 0 );
1631 }
1732
1833 public ContoursReport (MatVector contours , int rows , int cols ) {
@@ -21,27 +36,81 @@ public ContoursReport(MatVector contours, int rows, int cols) {
2136 this .cols = cols ;
2237 }
2338
24- public void setContours (MatVector contours ) {
25- this .contours = contours ;
39+ public int getRows () {
40+ return this .rows ;
41+ }
42+
43+ public int getCols () {
44+ return this .cols ;
2645 }
2746
2847 public MatVector getContours () {
2948 return this .contours ;
3049 }
3150
32- public void setRows (int rows ) {
33- this .rows = rows ;
51+ /**
52+ * Compute the bounding boxes of all contours (if they haven't already been computed). Bounding boxes are used
53+ * to compute several different properties, so it's probably not a good idea to compute them over and over again.
54+ */
55+ private synchronized List <Rect > computeBoundingBoxes () {
56+ if (!boundingBoxes .isPresent ()) {
57+ List <Rect > bb = new ArrayList <>();
58+ for (int i = 0 ; i < contours .size (); i ++) {
59+ bb .add (boundingRect (contours .get (i )));
60+ }
61+
62+ boundingBoxes = Optional .of (bb );
63+ }
64+
65+ return boundingBoxes .get ();
3466 }
3567
36- public void setCols (int cols ) {
37- this .cols = cols ;
68+ @ NTValue (key = "area" )
69+ public double [] getArea () {
70+ final double [] areas = new double [(int ) contours .size ()];
71+ for (int i = 0 ; i < contours .size (); i ++) {
72+ areas [i ] = contourArea (contours .get (i ));
73+ }
74+ return areas ;
3875 }
3976
40- public int getRows () {
41- return this .rows ;
77+ @ NTValue (key = "centerX" )
78+ public double [] getCenterX () {
79+ final double [] centers = new double [(int ) contours .size ()];
80+ final List <Rect > boundingBoxes = computeBoundingBoxes ();
81+ for (int i = 0 ; i < contours .size (); i ++) {
82+ centers [i ] = boundingBoxes .get (i ).x () + boundingBoxes .get (i ).width () / 2 ;
83+ }
84+ return centers ;
4285 }
4386
44- public int getCols () {
45- return this .cols ;
87+ @ NTValue (key = "centerY" )
88+ public double [] getCenterY () {
89+ final double [] centers = new double [(int ) contours .size ()];
90+ final List <Rect > boundingBoxes = computeBoundingBoxes ();
91+ for (int i = 0 ; i < contours .size (); i ++) {
92+ centers [i ] = boundingBoxes .get (i ).y () + boundingBoxes .get (i ).height () / 2 ;
93+ }
94+ return centers ;
95+ }
96+
97+ @ NTValue (key = "width" )
98+ public synchronized double [] getWidth () {
99+ final double [] widths = new double [(int ) contours .size ()];
100+ final List <Rect > boundingBoxes = computeBoundingBoxes ();
101+ for (int i = 0 ; i < contours .size (); i ++) {
102+ widths [i ] = boundingBoxes .get (i ).width ();
103+ }
104+ return widths ;
105+ }
106+
107+ @ NTValue (key = "height" )
108+ public synchronized double [] getHeights () {
109+ final double [] heights = new double [(int ) contours .size ()];
110+ final List <Rect > boundingBoxes = computeBoundingBoxes ();
111+ for (int i = 0 ; i < contours .size (); i ++) {
112+ heights [i ] = boundingBoxes .get (i ).height ();
113+ }
114+ return heights ;
46115 }
47116}
0 commit comments