30 #ifdef OSVR_USE_REALTIME_LAPLACIAN
46 static const std::uint8_t MAX_JPG_EDGEDETECT_NOISE = 20;
47 static const auto PREFIX =
"[EdgeHoleBasedLedExtractor] ";
48 EdgeHoleParams::EdgeHoleParams()
49 : preEdgeDetectionBlurSize(3), laplacianKSize(3), laplacianScale(5),
50 edgeDetectErosion(false),
51 erosionKernelValue(MAX_JPG_EDGEDETECT_NOISE),
52 postEdgeDetectionBlur(true), postEdgeDetectionBlurSize(3),
53 postEdgeDetectionBlurThreshold(80) {}
55 static const int EDGE_DETECT_DEST_DEPTH = CV_8U;
57 EdgeHoleBasedLedExtractor::EdgeHoleBasedLedExtractor(
58 EdgeHoleParams
const &extractorParams)
59 : extParams_(extractorParams)
60 #ifdef OSVR_USE_REALTIME_LAPLACIAN
62 laplacianImpl_(new RealtimeLaplacian(EDGE_DETECT_DEST_DEPTH,
63 extParams_.laplacianKSize,
64 extParams_.laplacianScale))
68 compressionArtifactRemovalKernel_ =
69 cv::Mat::ones(cv::Size(3, 3), CV_8U) *
70 static_cast<std::uint8_t
>(extractorParams.erosionKernelValue);
72 compressionArtifactRemoval_ = cv::createMorphologyFilter(
73 cv::MORPH_ERODE, CV_8U, compressionArtifactRemovalKernel_);
77 namespace tracing = ::osvr::common::tracing;
79 :
public tracing::TracingRegion<tracing::MainTracePolicy> {
82 : tracing::TracingRegion<tracing::MainTracePolicy>(
89 bool verboseBlobOutput) {
96 verbose_ = verboseBlobOutput;
104 return measurements_;
108 minBeaconCenterVal_ =
109 static_cast<std::uint8_t
>(thresholdInfo.minThreshold);
116 cv::GaussianBlur(gray_, blurred_,
121 #ifdef OSVR_USE_REALTIME_LAPLACIAN
122 laplacianImpl_->apply(blurred_, edge_);
134 compressionArtifactRemoval_->apply(edge_, edge_);
136 cv::erode(edge_, edge_, compressionArtifactRemovalKernel_);
142 cv::GaussianBlur(edge_, edgeTemp_,
146 cv::threshold(edgeTemp_, edgeBinary_,
150 cv::threshold(edge_, edgeBinary_,
162 edgeBinary_.copyTo(binTemp_);
163 consumeHolesOfConnectedComponents(
164 binTemp_, contoursTempStorage_, hierarchyTempStorage_,
165 [&](ContourType &&contour) { checkBlob(std::move(contour), p); });
166 return measurements_;
171 void EdgeHoleBasedLedExtractor::reset() {
173 measurements_.clear();
177 void EdgeHoleBasedLedExtractor::checkBlob(ContourType &&contour,
178 BlobParams
const &p) {
180 auto data = getBlobDataFromContour(contour);
181 auto debugStream = [&] {
182 #ifdef OSVR_DEBUG_CONTOUR_CONDITIONS
183 return outputIf(std::cout,
true);
185 return outputIf(std::cout, verbose_);
188 auto myId = contourId_;
190 debugStream() <<
"\nContour ID " << myId <<
" centered at "
192 debugStream() <<
" - diameter: " << data.diameter;
193 debugStream() <<
" - area: " << data.area;
194 debugStream() <<
" - circularity: " << data.circularity;
195 debugStream() <<
" - bounding box size: " << data.bounds.size();
196 if (data.area < p.minArea) {
197 debugStream() <<
"Reject based on area: " << data.area <<
" < "
198 << p.minArea <<
"\n";
200 addToRejectList(myId, RejectReason::Area, data);
208 cv::getRectSubPix(gray_, cv::Size(1, 1),
209 castPointToFloat(data.center), patch);
210 auto centerPointValue = patch.at<
unsigned char>(0, 0);
211 if (centerPointValue < minBeaconCenterVal_) {
212 debugStream() <<
"Reject based on center point value: "
213 << int(centerPointValue) <<
" < "
214 << int(minBeaconCenterVal_) <<
"\n";
215 addToRejectList(myId, RejectReason::CenterPointValue, data);
220 if (p.filterByCircularity) {
221 if (data.circularity < p.minCircularity) {
223 <<
"Reject based on circularity: " << data.circularity
224 <<
" < " << p.minCircularity <<
"\n";
225 addToRejectList(myId, RejectReason::Circularity, data);
229 if (p.filterByConvexity) {
230 auto convexity = getConvexity(contour, data.area);
231 debugStream() <<
" - convexity: " << convexity;
232 if (convexity < p.minConvexity) {
233 debugStream() <<
"Reject based on convexity: " << convexity
234 <<
" < " << p.minConvexity <<
"\n";
235 addToRejectList(myId, RejectReason::Convexity, data);
241 debugStream() <<
"Accepted!\n";
244 LedMeasurement(castPointToFloat(data.center),
245 static_cast<float>(data.diameter), gray_.size(),
246 static_cast<float>(data.area));
247 newMeas.circularity =
static_cast<float>(data.circularity);
248 newMeas.setBoundingBox(data.bounds);
250 measurements_.emplace_back(std::move(newMeas));
252 contours_.emplace_back(std::move(contour));
bool postEdgeDetectionBlur
int postEdgeDetectionBlurSize
int postEdgeDetectionBlurThreshold
int preEdgeDetectionBlurSize
double absoluteMinThreshold
Blob detection configuration parameters.