15
15
#include < tagCustom48h12.h>
16
16
#include < tagStandard41h12.h>
17
17
#include < tagStandard52h13.h>
18
+ #include < opencv2/opencv.hpp>
18
19
19
20
using HammHist = std::array<int , 10 >;
20
21
using Eigen::AngleAxisd;
@@ -30,7 +31,7 @@ PluginAprilTag::PluginAprilTag(FrameBuffer *buffer,
30
31
std::shared_ptr<TeamTags> blue_team_tags,
31
32
std::shared_ptr<TeamTags> yellow_team_tags,
32
33
CMPattern::TeamSelector &blue_team_selector,
33
- CMPattern::TeamSelector &yellow_team_selector)
34
+ CMPattern::TeamSelector &yellow_team_selector, ConvexHullImageMask& mask )
34
35
: VisionPlugin(buffer), settings(new VarList(" AprilTag" )),
35
36
v_enable(new VarBool(" enable" , true )),
36
37
v_quad_size(new VarDouble(" quad size (mm)" , 70.0 )),
@@ -43,7 +44,8 @@ PluginAprilTag::PluginAprilTag(FrameBuffer *buffer,
43
44
camera_params (camera_params), blue_team_tags(blue_team_tags),
44
45
yellow_team_tags(yellow_team_tags),
45
46
blue_team_selector(blue_team_selector),
46
- yellow_team_selector(yellow_team_selector) {
47
+ yellow_team_selector(yellow_team_selector),
48
+ image_mask(mask){
47
49
48
50
v_family.reset (new VarStringEnum (" Tag Family" , " tagCircle21h7" ));
49
51
v_family->addItem (" tag36h11" );
@@ -74,11 +76,13 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
74
76
if (!v_enable->getBool ()) {
75
77
return ProcessingOk;
76
78
}
79
+ image_mask.lock ();
77
80
if (!tag_family || v_family->getString () != tag_family->name ) {
78
81
makeTagFamily ();
79
82
if (!tag_family) {
80
83
std::cerr << " AprilTag: Failed to create tag family '"
81
84
<< v_family->getString () << " '\n " ;
85
+ image_mask.unlock ();
82
86
return ProcessingFailed;
83
87
}
84
88
@@ -91,6 +95,7 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
91
95
makeTagDetector ();
92
96
if (!tag_detector) {
93
97
std::cerr << " AprilTag: Failed to create tag detector\n " ;
98
+ image_mask.unlock ();
94
99
return ProcessingFailed;
95
100
}
96
101
}
@@ -104,20 +109,55 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
104
109
reinterpret_cast <Image<raw8> *>(data->map .get (" greyscale" ));
105
110
if (img_greyscale == nullptr ) {
106
111
std::cerr << " AprilTag: No greyscale image in frame data\n " ;
112
+ image_mask.unlock ();
107
113
return ProcessingFailed;
108
114
}
109
115
116
+ Image<raw8> *img_masked;
117
+ if ((img_masked = reinterpret_cast <Image<raw8> *>(
118
+ data->map .get (" masked" ))) == nullptr ) {
119
+ img_masked = reinterpret_cast <Image<raw8> *>(
120
+ data->map .insert (" masked" , new Image<raw8>()));
121
+ }
122
+ img_masked->allocate (img_greyscale->getWidth (), img_greyscale->getHeight ());
123
+
124
+ // TODO(dschwab): In the interest of speed on hi-res images, it
125
+ // might be useful to compute the bounding box of the convex hull
126
+ // and if it is x% smaller than original image, apply the mask and
127
+ // then crop the image so that the detection needs to work with less
128
+ // pixels.
129
+
130
+ Image<raw8> *input_image = img_greyscale;
131
+ const auto & hull = image_mask.getConvexHull ();
132
+ // there must be at least 3 points in the convex hull for the mask to have restricted
133
+ // the image size. If there are less than 3 skip masking the
134
+ // greyscale image.
135
+ if (hull.getNumPoints () >= 3 ) {
136
+ const auto &mask = image_mask.getMask ();
137
+ cv::Mat cv_mask (mask.getHeight (), mask.getWidth (), CV_8UC1, mask.getData ());
138
+ cv::Mat cv_greyscale (img_greyscale->getHeight (), img_greyscale->getWidth (),
139
+ CV_8UC1, img_greyscale->getData ());
140
+ cv::Mat cv_masked (img_masked->getHeight (), img_masked->getWidth (), CV_8UC1, img_masked->getData ());
141
+
142
+ cv::Mat& input1 = cv_mask;
143
+ cv::Mat& input2 = cv_greyscale;
144
+ cv::Mat& output = cv_masked;
145
+ cv::bitwise_and (input1, input2, output);
146
+
147
+ input_image = img_masked;
148
+ }
149
+
110
150
const int maxiters = v_iters->getInt ();
111
151
for (int iter = 0 ; iter < maxiters; iter++) {
112
152
if (maxiters > 1 ) {
113
153
std::cout << " iter " << iter + 1 << " / " << maxiters << " \n " ;
114
154
}
115
155
116
156
// zero-copy. Just use the already allocated buffer data.
117
- image_u8_t im{.width = img_greyscale ->getWidth (),
118
- .height = img_greyscale ->getHeight (),
119
- .stride = img_greyscale ->getWidth (),
120
- .buf = img_greyscale ->getData ()};
157
+ image_u8_t im{.width = input_image ->getWidth (),
158
+ .height = input_image ->getHeight (),
159
+ .stride = input_image ->getWidth (),
160
+ .buf = input_image ->getData ()};
121
161
122
162
detections.reset (apriltag_detector_detect (tag_detector.get (), &im));
123
163
data->map .update (" apriltag_detections" , detections.get ());
@@ -229,6 +269,7 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
229
269
}
230
270
}
231
271
272
+ image_mask.unlock ();
232
273
return ProcessingOk;
233
274
}
234
275
0 commit comments