Robobot camera: Difference between revisions

From Rsewiki
 
(15 intermediate revisions by the same user not shown)
Line 2: Line 2:


== camera settings ==
== camera settings ==
<!--
=== On Raspberry PI Debian OS. ===


The used camera has limited possibilities.
=== Data formats ===


640 x 480 at 25 FPS using MJPG coding seems like a working resolution.
The used camera is a 'Jieli Technology' camera of type 'USB PHY 2.0' (packed by Sandberg).


All higher resolutions seem to crash the camera driver, requiring a reboot.
The camera has limited control capabilities but supports the following data formats.


BUT, after a few, sometimes, successful captures, things go wrong, and 'sudo dmesg' shows something like:
* MJPG coded 640 x 320 pixels at 25 or 30 FPS
* MJPG coded 1280 x 720 pixels at 25 or 30 FPS
* MJPG coded 1920 x 1080 pixels at 25 or 30 FPS
* MJPG coded 640 x 480 pixels at 25 or 30 FPS; this mode cuts parts of the image width to fit the format


[  237.889889] usb 1-1.5: new high-speed USB device number 6 using dwc2
It also supports "raw" format as YUYV 4:2:2, but it seems like data loss occurs (fragmented images), so do not use this format.
[  237.991458] usb 1-1.5: New USB device found, idVendor=1224, idProduct=2a25, bcdDevice= 1.00
[  237.991505] usb 1-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  237.991524] usb 1-1.5: Product: USB PHY 2.0
[  237.991540] usb 1-1.5: Manufacturer: Jieli Technology
[  237.993188] usb 1-1.5: Found UVC 1.00 device USB PHY 2.0 (1224:2a25)
[  237.996497] input: USB PHY 2.0: GENERAL Webcam as /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.5/1-1.5:1.0/input/input1
[  238.004536] usb 1-1.5: set resolution quirk: cval->res = 16
[  348.102430] dwc2 3f980000.usb: dwc2_hc_halt() Channel can't be halted
[  348.109275] dwc2 3f980000.usb: dwc2_hc_halt() Channel can't be halted


A google search suggests that it is the USB driver 'dwc2_hc' that is to blame.
=== Use from OpenCV (C++) ===


Trying Raspberry Pi OS instead.
First, open and set the camera format:
-->
=== Raspberry Pi OS ===


Under installation
cv::VideoCapture cap;
void setup()
{
  int deviceID = 0;       
  int apiID = cv::CAP_V4L2;
  // open selected camera using selected API
  cap.open(deviceID, apiID);
  // check if we succeeded
  camIsOpen = cap.isOpened();
  if (not camIsOpen)
  {
    cerr << "ERROR! Unable to open camera\n";
  }
  else
  {
    uint32_t fourcc = cv::VideoWriter::fourcc('M','J','P','G');
    cap.set(cv::CAP_PROP_FOURCC, fourcc);
    // possible resolutions in JPEG coding
    // (rows x columns) 320x640, 720x1280
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
    cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
    cap.set(cv::CAP_PROP_FPS, 25);
    // now the camera is ready for frame capture.
    //
    // debug print of accepted format:
    union FourChar
    { // the four characters are coded into a 32-bit integer.
      uint32_t cc4;
      char ccc[4];
    } fmt;
    fmt.cc4 = cap.get(cv::CAP_PROP_FOURCC); // get format
    printf("# Video device %d: width=%g, height=%g, format=%c%c%c%c, FPS=%g\n",
          dev,
          cap.get(cv::CAP_PROP_FRAME_WIDTH),
          cap.get(cv::CAP_PROP_FRAME_HEIGHT),
          fmt.ccc[0], fmt.ccc[1], fmt.ccc[2], fmt.ccc[3],
          cap.get(cv::CAP_PROP_FPS));
  }
 
Then capture an image to a matrix called 'frame':
 
cv::Mat frame;
bool gotFrame = false;
cap.read(frame);
// mark as available
gotFrame = not frame.empty();
 
The frame has 3 channels in BGR format.
 
To get the most recent image, it is a good idea to keep the buffer empty by discarding unneeded images by:
 
cap.grab();
 
In the template code, this is done in a thread (called loop())
 
=== Camera calibration ===
 
The camera has significant lens distortion and can be calibrated and rectified using the openCV calibration functions.
 
But, close to the centre of the image, this may not be needed.
The main parameter here is the focal length.
 
The focal length f is approximately 1008 pixels, when the image format is 1280 x 720.
 
=== Finding 3D position of a known object ===
 
The relation between an object with pixel size '''Px''' and the focal length '''f''' is the same as the actual object size '''S''' and the distance '''D''' from the camera to the object along the centre axis of the camera, i.e.
 
Px    S
--- = ---
  f    D
The unit of S and D could be in meters.
 
This can be used to find the 3D position of a known object.
 
The distance along the camera axis is thus (when the size of the object is known):
* D = S * f / Px
 
The 3D position of the object can then be found in camera coordinates as (with x being to the right and y directed down
 
* xm = (xi - xc) * D / f
* ym = (yi - yc) * D / f
 
where xm and ym are distances in meters from the camera axis, xi and yi is the image column and row for the (centre of the object), xc and yc are the column and row for the centre of the image, D is the distance to the object in meters and f is the focal length in pixels.

Latest revision as of 12:55, 6 December 2022

Back to Robobot

camera settings

Data formats

The used camera is a 'Jieli Technology' camera of type 'USB PHY 2.0' (packed by Sandberg).

The camera has limited control capabilities but supports the following data formats.

  • MJPG coded 640 x 320 pixels at 25 or 30 FPS
  • MJPG coded 1280 x 720 pixels at 25 or 30 FPS
  • MJPG coded 1920 x 1080 pixels at 25 or 30 FPS
  • MJPG coded 640 x 480 pixels at 25 or 30 FPS; this mode cuts parts of the image width to fit the format

It also supports "raw" format as YUYV 4:2:2, but it seems like data loss occurs (fragmented images), so do not use this format.

Use from OpenCV (C++)

First, open and set the camera format:

cv::VideoCapture cap;

void setup()
{
 int deviceID = 0;        
 int apiID = cv::CAP_V4L2;
 // open selected camera using selected API
 cap.open(deviceID, apiID);
 // check if we succeeded
 camIsOpen = cap.isOpened();
 if (not camIsOpen)
 {
   cerr << "ERROR! Unable to open camera\n";
 }
 else
 {
   uint32_t fourcc = cv::VideoWriter::fourcc('M','J','P','G'); 
   cap.set(cv::CAP_PROP_FOURCC, fourcc);
   // possible resolutions in JPEG coding
   // (rows x columns) 320x640, 720x1280
   cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
   cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
   cap.set(cv::CAP_PROP_FPS, 25);
   // now the camera is ready for frame capture. 
   //
   // debug print of accepted format:
   union FourChar
   { // the four characters are coded into a 32-bit integer.
     uint32_t cc4;
     char ccc[4];
   } fmt;
   fmt.cc4 = cap.get(cv::CAP_PROP_FOURCC); // get format
   printf("# Video device %d: width=%g, height=%g, format=%c%c%c%c, FPS=%g\n", 
          dev, 
          cap.get(cv::CAP_PROP_FRAME_WIDTH), 
          cap.get(cv::CAP_PROP_FRAME_HEIGHT), 
          fmt.ccc[0], fmt.ccc[1], fmt.ccc[2], fmt.ccc[3], 
          cap.get(cv::CAP_PROP_FPS));
 }

Then capture an image to a matrix called 'frame':

cv::Mat frame;
bool gotFrame = false;

cap.read(frame);
// mark as available
gotFrame = not frame.empty();

The frame has 3 channels in BGR format.

To get the most recent image, it is a good idea to keep the buffer empty by discarding unneeded images by:

cap.grab();

In the template code, this is done in a thread (called loop())

Camera calibration

The camera has significant lens distortion and can be calibrated and rectified using the openCV calibration functions.

But, close to the centre of the image, this may not be needed. The main parameter here is the focal length.

The focal length f is approximately 1008 pixels, when the image format is 1280 x 720.

Finding 3D position of a known object

The relation between an object with pixel size Px and the focal length f is the same as the actual object size S and the distance D from the camera to the object along the centre axis of the camera, i.e.

Px     S
--- = ---
 f     D

The unit of S and D could be in meters.

This can be used to find the 3D position of a known object.

The distance along the camera axis is thus (when the size of the object is known):

  • D = S * f / Px

The 3D position of the object can then be found in camera coordinates as (with x being to the right and y directed down

  • xm = (xi - xc) * D / f
  • ym = (yi - yc) * D / f

where xm and ym are distances in meters from the camera axis, xi and yi is the image column and row for the (centre of the object), xc and yc are the column and row for the centre of the image, D is the distance to the object in meters and f is the focal length in pixels.