Skip to content

Commit a6b3787

Browse files
committed
✨ Use masked image in apriltags detector
1 parent dce2e36 commit a6b3787

File tree

3 files changed

+53
-8
lines changed

3 files changed

+53
-8
lines changed

src/app/plugins/plugin_apriltag.cpp

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <tagCustom48h12.h>
1616
#include <tagStandard41h12.h>
1717
#include <tagStandard52h13.h>
18+
#include <opencv2/opencv.hpp>
1819

1920
using HammHist = std::array<int, 10>;
2021
using Eigen::AngleAxisd;
@@ -30,7 +31,7 @@ PluginAprilTag::PluginAprilTag(FrameBuffer *buffer,
3031
std::shared_ptr<TeamTags> blue_team_tags,
3132
std::shared_ptr<TeamTags> yellow_team_tags,
3233
CMPattern::TeamSelector &blue_team_selector,
33-
CMPattern::TeamSelector &yellow_team_selector)
34+
CMPattern::TeamSelector &yellow_team_selector, ConvexHullImageMask& mask)
3435
: VisionPlugin(buffer), settings(new VarList("AprilTag")),
3536
v_enable(new VarBool("enable", true)),
3637
v_quad_size(new VarDouble("quad size (mm)", 70.0)),
@@ -43,7 +44,8 @@ PluginAprilTag::PluginAprilTag(FrameBuffer *buffer,
4344
camera_params(camera_params), blue_team_tags(blue_team_tags),
4445
yellow_team_tags(yellow_team_tags),
4546
blue_team_selector(blue_team_selector),
46-
yellow_team_selector(yellow_team_selector) {
47+
yellow_team_selector(yellow_team_selector),
48+
image_mask(mask){
4749

4850
v_family.reset(new VarStringEnum("Tag Family", "tagCircle21h7"));
4951
v_family->addItem("tag36h11");
@@ -74,11 +76,13 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
7476
if (!v_enable->getBool()) {
7577
return ProcessingOk;
7678
}
79+
image_mask.lock();
7780
if (!tag_family || v_family->getString() != tag_family->name) {
7881
makeTagFamily();
7982
if (!tag_family) {
8083
std::cerr << "AprilTag: Failed to create tag family '"
8184
<< v_family->getString() << "'\n";
85+
image_mask.unlock();
8286
return ProcessingFailed;
8387
}
8488

@@ -91,6 +95,7 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
9195
makeTagDetector();
9296
if (!tag_detector) {
9397
std::cerr << "AprilTag: Failed to create tag detector\n";
98+
image_mask.unlock();
9499
return ProcessingFailed;
95100
}
96101
}
@@ -104,20 +109,55 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
104109
reinterpret_cast<Image<raw8> *>(data->map.get("greyscale"));
105110
if (img_greyscale == nullptr) {
106111
std::cerr << "AprilTag: No greyscale image in frame data\n";
112+
image_mask.unlock();
107113
return ProcessingFailed;
108114
}
109115

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+
110150
const int maxiters = v_iters->getInt();
111151
for (int iter = 0; iter < maxiters; iter++) {
112152
if (maxiters > 1) {
113153
std::cout << "iter " << iter + 1 << " / " << maxiters << "\n";
114154
}
115155

116156
// 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()};
121161

122162
detections.reset(apriltag_detector_detect(tag_detector.get(), &im));
123163
data->map.update("apriltag_detections", detections.get());
@@ -229,6 +269,7 @@ ProcessResult PluginAprilTag::process(FrameData *data, RenderOptions *options) {
229269
}
230270
}
231271

272+
image_mask.unlock();
232273
return ProcessingOk;
233274
}
234275

src/app/plugins/plugin_apriltag.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef PLUGIN_APRILTAG_H
22
#define PLUGIN_APRILTAG_H
33

4+
#include "convex_hull_image_mask.h"
45
#include "camera_calibration.h"
56
#include "cmpattern_teamdetector.h"
67
#include "team_tags.h"
@@ -36,13 +37,15 @@ class PluginAprilTag : public VisionPlugin {
3637
const std::shared_ptr<TeamTags> yellow_team_tags;
3738
CMPattern::TeamSelector &blue_team_selector;
3839
CMPattern::TeamSelector &yellow_team_selector;
40+
ConvexHullImageMask& image_mask;
3941

4042
public:
4143
PluginAprilTag(FrameBuffer *buffer, const CameraParameters &camera_params,
4244
std::shared_ptr<TeamTags> blue_team_tags,
4345
std::shared_ptr<TeamTags> yellow_team_tags,
4446
CMPattern::TeamSelector &blue_team_selector,
45-
CMPattern::TeamSelector &yellow_team_selector);
47+
CMPattern::TeamSelector &yellow_team_selector,
48+
ConvexHullImageMask& mask);
4649
~PluginAprilTag() override = default;
4750

4851
ProcessResult process(FrameData *data, RenderOptions *options) override;
@@ -52,6 +55,7 @@ class PluginAprilTag : public VisionPlugin {
5255
std::string getName() override;
5356

5457
private:
58+
5559
void makeTagFamily();
5660
void makeTagDetector();
5761
};

src/app/stacks/stack_robocup_ssl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ StackRoboCupSSL::StackRoboCupSSL(
8181
stack.push_back(new PluginGreyscale(_fb));
8282

8383
#ifdef APRILTAG
84-
stack.push_back(new PluginAprilTag(_fb, *camera_parameters, _global_blue_team_tags, _global_yellow_team_tags, *global_team_selector_blue, *global_team_selector_yellow));
84+
stack.push_back(new PluginAprilTag(_fb, *camera_parameters, _global_blue_team_tags, _global_yellow_team_tags, *global_team_selector_blue, *global_team_selector_yellow, *_image_mask));
8585
#endif
8686

8787
stack.push_back(new PluginRunlengthEncode(_fb));

0 commit comments

Comments
 (0)