34 #include <json/reader.h>
35 #include <json/value.h>
36 #include <opencv2/core/core.hpp>
37 #include <opencv2/highgui/highgui.hpp>
38 #include <opencv2/imgproc/imgproc.hpp>
50 static bool g_showAllRejects =
false;
51 static EdgeHoleParams g_holeExtractorParams{};
52 static BlobParams g_blobParams{};
53 void showImage(std::string
const &title, cv::Mat
const &img,
54 bool showImages =
true) {
56 cv::namedWindow(title);
57 cv::imshow(title, img);
61 void handleImage(std::string
const &fn, cv::Mat color, cv::Mat gray,
62 bool pause,
bool showImages =
true) {
63 BlobParams &p = g_blobParams;
66 std::cout <<
"Handling image " << fn << std::endl;
69 EdgeHoleBasedLedExtractor extractor{g_holeExtractorParams};
70 extractor(gray, p, pause);
73 showImage(
"Edges", extractor.getEdgeDetectedImage(), showImages);
74 cv::imwrite(fn +
".edge.png", extractor.getEdgeDetectedImage());
76 showImage(
"Binarized Contour Input",
77 extractor.getEdgeDetectedBinarizedImage(), showImages);
78 cv::imwrite(fn +
".binarized.png",
79 extractor.getEdgeDetectedBinarizedImage());
85 cv::Mat highlightedContours =
86 drawColoredContours(gray, extractor.getContours());
92 static const auto FONT_FACE = cv::FONT_HERSHEY_PLAIN;
93 static const auto FONT_SCALE = 0.8;
94 static const int FONT_THICKNESS = 1;
96 auto imageSize = highlightedContours.size();
98 cv::Point2d(imageSize.width / 2, imageSize.height / 2);
99 std::random_device rd;
100 std::mt19937 mt(rd());
101 std::uniform_real_distribution<double> vectorScaleDistribution(1.1,
103 auto computeTextLocation = [&](cv::Point2d rejectCenter,
104 std::string
const &text) {
105 auto centerToRejectVec = rejectCenter - imageCenter;
107 cv::Point(centerToRejectVec * vectorScaleDistribution(mt) +
112 auto textSize = cv::getTextSize(text, FONT_FACE, FONT_SCALE,
113 FONT_THICKNESS,
nullptr);
116 cv::Point(textSize.width / 2, textSize.height / 2);
117 return textPoint - textOffset;
121 for (
auto &reject : extractor.getRejectList()) {
122 EdgeHoleBasedLedExtractor::ContourId contourId = 0;
125 std::tie(contourId, reason, center) = reject;
127 if (!g_showAllRejects &&
128 (osvr::vbtracker::RejectReason::Area == reason ||
129 RejectReason::CenterPointValue == reason)) {
134 drawSubpixelPoint(highlightedContours, center,
136 std::ostringstream os;
140 case RejectReason::Area:
143 case RejectReason::CenterPointValue:
146 case RejectReason::Circularity:
149 case RejectReason::Convexity:
156 auto text = os.str();
157 cv::putText(highlightedContours, text,
158 computeTextLocation(center, text), FONT_FACE,
159 FONT_SCALE,
cv::Scalar(0, 0, 255), FONT_THICKNESS);
163 showImage(
"Selected contours", highlightedContours, showImages);
164 cv::imwrite(fn +
".contours.png", highlightedContours);
169 void handleImage(std::string
const &fn,
bool pause) {
172 std::cout <<
"Loading image " << fn << std::endl;
173 cv::Mat color = cv::imread(fn, cv::IMREAD_COLOR);
175 std::cerr <<
"Could not load image!" << std::endl;
180 cv::cvtColor(color, gray, cv::COLOR_BGR2GRAY);
183 std::cerr <<
"Conversion to gray failed?" << std::endl;
187 handleImage(fn, color, gray, pause);
192 void processAVI(std::string
const &fn) {
193 cv::VideoCapture capture;
195 if (!capture.isOpened()) {
196 std::cerr <<
"Could not open video file " << fn << std::endl;
203 while (capture.read(frame)) {
204 std::ostringstream os;
205 os << fn <<
"." << std::setw(4) << std::setfill(
'0') << i <<
".png";
206 auto pngFileName = os.str();
207 cv::imwrite(pngFileName, frame);
208 cv::cvtColor(frame, frameGray, cv::COLOR_BGR2GRAY);
209 osvr::vbtracker::handleImage(pngFileName, frame, frameGray,
false,
215 void tryLoadingConfigFile() {
217 static const auto FN =
"blobDemoConfig.json";
219 std::ifstream configStream{
"blobDemoConfig.json"};
221 std::cout <<
"Note: Did not find or could not open config file "
222 << FN <<
", just using defaults..." << std::endl;
226 if (!reader.parse(configStream, root)) {
227 std::cout <<
"Note: Opened, but could not parse as valid JSON ["
228 << reader.getFormattedErrorMessages()
229 <<
"], the config file " << FN
230 <<
", just using the defaults..." << std::endl;
234 std::cout <<
"Opened config file " << FN <<
" and parsed as JSON..."
237 if (root.isMember(
"blobParams")) {
238 std::cout <<
"Found \"blobParams\" element, parsing..." << std::endl;
239 parseBlobParams(root[
"blobParams"], g_blobParams);
241 if (root.isMember(
"extractParams")) {
242 std::cout <<
"Found \"extractParams\" element, parsing..." << std::endl;
243 parseEdgeHoleExtractorParams(root[
"extractParams"],
244 g_holeExtractorParams);
246 getOptionalParameter(g_showAllRejects, root,
"showAllRejects");
249 int main(
int argc,
char *argv[]) {
251 tryLoadingConfigFile();
254 auto fn = std::string{argv[1]};
255 if (fn.find(
".avi") != std::string::npos &&
256 fn.find(
".avi.") == std::string::npos) {
262 bool pause = (argc < 3);
263 for (
int arg = 1; arg < argc; ++arg) {
264 osvr::vbtracker::handleImage(argv[arg], pause);
double Scalar
Common scalar type.