OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
BlobExtractionDemo.cpp
Go to the documentation of this file.
1 
11 // Copyright 2016 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 // Internal Includes
26 #include <BlobExtractor.h>
27 #include <BlobParams.h>
29 #include <OptionalStream.h>
30 #include <ParseBlobParams.h>
31 #include <cvUtils.h>
32 
33 // Library/third-party includes
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>
39 
40 // Standard includes
41 #include <cmath>
42 #include <fstream>
43 #include <iomanip>
44 #include <iostream>
45 #include <random>
46 #include <sstream>
47 
48 namespace osvr {
49 namespace vbtracker {
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) {
55  if (showImages) {
56  cv::namedWindow(title);
57  cv::imshow(title, img);
58  }
59  }
60 
61  void handleImage(std::string const &fn, cv::Mat color, cv::Mat gray,
62  bool pause, bool showImages = true) {
63  BlobParams &p = g_blobParams;
64 
66  std::cout << "Handling image " << fn << std::endl;
67 
68  // showImage("Original", gray);
69  EdgeHoleBasedLedExtractor extractor{g_holeExtractorParams};
70  extractor(gray, p, pause);
71 
73  showImage("Edges", extractor.getEdgeDetectedImage(), showImages);
74  cv::imwrite(fn + ".edge.png", extractor.getEdgeDetectedImage());
75 
76  showImage("Binarized Contour Input",
77  extractor.getEdgeDetectedBinarizedImage(), showImages);
78  cv::imwrite(fn + ".binarized.png",
79  extractor.getEdgeDetectedBinarizedImage());
80 
82 
85  cv::Mat highlightedContours =
86  drawColoredContours(gray, extractor.getContours());
87 
88  // Figure out where to put the text - further along the ray
89  // that passes from the image center through the reject center, to try
90  // to get it "away from the crowd"
91  {
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;
95 
96  auto imageSize = highlightedContours.size();
97  auto imageCenter =
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,
102  1.3);
103  auto computeTextLocation = [&](cv::Point2d rejectCenter,
104  std::string const &text) {
105  auto centerToRejectVec = rejectCenter - imageCenter;
106  auto textPoint =
107  cv::Point(centerToRejectVec * vectorScaleDistribution(mt) +
108  imageCenter);
109 
112  auto textSize = cv::getTextSize(text, FONT_FACE, FONT_SCALE,
113  FONT_THICKNESS, nullptr);
114 
115  auto textOffset =
116  cv::Point(textSize.width / 2, textSize.height / 2);
117  return textPoint - textOffset;
118  };
119 
121  for (auto &reject : extractor.getRejectList()) {
122  EdgeHoleBasedLedExtractor::ContourId contourId = 0;
123  RejectReason reason;
124  cv::Point2d center;
125  std::tie(contourId, reason, center) = reject;
126 
127  if (!g_showAllRejects &&
128  (osvr::vbtracker::RejectReason::Area == reason ||
129  RejectReason::CenterPointValue == reason)) {
130  // Skip drawing these, they clutter the display
131  continue;
132  }
133 
134  drawSubpixelPoint(highlightedContours, center,
135  cv::Scalar(0, 0, 0), 1.2);
136  std::ostringstream os;
137  // os << "[";
138  os << contourId;
139  switch (reason) {
140  case RejectReason::Area:
141  os << ":A";
142  break;
143  case RejectReason::CenterPointValue:
144  os << ":V";
145  break;
146  case RejectReason::Circularity:
147  os << ":CIRC";
148  break;
149  case RejectReason::Convexity:
150  os << ":CONV";
151  break;
152  default:
153  break;
154  }
155  // os << "]";
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);
160  }
161  }
162 
163  showImage("Selected contours", highlightedContours, showImages);
164  cv::imwrite(fn + ".contours.png", highlightedContours);
165  if (pause) {
166  cv::waitKey();
167  }
168  }
169  void handleImage(std::string const &fn, bool pause) {
170 
172  std::cout << "Loading image " << fn << std::endl;
173  cv::Mat color = cv::imread(fn, cv::IMREAD_COLOR);
174  if (!color.data) {
175  std::cerr << "Could not load image!" << std::endl;
176  return;
177  }
178 
179  cv::Mat gray;
180  cv::cvtColor(color, gray, cv::COLOR_BGR2GRAY);
181 
182  if (!gray.data) {
183  std::cerr << "Conversion to gray failed?" << std::endl;
184  return;
185  }
186  // showImage("Original", gray);
187  handleImage(fn, color, gray, pause);
188  }
189 } // namespace vbtracker
190 } // namespace osvr
191 
192 void processAVI(std::string const &fn) {
193  cv::VideoCapture capture;
194  capture.open(fn);
195  if (!capture.isOpened()) {
196  std::cerr << "Could not open video file " << fn << std::endl;
197  return;
198  }
199  std::size_t i = 0;
200  cv::Mat frame;
201  cv::Mat frameGray;
202  capture >> frame;
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,
210  false);
211  i++;
212  }
213 }
214 
215 void tryLoadingConfigFile() {
216  Json::Value root;
217  static const auto FN = "blobDemoConfig.json";
218  {
219  std::ifstream configStream{"blobDemoConfig.json"};
220  if (!configStream) {
221  std::cout << "Note: Did not find or could not open config file "
222  << FN << ", just using defaults..." << std::endl;
223  return;
224  }
225  Json::Reader reader;
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;
231  return;
232  }
233  }
234  std::cout << "Opened config file " << FN << " and parsed as JSON..."
235  << std::endl;
236  using namespace osvr::vbtracker;
237  if (root.isMember("blobParams")) {
238  std::cout << "Found \"blobParams\" element, parsing..." << std::endl;
239  parseBlobParams(root["blobParams"], g_blobParams);
240  }
241  if (root.isMember("extractParams")) {
242  std::cout << "Found \"extractParams\" element, parsing..." << std::endl;
243  parseEdgeHoleExtractorParams(root["extractParams"],
244  g_holeExtractorParams);
245  }
246  getOptionalParameter(g_showAllRejects, root, "showAllRejects");
247 }
248 
249 int main(int argc, char *argv[]) {
251  tryLoadingConfigFile();
253  if (argc == 2) {
254  auto fn = std::string{argv[1]};
255  if (fn.find(".avi") != std::string::npos &&
256  fn.find(".avi.") == std::string::npos) {
258  processAVI(fn);
259  return 0;
260  }
261  }
262  bool pause = (argc < 3);
263  for (int arg = 1; arg < argc; ++arg) {
264  osvr::vbtracker::handleImage(argv[arg], pause);
265  }
266  return 0;
267 }
int main(int argc, char *argv[])
Header.
Header.
double Scalar
Common scalar type.