SLProject  4.3.020
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SENSCvCamera.cpp
Go to the documentation of this file.
1 #include "SENSCvCamera.h"
2 #include <opencv2/imgproc.hpp>
3 #include <SENSUtils.h>
4 #include <Utils.h>
5 
6 //TODO: we scale the original image only to meet the width of manipImg. After that the targetImg may be additionally cropped (e.g. to screen width)
7 SENSFramePtr SENSCvCamera::processNewFrame(const SENSTimePt& timePt, cv::Mat bgrImg, cv::Mat intrinsics, bool intrinsicsChanged)
8 {
9  //todo: accessing config readonly should be no problem here, as the config only changes when camera is stopped
10  cv::Size inputSize = bgrImg.size();
11 
12  // Crop Video image to required aspect ratio
13  int cropW = 0, cropH = 0;
14  SENS::cropImage(bgrImg, (float)_config->targetWidth / (float)_config->targetHeight, cropW, cropH);
15 
16  // Mirroring
17  SENS::mirrorImage(bgrImg, _config->mirrorH, _config->mirrorV);
18 
19  cv::Mat manipImg;
20  float scale = 1.0f;
21  //problem: eingangsbild 16:9 -> targetImg 4:3 -> crop left and right -> manipImg 16:9 -> weiterer crop oben und unten -> FALSCH
22  if (_config->manipWidth > 0 && _config->manipHeight > 0)
23  {
24  manipImg = bgrImg;
25  int cropW = 0, cropH = 0;
26  SENS::cropImage(manipImg, (float)_config->manipWidth / (float)_config->manipHeight, cropW, cropH);
27  scale = (float)_config->manipWidth / (float)manipImg.size().width;
28  cv::resize(manipImg, manipImg, cv::Size(), scale, scale);
29  }
30  else if (_config->convertManipToGray)
31  {
32  manipImg = bgrImg;
33  }
34 
35  // Create grayscale
36  if (_config->convertManipToGray)
37  {
38  cv::cvtColor(manipImg, manipImg, cv::COLOR_BGR2GRAY);
39  }
40 
41  SENSFramePtr sensFrame = std::make_unique<SENSFrame>(timePt,
42  bgrImg.clone(),
43  manipImg,
44  _config->mirrorH,
45  _config->mirrorV,
46  1 / scale,
47  intrinsics.clone(),
48  manipImg.cols,
49  manipImg.rows);
50 
51  return sensFrame;
52 }
53 
54 void SENSCvCamera::guessAndSetCalibration(float fovDegFallbackGuess)
55 {
56  //We make a calibration with full resolution and adjust it to the manipulated image size later if neccessary:
57  //For the initial setup we have to use streamconfig values because that is where the fovV fits too
58  float horizFOVDev = fovDegFallbackGuess;
59  if (_config->streamConfig->focalLengthPix > 0)
60  horizFOVDev = SENS::calcFOVDegFromFocalLengthPix(_config->streamConfig->focalLengthPix, _config->streamConfig->widthPix);
61 
62  //init calibration with streaconfig image size, because that is where the fovV fits too
63  _calibration = std::make_unique<SENSCalibration>(cv::Size(_config->streamConfig->widthPix, _config->streamConfig->heightPix),
64  horizFOVDev,
65  false,
66  false,
69  //now we adapt the calibration to the target size
70  if (_config->targetWidth != _config->streamConfig->widthPix || _config->targetHeight != _config->streamConfig->heightPix)
71  _calibration->adaptForNewResolution({_config->targetWidth, _config->targetHeight}, false);
72 
73  //update second calibration
74  if (_config->manipWidth > 0 && _config->manipHeight > 0)
75  {
76  _calibrationManip = std::make_unique<SENSCalibration>(*_calibration);
77  _calibrationManip->adaptForNewResolution(cv::Size(_config->manipWidth, _config->manipHeight), false);
78  }
79 }
80 
82  : _camera(camera)
83 {
84  assert(camera);
85  //retrieve capture properties
86  if (_camera)
88 }
89 
91 {
92  if (!_camera)
93  return false;
94 
95  const SENSCaptureProps& props = _camera->captureProperties();
96  return props.supportsCameraFacing(facing);
97 }
98 
99 /*!
100  configure camera: the function checks with the wrapped camera if it could successfully configure the camera.
101  If not, it will return false. This may have dirrerent reasons:
102  - the wrapped camera is not valid
103  - it has to extrapolate the maximum found stream config size to get targetWidth, targetHeight.
104  Transfer -1 for manipWidth and manipHeight to disable generation of manipulated image
105  */
107  int targetWidth,
108  int targetHeight,
109  int manipWidth,
110  int manipHeight,
111  bool mirrorH,
112  bool mirrorV,
113  bool convertManipToGray)
114 {
115  //this can happen, because it is possible to retrieve a camera pointer reference for camera simulation
116  if (!_camera)
117  return ERROR_CAMERA_INVALID;
118 
119  bool cameraWasStarted = false;
120  if (_camera->started())
121  {
122  _camera->stop();
123  cameraWasStarted = true;
124  }
125 
126  const SENSCaptureProps& props = _camera->captureProperties();
127  //check if facing is available
128  if (!props.supportsCameraFacing(facing))
130 
131  ConfigReturnCode returnCode = SUCCESS;
132 
133  //search for best matching stream config
134  int trackingImgW = 640;
135  float searchWdivH;
136  if (manipWidth > 0 && manipHeight > 0 &&
137  ((float)targetWidth / (float)targetHeight) >
138  ((float)manipWidth / (float)manipHeight))
139  searchWdivH = (float)manipWidth / (float)manipHeight;
140  else
141  searchWdivH = (float)targetWidth / (float)targetHeight;
142 
143  //approximately what resolution we search for visualiation image
144  int aproxHighImgW = targetWidth;
145 
146  std::pair<const SENSCameraDeviceProps*, const SENSCameraStreamConfig*> bestConfig =
147  props.findBestMatchingConfig(facing, 65.f, aproxHighImgW, (int)((float)aproxHighImgW / searchWdivH));
148 
149  //warn if extrapolation needed (image will not be extrapolated)
150  if (!bestConfig.first && !bestConfig.second)
151  {
152  //we reduce this size
153  aproxHighImgW = 640;
154  bestConfig = props.findBestMatchingConfig(facing, 65.f, aproxHighImgW, (int)((float)aproxHighImgW / searchWdivH));
155  if (!bestConfig.first && !bestConfig.second)
156  return ERROR_UNKNOWN;
157  else
158  returnCode = WARN_TARGET_SIZE_NOT_FOUND;
159  }
160 
161  _config = std::make_unique<SENSCvCameraConfig>(bestConfig.first,
162  bestConfig.second,
163  targetWidth,
164  targetHeight,
165  manipWidth,
166  manipHeight,
167  mirrorH,
168  mirrorV,
169  convertManipToGray);
170 
171  //guess calibrations if no calibration is set from outside
174 
175  if (cameraWasStarted)
176  _camera->start(bestConfig.first->deviceId(), *bestConfig.second);
177 
178  return returnCode;
179 }
180 
182 {
183  if (!_camera)
184  return false;
185 
186  if (!_config)
187  return false;
188 
189  _camera->start(_config->deviceProps->deviceId(),
190  *_config->streamConfig,
191  true);
192 
193  return true;
194 }
195 
197 {
198  if (_camera)
199  return _camera->started();
200  else
201  return false;
202 }
203 
205 {
206  if (_camera)
207  _camera->stop();
208 }
209 
211 {
213 
214  SENSFrameBasePtr frameBase = _camera->latestFrame();
215  if (frameBase)
216  {
217  //process
218  latestFrame = processNewFrame(frameBase->timePt, frameBase->imgBGR, frameBase->intrinsics, !frameBase->intrinsics.empty());
219  }
220 
221  //update calibration if necessary
222  //we wont update it, if overwrite calibration is valid (set from outside)
223  //todo: if frame size changed (or config) then we also have to adjust the overwrite calibration?
224  if (latestFrame && !_calibrationOverwrite && !latestFrame->intrinsics.empty())
225  {
226  HighResTimer t;
227  //todo: mutex for calibration?
228  _calibration = std::make_unique<SENSCalibration>(latestFrame->intrinsics,
229  cv::Size(_config->streamConfig->widthPix, _config->streamConfig->heightPix),
230  _calibration->isMirroredH(),
231  _calibration->isMirroredV(),
232  _calibration->camType(),
233  _calibration->computerInfos());
234  //now we adapt the calibration to the target size
235  if (_config->targetWidth != _config->streamConfig->widthPix || _config->targetHeight != _config->streamConfig->heightPix)
236  _calibration->adaptForNewResolution({_config->targetWidth, _config->targetHeight}, false);
237 
238  //update second calibration
239  if (_config->manipWidth > 0 && _config->manipHeight > 0)
240  {
241  _calibrationManip = std::make_unique<SENSCalibration>(*_calibration);
242  _calibrationManip->adaptForNewResolution(cv::Size(_config->manipWidth, _config->manipHeight), false);
243  }
244 
245  //SENS_DEBUG("calib update duration %f", t.elapsedTimeInMilliSec());
246  }
247 
248  return latestFrame;
249 }
250 
252 {
253  if (!_calibrationManip)
254  return cv::Mat();
255  else
256  return _calibrationManip->cameraMat();
257 }
258 
259 //! Set calibration and adapt it to current image size. Camera has to be configured, before this function is called.
260 void SENSCvCamera::setCalibration(const SENSCalibration& calibration, bool buildUndistortionMaps)
261 {
262  _calibrationOverwrite = std::make_unique<SENSCalibration>(calibration);
263 
264  //update first calibration
265  _calibration = std::make_unique<SENSCalibration>(*_calibrationOverwrite);
266  _calibration->adaptForNewResolution(cv::Size(_config->targetWidth, _config->targetHeight), buildUndistortionMaps);
267 
268  //update second calibration
269  if (_config->manipWidth > 0 && _config->manipHeight > 0)
270  {
271  _calibrationManip = std::make_unique<SENSCalibration>(*_calibrationOverwrite);
272  _calibrationManip->adaptForNewResolution(cv::Size(_config->manipWidth, _config->manipHeight), buildUndistortionMaps);
273  }
274 }
std::chrono::high_resolution_clock::time_point SENSTimePt
Definition: SENS.h:57
SENSCameraFacing
Definition of camera facing.
Definition: SENSCamera.h:28
std::shared_ptr< SENSFrame > SENSFramePtr
Definition: SENSFrame.h:73
std::shared_ptr< SENSFrameBase > SENSFrameBasePtr
Definition: SENSFrame.h:27
High Resolution Timer class using C++11.
Definition: HighResTimer.h:31
Pure abstract camera class.
Definition: SENSCamera.h:160
virtual SENSFrameBasePtr latestFrame()=0
Get the latest captured frame. If no frame was captured the frame will be empty (null).
virtual const SENSCameraConfig & start(std::string deviceId, const SENSCameraStreamConfig &streamConfig, bool provideIntrinsics=true)=0
virtual bool started() const =0
virtual const SENSCaptureProps & captureProperties()=0
Get SENSCaptureProps which contains necessary information about all available camera devices and thei...
virtual void stop()=0
Stop a started camera device.
std::pair< const SENSCameraDeviceProps *const, const SENSCameraStreamConfig *const > findBestMatchingConfig(SENSCameraFacing facing, const float horizFov, const int width, const int height) const
Helper function to find a camera device and stream configuration with certain characteristics.
Definition: SENSCamera.cpp:89
bool supportsCameraFacing(const SENSCameraFacing &facing) const
Definition: SENSCamera.cpp:67
cv::Mat scaledCameraMat()
bool supportsFacing(SENSCameraFacing facing)
ConfigReturnCode
error code definition, will be returned by configure in case of failure. See method advice() for expl...
Definition: SENSCvCamera.h:69
@ ERROR_FACING_NOT_AVAILABLE
Definition: SENSCvCamera.h:74
@ ERROR_CAMERA_INVALID
Definition: SENSCvCamera.h:72
@ WARN_TARGET_SIZE_NOT_FOUND
Definition: SENSCvCamera.h:71
void guessAndSetCalibration(float fovDegFallbackGuess)
std::unique_ptr< SENSCalibration > _calibrationManip
Definition: SENSCvCamera.h:143
std::unique_ptr< SENSCvCameraConfig > _config
Definition: SENSCvCamera.h:138
void setCalibration(const SENSCalibration &calibration, bool buildUndistortionMaps)
Set calibration and adapt it to current image size. Camera has to be configured, before this function...
SENSCvCamera(SENSCamera *camera)
ConfigReturnCode configure(SENSCameraFacing facing, int targetWidth, int targetHeight, int manipWidth, int manipHeight, bool mirrorH, bool mirrorV, bool convertManipToGray)
SENSCamera * _camera
Definition: SENSCvCamera.h:137
const SENSCalibration *const calibration() const
returns SENSCalibration if it was started (maybe a guessed one from a fovV guess)....
Definition: SENSCvCamera.h:120
SENSFramePtr latestFrame()
std::unique_ptr< SENSCalibration > _calibration
The calibration is used for computer vision applications. This calibration is adjusted to fit to the ...
Definition: SENSCvCamera.h:141
SENSFramePtr processNewFrame(const SENSTimePt &timePt, cv::Mat bgrImg, cv::Mat intrinsics, bool intrinsicsChanged)
Definition: SENSCvCamera.cpp:7
std::unique_ptr< SENSCalibration > _calibrationOverwrite
Definition: SENSCvCamera.h:146
Class for holding computer information.
Definition: Utils.h:288
static std::string get()
Definition: Utils.cpp:1258
void mirrorImage(cv::Mat &img, bool mirrorH, bool mirrorV)
Definition: SENSUtils.cpp:170
float calcFOVDegFromFocalLengthPix(const float focalLengthPix, const int imgLength)
Definition: SENSUtils.cpp:192
void cropImage(cv::Mat &img, float targetWdivH, int &cropW, int &cropH)
Definition: SENSUtils.cpp:62