0

I have 2 Logitech Pro 9000 webcams. I want to do some stereocalibration and pose estimation but I'm currently stuck on some weird (for me at least) behaviour on part of cv::VideoCapture. Note that this question is related to the one here.

I have two classes, which will be used as a base for creating capture modules for various cameras in order to include those in a bigger system. The first one - CameraSettings - contains camera-specific settings. These settings are used in the second class - Camera - which handles the video stream, calibration and so on. The constructor of a camera simply uses the values in the CameraSettings object with cv::VideoCapture::set(CV_CAP_PROP_ ...):

#ifndef CAMERASETTINGS_H
#define CAMERASETTINGS_H

#include <string>
using std::string;
namespace Camera {
  class CameraSettings {
    private:
      double deviceIndex; /// Device index (starts from 0)
      double frameRateLimit;  /// Limits the frames per second. Depending on the number of cameras and the amount of data that is retrieved from those setting this to a lower (supported by the camera model!) value will prevent data clogging
      double frameWidth;  /// Width of the frame
      double frameHeight; /// Height of the frame

    public:
      /// Creates an empty set of settings
      CameraSettings();
      /// Creates a partially predefined set of settings
      CameraSettings(double deviceIndex, double frameRateLimit=25, double frameWidth=320, double frameHeight=240);
      CameraSettings(string devideIpAddrAndFormat, double frameRateLimit=25, double frameWidth=320, double frameHeight=240);
      ~CameraSettings();

      /*
       * Getters and setters for all settings of a camera
       */

      double getDevice() const;
      void setDevice(double value);

      double getFrameRateLimit() const;
      void setFrameRateLimit(double value);

      double getFrameWidth() const;
      void setFrameWidth(double value);

      double getFrameHeight() const;
      void setFrameHeight(double value);
  };
}
namespace Camera {
  class Camera {
    private:
      CameraSettings settings;  // Various camera settings
      VideoCapture *capture;  // Points at the video stream generated by the camera

    public:
      /*
       * Creates a new camera using a set of given settings
       * @param settings Contains an object with camera settings
       */
      Camera(CameraSettings& settings);
      ~Camera();

      /*
       * Retrieves the next frame in the stream
       * @param frame Contains a retrieved frame from the video stream
       */
      void getFrame(Mat& frame);
  };

Note: this is still an early work in progress!

The problem comes from my getFrame() method, which looks as follows:

void Camera::getFrame(Mat &frame)
{
  cout << "Reading frame..." << endl;
  // Check if stream is opened
  if(capture->isOpened()) {
    // Store next frame and check if frames can actually be read from the specified capture
    if(!capture->read(frame))
      cout << MSG_PREFIX_ERROR << ERROR_CAPT_UNABLE_TO_READ << endl;
  }
}

After I create a CameraSettings object I can additionally tweak the parameters and pass it to a newly created Camera object:

// Set both sets of settings to framerate of 15 and resolution of 352x288
Camera::CameraSettings cs1(1, 15);
Camera::CameraSettings cs2(2, 15);
cs1.setFrameHeight(288);
cs1.setFrameWidth(352);
cs2.setFrameHeight(288);
cs2.setFrameWidth(352);

// Create two cameras using the specified above settings
Camera::Camera cam1(cs1);
Camera::Camera cam2(cs2);

I discovered that the VideoCapture that I have in my Camera object allows a much lower resolution and frame rate compared to the following direct approach:

main(int argc, char **argv) {
  VideoCapture cap1(1);
  VideoCapture cap2(2);

  if(!cap1.isOpened())
  {
    cout << "Cannot open the video cam [1]" << endl;
    return -1;
  }

  if(!cap2.isOpened())
  {
    cout << "Cannot open the video cam [2]" << endl;
    return -1;
  }

  cap1.set(CV_CAP_PROP_FPS, 15);
  cap2.set(CV_CAP_PROP_FPS, 15);

  double dWidth1 = cap1.get(CV_CAP_PROP_FRAME_WIDTH);
  double dHeight1 = cap1.get(CV_CAP_PROP_FRAME_HEIGHT);
  double dWidth2 = cap2.get(CV_CAP_PROP_FRAME_WIDTH);
  double dHeight2 = cap2.get(CV_CAP_PROP_FRAME_HEIGHT);

  cout << "cam[1] Frame size: " << dWidth1 << " x " << dHeight1 << endl;
  cout << "cam[2] Frame size: " << dWidth2 << " x " << dHeight2 << endl;
  namedWindow("cam[1]",CV_WINDOW_AUTOSIZE);
  namedWindow("cam[2]",CV_WINDOW_AUTOSIZE);

  while(1)
  {
    Mat frame1, frame2;
    bool bSuccess1 = cap1.read(frame1);
    bool bSuccess2 = cap2.read(frame2);

    if (!bSuccess1)
    {
      cout << "Cannot read a frame from video stream [1]" << endl;
      break;
    }

    if (!bSuccess2)
    {
      cout << "Cannot read a frame from video stream [2]" << endl;
      break;
    }

    imshow("cam[1]", frame1);
    imshow("cam[2]", frame2);

    if(waitKey(30) == 27)
    {
      cout << "ESC key was pressed by user" << endl;
      break;
    }
  }
}

The way I am handling things in my class is the exact same as the second piece of code I posted with the difference that here I use the default settings of cv::VideoCapture. I checked the dimensions of the frames and they are 640x480. In the case of using my Camera class however I can't get such a high resolution because I get the infamous error:

libv4l2: error turning on stream: No space left on device

VIDIOC_STREAMON: No space left on device

For example if I do the following:

cs1.setFrameHeight(288);
cs1.setFrameWidth(352);
cs2.setFrameHeight(288);
cs2.setFrameWidth(352);

for both of my cameras at 15 fps it is working as expected. Using 640x480 as in the case without my classes is not possible.

Note that I have checked the supported resolutions using v4l2-ctl. I have also tested the framerates in both cases because they DO affect how high the data volumes are from both cameras.

Obviously my question is why this is happening and how does my class affects the capabilities of cv::VideoCapture when it comes to FPS and resolution.

EDIT: Removed code that is not required for the problem at hand. Thanks @Wug!

Community
  • 1
  • 1
rbaleksandar
  • 8,713
  • 7
  • 76
  • 161
  • At least when voting down my question write the reason why so that I can improve it. Otherwise this is extremely counterproductive. – rbaleksandar Nov 05 '14 at 17:46
  • I didn't downvote it, but you should probably trim out anything that's not directly relevant to the question so we don't have to read 20 screens of code to figure anything out. – Wug Nov 05 '14 at 18:08
  • Thanks for the advice. I removed the parts that are not required here. – rbaleksandar Nov 05 '14 at 18:16

0 Answers0