SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
AppDemoVideo.cpp
Go to the documentation of this file.
1 /**
2  * \file AppDemoVideo.cpp
3  * \brief All video capturing and video tracking functions are in here.
4  * \date August 2019
5  * \authors Marcus Hudritsch
6  * \copyright http://opensource.org/licenses/GPL-3.0
7  * \remarks Please use clangformat to format the code. See more code style on
8  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
9  */
10 
11 #include <AppDemoSceneView.h>
12 #include <AppCommon.h>
13 #include <AppDemoSceneID.h>
14 #include <SLScene.h>
15 #include <SLSceneView.h>
16 #include <CVCapture.h>
17 #include <CVTracked.h>
18 #include <CVTrackedAruco.h>
19 #include <SLGLTexture.h>
20 #include <CVCalibrationEstimator.h>
21 #include <GlobalTimer.h>
22 #include <Profiler.h>
23 
24 #ifndef SL_EMSCRIPTEN
25 # include <FtpUtils.h>
26 #endif
27 
28 //-----------------------------------------------------------------------------
29 /*! Global pointer for the video texture defined in AppDemoLoad for video scenes
30  It gets updated in the following onUpdateTracking routine
31  */
33 
34 /*! Global pointer for a gVideoTracker that is set in AppDemoLoad for video scenes
35  It gets updated in the following onUpdateTracking routine
36  */
38 
39 /*! Global pointer to a node that from witch the gVideoTracker changes the pose.
40  it gets updated in the following onUpdateTracking routine
41  */
43 
44 //-----------------------------------------------------------------------------
45 /*! always update scene camera fovV from calibration because the calibration
46  may have been adapted in adjustForSL after a change of aspect ratio!
47  Attention: The active scene view camera may be a different one that the
48  tracking camera but we have to update the tracking camera only!
49 */
51 {
53 
54  if (gVideoTrackedNode && typeid(*gVideoTrackedNode) == typeid(SLCamera))
55  {
56  SLCamera* trackingCam = dynamic_cast<SLCamera*>(gVideoTrackedNode);
57  trackingCam->fov(ac->calibration.cameraFovVDeg());
58  }
59 }
60 //-----------------------------------------------------------------------------
61 // CVCalibrationEstimator* calibrationEstimator = nullptr;
63 {
65 
66  AppDemoSceneView* adSv = dynamic_cast<AppDemoSceneView*>(sv);
67  static bool processedCalibResult = false;
68  try
69  {
71  {
73  CVCapture::instance()->activeCamSizeIndex,
74  ac->mirrorH(),
75  ac->mirrorV(),
76  ac->type(),
81 
82  // clear grab request from sceneview
83  adSv->grab = false;
84  processedCalibResult = false;
85  }
86 
87  if (AppCommon::calibrationEstimator->isStreaming())
88  {
90  CVCapture::instance()->lastFrameGray,
91  adSv->grab);
92  // reset grabbing switch
93  adSv->grab = false;
94 
95  stringstream ss;
96  ss << "Click on the screen to create a calibration photo. Created "
99  s->info(ss.str());
100  }
101  else if (AppCommon::calibrationEstimator->isBusyExtracting())
102  {
103  // also reset grabbing, user has to click again
104  adSv->grab = false;
106  CVCapture::instance()->lastFrameGray,
107  false);
108  s->info("Busy extracting corners, please wait with grabbing ...");
109  }
110  else if (AppCommon::calibrationEstimator->isCalculating())
111  {
113  CVCapture::instance()->lastFrameGray,
114  false);
115  s->info("Calculating calibration, please wait ...");
116  }
117  else if (AppCommon::calibrationEstimator->isDone())
118  {
119  if (!processedCalibResult)
120  {
121  if (AppCommon::calibrationEstimator->calibrationSuccessful())
122  {
123  processedCalibResult = true;
125 
126  std::string computerInfo = Utils::ComputerInfos::get();
127  string mainCalibFilename = "camCalib_" + computerInfo + "_main.xml";
128  string scndCalibFilename = "camCalib_" + computerInfo + "_scnd.xml";
129  std::string errorMsg;
130  if (ac->calibration.save(AppCommon::calibFilePath, mainCalibFilename))
131  {
132 
133 #ifndef SL_EMSCRIPTEN
135  mainCalibFilename,
140  errorMsg))
141  {
142  Utils::log("WAIApp", errorMsg.c_str());
143  }
144 #endif
145  }
146  else
147  {
148  errorMsg += " Saving calibration failed!";
149  }
150 
151  s->info("Calibration successful." + errorMsg);
152  }
153  else
154  {
155  s->info(("Calibration failed!"));
156  }
157  }
158  }
159  else if (AppCommon::calibrationEstimator->isDoneCaptureAndSave())
160  {
161  s->info(("Capturing done!"));
162  }
163  }
165  {
166  log("SLProject", e.what());
167  s->info("Exception during calibration! Please restart!");
168  }
169 }
170 
171 //-----------------------------------------------------------------------------
172 //! logic that ensures that we have a valid calibration state
174 {
176 
177  // we have to make sure calibration process is stopped if someone stops calibrating
179  {
182  }
183 
184  if (ac->calibration.state() == CS_uncalibrated)
185  {
186  // Try to read device lens and sensor information
187  string strF = AppCommon::deviceParameter["DeviceLensFocalLength"];
188  string strW = AppCommon::deviceParameter["DeviceSensorPhysicalSizeW"];
189  string strH = AppCommon::deviceParameter["DeviceSensorPhysicalSizeH"];
190  if (!strF.empty() && !strW.empty() && !strH.empty())
191  {
192  float devF = strF.empty() ? 0.0f : stof(strF);
193  float devW = strW.empty() ? 0.0f : stof(strW);
194  float devH = strH.empty() ? 0.0f : stof(strH);
195 
196  // Changes the state to CS_guessed
197  ac->calibration = CVCalibration(devW,
198  devH,
199  devF,
200  cv::Size(CVCapture::instance()->lastFrame.cols,
202  ac->mirrorH(),
203  ac->mirrorV(),
204  ac->type(),
206  }
207  else
208  {
209  // make a guess using frame size and a guessed field of view
210  ac->calibration = CVCalibration(cv::Size(CVCapture::instance()->lastFrame.cols,
212  60.0,
213  ac->mirrorH(),
214  ac->mirrorV(),
215  ac->type(),
217  }
218  }
219 }
220 //-----------------------------------------------------------------------------
221 //! Implements the update per frame for video update and feature tracking
222 /*! This routine is called once per frame before any other update within the
223  the main rendering loop (see: AppDemoMainGLFW::onPaint or GLES3View::onDrawFrame).
224  See the documentation within SLCVTracked and in all of its inheritants.
225 */
227 {
229 
230  if (AppCommon::sceneViews.empty())
231  return false;
232 
235 
236  if (CVCapture::instance()->videoType() != VT_NONE &&
237  !CVCapture::instance()->lastFrame.empty())
238  {
239  SLfloat trackingTimeStartMS = GlobalTimer::timeMS();
240 
242 
245  {
247  }
248  else
249  {
251  // Attention: Always update scene camera fovV from calibration because the calibration may have
252  // been adapted in adjustForSL after a change of aspect ratio!
253  // The active scene view camera may be a different one that the tracking camera
254  // but we have to update the tracking camera only!
256 
258  {
259  bool foundPose = gVideoTracker->track(CVCapture::instance()->lastFrameGray,
260  CVCapture::instance()->lastFrame,
261  &ac->calibration);
262  if (foundPose)
263  {
264  // clang-format off
265  // convert matrix type CVMatx44f to SLMat4f
267  SLMat4f glOVM(cvOVM.val[0], cvOVM.val[1], cvOVM.val[2], cvOVM.val[3],
268  cvOVM.val[4], cvOVM.val[5], cvOVM.val[6], cvOVM.val[7],
269  cvOVM.val[8], cvOVM.val[9], cvOVM.val[10],cvOVM.val[11],
270  cvOVM.val[12],cvOVM.val[13],cvOVM.val[14],cvOVM.val[15]);
271  // clang-format on
272 
273  // set the object matrix depending if the
274  // tracked node is attached to a camera or not
275  if (typeid(*gVideoTrackedNode) == typeid(SLCamera))
276  {
277  gVideoTrackedNode->om(glOVM.inverted());
279  }
280  else
281  {
282  // see comments in CVTracked::calcObjectMatrix
283  gVideoTrackedNode->om(sv->camera()->om() * glOVM);
285  }
286  }
287  else
289  }
290 
291  // Update info text only for chessboard scene
296  {
297  SLfloat fovH = ac->calibration.cameraFovHDeg();
299  stringstream ss; // info line text
300  ss << "Tracking Chessboard on " << (CVCapture::instance()->videoType() == VT_MAIN ? "main " : "scnd. ") << "camera. ";
301  if (ac->calibration.state() == CS_calibrated)
302  ss << "FOVH: " << fovH << ", error: " << err;
303  else
304  ss << "Not calibrated. FOVH guessed: " << fovH << " degrees.";
305  s->info(ss.str());
306  }
307  }
308 
309  //...................................................................
310  // copy image to video texture
311  if (gVideoTexture)
312  {
313  if (ac->calibration.state() == CS_calibrated && ac->showUndistorted())
314  {
315  CVMat undistorted;
316  ac->calibration.remap(CVCapture::instance()->lastFrame, undistorted);
317 
318  // CVCapture::instance()->gVideoTexture()->copyVideoImage(undistorted.cols,
319  gVideoTexture->copyVideoImage(undistorted.cols,
320  undistorted.rows,
322  undistorted.data,
323  undistorted.isContinuous(),
324  true);
325  }
326  else
327  {
328  // CVCapture::instance()->gVideoTexture()->copyVideoImage(CVCapture::instance()->lastFrame.cols,
333  CVCapture::instance()->lastFrame.isContinuous(),
334  true);
335  }
336  }
337  else
338  SL_WARN_MSG("No video texture to copy to.");
339 
340 #ifndef SL_EMSCRIPTEN
341  CVTracked::trackingTimesMS.set(GlobalTimer::timeMS() - trackingTimeStartMS);
342 #endif
343 
344  return true;
345  }
346 
347  return false;
348 }
349 //-----------------------------------------------------------------------------
The AppCommon class holds the top-level instances of the app-demo.
Definition of scene IDs in the demo app.
@ SID_VideoTrackChessScnd
@ SID_VideoCalibrateScnd
@ SID_VideoCalibrateMain
@ SID_VideoTrackChessMain
bool onUpdateVideo()
Implements the update per frame for video update and feature tracking.
SLNode * gVideoTrackedNode
SLGLTexture * gVideoTexture
void ensureValidCalibration(CVCamera *ac, SLSceneView *sv)
logic that ensures that we have a valid calibration state
void updateTrackingSceneCamera(CVCamera *ac)
CVTracked * gVideoTracker
void runCalibrationEstimator(CVCamera *ac, SLScene *s, SLSceneView *sv)
@ CS_calibrated
The camera is calibrated.
Definition: CVCalibration.h:33
@ CS_uncalibrated
The camera is not calibrated (no calibration found)
Definition: CVCalibration.h:32
@ VT_NONE
No camera needed.
Definition: CVCapture.h:41
@ VT_MAIN
Main camera on all on all all devices.
Definition: CVCapture.h:42
cv::Matx44f CVMatx44f
Definition: CVTypedefs.h:59
cv::Mat CVMat
Definition: CVTypedefs.h:38
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
float SLfloat
Definition: SL.h:173
#define SL_WARN_MSG(message)
Definition: SL.h:241
#define SL_DB_HIDDEN
Flags an object as hidden.
Definition: SLDrawBits.h:20
SLSceneView * sv
Definition: SLGLImGui.h:28
static const string CALIB_FTP_HOST
ftp host for calibration up and download
Definition: AppCommon.h:114
static CVCalibrationEstimator * calibrationEstimator
Definition: AppCommon.h:107
static const string CALIB_FTP_USER
ftp login user for calibration up and download
Definition: AppCommon.h:115
static const string CALIB_FTP_DIR
ftp directory for calibration up and download
Definition: AppCommon.h:117
static SLstring calibIniPath
That's where data/calibrations folder is located.
Definition: AppCommon.h:108
static SLstring exePath
executable root path
Definition: AppCommon.h:80
static const string CALIB_FTP_PWD
ftp login pwd for calibration up and download
Definition: AppCommon.h:116
static SLVSceneView sceneViews
Vector of sceneview pointers.
Definition: AppCommon.h:62
static CVCalibrationEstimatorParams calibrationEstimatorParams
Definition: AppCommon.h:106
static SLstring externalPath
Default path for external file storage.
Definition: AppCommon.h:82
static SLSceneID sceneID
ID of currently loaded scene.
Definition: AppCommon.h:89
static SLScene * scene
Pointer to the one and only SLScene instance.
Definition: AppCommon.h:61
static map< string, string > deviceParameter
Generic device parameter.
Definition: AppCommon.h:101
static SLstring calibFilePath
That's where calibrations are stored and loaded from.
Definition: AppCommon.h:109
special exception that informs about errors during calibration process
CVCalibration getCalibration()
Get resulting calibration.
bool updateAndDecorate(CVMat imageColor, const CVMat &imageGray, bool grabFrame, bool drawCorners=true)
< Finds the inner chessboard corners in the given image
Live video camera calibration class with OpenCV an OpenCV calibration.
Definition: CVCalibration.h:71
void remap(CVMat &inDistorted, CVMat &outUndistorted)
Undistorts the inDistorted image into the outUndistorted.
float reprojectionError() const
float cameraFovHDeg() const
float cameraFovVDeg() const
bool save(const string &calibDir, const string &calibFileName)
Saves the camera calibration parameters to the config file.
CVCalibState state() const
bool mirrorH()
Definition: CVCamera.h:22
CVCalibration calibration
Definition: CVCamera.h:36
CVCameraType type()
Definition: CVCamera.h:24
void showUndistorted(bool su)
Definition: CVCamera.h:25
bool mirrorV()
Definition: CVCamera.h:23
CVCamera * activeCamera
Pointer to the active camera.
Definition: CVCapture.h:136
CVPixelFormatGL format
GL pixel format.
Definition: CVCapture.h:122
void videoType(CVVideoType vt)
Setter for video type also sets the active calibration.
Definition: CVCapture.cpp:866
CVMat lastFrame
last frame grabbed in BGR
Definition: CVCapture.h:119
static CVCapture * instance()
Public static instance getter for singleton pattern.
Definition: CVCapture.h:65
CVTracked is the pure virtual base class for tracking features in video.
Definition: CVTracked.h:50
static AvgFloat trackingTimesMS
Averaged time for video tracking in ms.
Definition: CVTracked.h:82
virtual bool track(CVMat imageGray, CVMat imageBgr, CVCalibration *calib)=0
CVMatx44f objectViewMat()
Definition: CVTracked.h:65
static float timeMS()
Definition: GlobalTimer.cpp:25
Active or visible camera node class.
Definition: SLCamera.h:54
void fov(const SLfloat fov)
vertical field of view
Definition: SLCamera.h:98
Texture object for OpenGL texturing.
Definition: SLGLTexture.h:110
SLbool copyVideoImage(SLint camWidth, SLint camHeight, CVPixelFormatGL glFormat, SLuchar *data, SLbool isContinuous, SLbool isTopLeft)
Copies the image data from a video camera into the current video image.
SLMat4< T > inverted() const
Computes the inverse of a 4x4 non-singular matrix.
Definition: SLMat4.h:1371
SLNode represents a node in a hierarchical scene graph.
Definition: SLNode.h:147
void om(const SLMat4f &mat)
Definition: SLNode.h:276
void setDrawBitsRec(SLuint bit, SLbool state)
Definition: SLNode.cpp:804
The SLScene class represents the top level instance holding the scene structure.
Definition: SLScene.h:47
void info(SLstring i)
Definition: SLScene.h:93
SceneView class represents a dynamic real time 3D view onto the scene.
Definition: SLSceneView.h:69
void camera(SLCamera *camera)
Definition: SLSceneView.h:145
void set(T value)
Sets the current value in the value array and builds the average.
Definition: Averaged.h:53
static std::string get()
Definition: Utils.cpp:1261
bool uploadFile(const string &fileDir, const string &fileName, const string &ftpHost, const string &ftpUser, const string &ftpPwd, const string &ftpDir, string &errorMsg)
Uploads file to the ftp server.
Definition: FtpUtils.cpp:198
void errorMsg(const char *tag, const char *msg, const int line, const char *file)
Platform independent error message output.
Definition: Utils.cpp:1168
void log(const char *tag, const char *format,...)
logs a formatted string platform independently
Definition: Utils.cpp:1103