Skip to content

Implement Camera Multiplexing API#15100

Merged
alalek merged 22 commits intoopencv:masterfrom
mpashchenkov:cam_multiplexing_function_v
Nov 15, 2019
Merged

Implement Camera Multiplexing API#15100
alalek merged 22 commits intoopencv:masterfrom
mpashchenkov:cam_multiplexing_function_v

Conversation

@mpashchenkov
Copy link
Copy Markdown
Contributor

@mpashchenkov mpashchenkov commented Jul 19, 2019

Added static function waitAny( ..., ..., ... ) to work with multiple cameras in one thread. The method accepts a collection of VideoCapture pointers, state collection ( 1 - ready, -1 - error, 0 - not ready ), timeout. It is implemented to find the cameras states for V4L.
Method camerasPoll( IVideoCupture --cast>> CvCupture, ..., ... ) calls function deviceHandlePoll( deviceHandle, ..., ... ). Method uses poll( ..., ..., ... ) function to find camera's state.
User recevies a collection of states for each camera.

Proposal: camera multiplexing API.
Multiplex camera API demo for tests.

Device details: Intel® Core™ i7-8700 CPU @ 3.20GHz × 12.
Cameras: Logitech C922 Pro Stream Webcam.

FPS test:
Parameters:
Net: Face-detection-retail-0004;
Size: Reshape (1, 3, 1000, 1000);
Launch time: 25 ms.

Method read()

Requests 2 3 4 5 6 7
2 cameras 27.1322 26.9473 26.9839 26.8831 27.0233 -------
3 cameras ------- 27.3065 27.1696 27.2726 27.3191 27.3035
4 cameras ------- ------- 27.2271 27.4342 26.624 27.0994

Method WaitAny()

Requests 2 3 4 5 6 7
2 cameras 30.9216 30.7505 29.5278 29.876 30.8151 -------
3 cameras ------- 29.9616 30.1515 30.8857 29.981 29.9445
4 cameras ------- ------- 30.69 30.9046 31.1103 30.5051

Parameters:
Net: Face-detection-adas-0001;
Size: (1, 3, 384, 672);
Launch time: 6.16 ms.

Method read()

Requests 2 3 4 5 6 7
2 cameras 81.3524 84.9231 83.3405 85.006 85.1356 -------
3 cameras ------- 86.8687 84.2587 87.7585 84.6507 84.6306
4 cameras ------- ------- 88.7628 85.0765 89.5895 85.2633

Method WaitAny()

Requests 2 3 4 5 6 7
2 cameras 85.8336 89.1905 86.3272 85.7945 89.0111 -------
3 cameras ------- 86.8968 84.0484 88.4938 85.3782 88.2053
4 cameras ------- ------- 83.4528 87.8218 88.0895 87.1574

Copy link
Copy Markdown
Contributor

@mshabunin mshabunin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of function usage. Ideally as a test case here (disabled by default): https://github.com/opencv/opencv/blob/master/modules/videoio/test/test_camera.cpp

And I think this fix changes too large part of public API, while it can be enough to add static function waitAny and several methods to CvCaptureCAM_V4L class.

Copy link
Copy Markdown
Contributor

@mshabunin mshabunin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you manage to run these tests? Do they pass for you?

TEST_P(DISABLED_videoio_timeout, v4l_poll_timeout)
{
//Two identical cameras
VideoCapture cap1(0);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add explicit backend parameter to all constructors: cap(0, CAP_V4L)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

{
if(state[i] == CAP_CAM_READY)
{
EXPECT_TRUE(VCM[i].retrieve(forMAt[i]));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps performance tests do not make much sense in this case. Standalone benchmark application (in samples/cpp dir) would be more useful. Lets say it could be launched in two modes: sync and async, and will perform some processing on frames (e.g. Canny) and measure performance and efficiency metrics. Take a look at the videocapture_camera.cpp sample application, it can be used as a starting point.

function waitAny

Add errors catcher

Stub for Python added.

Sifting warnings

One test added

Two tests for camera and Perf tests added
@mpashchenkov mpashchenkov force-pushed the cam_multiplexing_function_v branch from 1b098cc to 0c11e06 Compare July 29, 2019 07:45
{
if(!(bcknd == v_captures[bcknd_num].icap->getCaptureDomain()))
{
CV_Error(Error::StsError, "Backend equality expected");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like "All captures must have same backend"

return true;
}
else
CV_Error(Error::StsError, "Vector is empty");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like "capture list is empty"

{
int bcknd = v_captures[0].icap->getCaptureDomain();

for (unsigned int bcknd_num = 0; bcknd_num < v_captures.size(); ++bcknd_num)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use size_t

from 1

return false;
}

bool VideoCapture::waitAnyInterior(std::vector<VideoCapture>& v_captures, std::vector<int>& state, const int & timeout)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO better to remove this function and move this logic into waitAny

virtual bool setProperty(int, double) { return 0; }
virtual bool grabFrame() { return true; }

virtual int getDeviceHandle() { return 0; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Device handles are implementation detail, remove from common interface


CV_IMPL bool cvCamerasPoll(const std::vector<CvCapture*>& pointers, std::vector<int>& state, const int64_t & timeout)
{
return pointers[0] ? pointers[0]->camerasPoll(pointers, state, timeout) : 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false instead of 0

Mat frame1;

//false start
cap1>>frame1;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test for read success in all tests

Mat frame1;
int ITERATION_COUNT = 500;

//false start
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? Write some meaningful comment

@Hardcode84
Copy link
Copy Markdown

Hardcode84 commented Jul 29, 2019

Need test for "waitAny" with single VIdeoCapture.
Also nice to have tests for errors handling.

}
}

State.resize(v_captures.size());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of resizing better just check size and bail with error on mismatch

CV_WRAP virtual bool grab();


CV_WRAP static bool waitAny(std::vector<VideoCapture>&, std::vector<int>&, const int &);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • just int instead of const int &
  • add names
  • use int64

#else
char* datapath_dir = OPENCV_TEST_CAMERA_LIST;
#endif
ASSERT_FALSE(datapath_dir == nullptr || datapath_dir[0] == '\0');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove extra space

PERF_TEST(, DISABLED_GetReadFrame)
{
int ITERATION_COUNT = 50; //number of expected frames from all cameras
#ifndef WINRT
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap this block into function

{
std::vector< CvCapture * > capPtrs;

for (size_t capnum = 0; capnum < deviceHandles.size(); ++capnum)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use range for


for (size_t capnum = 0; capnum < deviceHandles.size(); ++capnum)
{
CV_Assert(dynamic_cast< LegacyCapture * >(deviceHandles[capnum]) != nullptr);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with CV_DbgAssert

virtual bool grabFrame() CV_OVERRIDE;
virtual IplImage* retrieveFrame(int) CV_OVERRIDE;

virtual bool deviceHandlePoll(const std::vector<int>&, std::vector<int>&, const int64_t &) CV_OVERRIDE;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass integers by value


std::vector<pollfd> fds;

for (size_t dhand_num = 0; dhand_num < deviceHandles.size(); ++dhand_num)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Range for

TEST_P(DISABLED_videoio_fps, v4l_poll_fps)
{
//Two identical cameras
VideoCapture cap1(0, CAP_V4L);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unhardcode camera indices

{
if(pointers[ptr_num])
{
CV_Assert(dynamic_cast< CvCaptureCAM_V4L * >(pointers[ptr_num]) != nullptr);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CV_DbgAssert

virtual bool setProperty(int, double) { return 0; }
virtual bool grabFrame() { return true; }
virtual bool deviceHandlePoll(const std::vector<int>&, std::vector<int>&, const int64_t &){ return false; }
virtual bool setFirstCapture() {return false;}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove from public interface

virtual double getProperty(int) const { return 0; }
virtual bool setProperty(int, double) { return 0; }
virtual bool grabFrame() { return true; }
virtual bool deviceHandlePoll(const std::vector<int>&, std::vector<int>&, const int64_t &){ return false; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove from public interface

"highgui/video/big_buck_bunny.wmv"
};

static char* set_environment_variable()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something like "get_cameras_list"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping

}
if(state[cupture_num] == CAP_CAM_ERROR)
{
//printf("error cam no. %d \n", cupture_num);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove debug code

int ret = poll(fds.data(), fds.size(), timeout);

if(ret == -1)
return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add perror call

}
else
{
perror("CvCapture pointer is null");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perror checks last errono. Is is not deeded there. Only after poll

"highgui/video/big_buck_bunny.wmv"
};

static char* set_environment_variable()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping

@Hardcode84
Copy link
Copy Markdown

  • Add url to original issue into PR description

@mpashchenkov
Copy link
Copy Markdown
Contributor Author

Tests passed.

typedef std::vector<DMatch> vector_DMatch;
typedef std::vector<String> vector_String;
typedef std::vector<Scalar> vector_Scalar;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rollback unrelated changes

//! @} videoio_flags_others


enum statecam
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use formatting consistent with other enums in this file

*/
CVAPI(int) cvGrabFrame( CvCapture* capture );

CVAPI(bool) cvCamerasPoll( const std::vector<CvCapture * >& pointers, std::vector<int>& state, const int64_t & timeout );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this function from public interface, C-API is deprecated and should not be extended. std::vector is part of C++ standard. If you need this function, declare it in private files (src/*.hpp, src/*.cpp).

#ifndef WINRT
return getenv("OPENCV_TEST_CAMERA_LIST");
#else
return OPENCV_TEST_CAMERA_LIST;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no such variable, build for WinRT will be broken.


static char* get_cameras_list()
{
#ifndef WINRT
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use #ifndef NO_GETENV check here

path += datapath_dir[step];
++step;
}
Mat frame1, frame2, processed1, processed2;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASSERT_EQUAL(VCM.size(), 2u);
Mat frame[2], processed[2];

std::vector<int> deviceHandles;
for(const auto& ptr_num : pointers)
{
if(ptr_num)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why didn't not you use dynamic_cast?

CvCaptureCAM_V4L *ptr = dynamic_cast< CvCaptureCAM_V4L * >(ptr_num);
if (!ptr)
    return false;
deviceHandles.push_back(ptr->deviceHandle);
ptr->setFirstCapture();

state[struct_num] = CAP_CAM_READY;
}
else
if((fds[struct_num].revents & POLLERR) != 0)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please balance braces, its either

if ()
    foo();
else
    bar();

either

if ()
{
    foo();
}
else
{
    bar();
}

return false;
}

bool CvCaptureCAM_V4L::setFirstCapture()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this method do? There is duplicated code in grabFrame. Duplicated code is bad practice.


bool CvCaptureCAM_V4L::deviceHandlePoll(const std::vector<int>& deviceHandles, std::vector<int>& state, int64_t timeout)
{
if(!deviceHandles.empty())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix indents in this function.

@alalek alalek merged commit 1acadd3 into opencv:master Nov 15, 2019
a-sajjad72 pushed a commit to a-sajjad72/opencv that referenced this pull request Mar 30, 2023
Implement Camera Multiplexing API

* IdideoCapture + two wrong function

function waitAny

Add errors catcher

Stub for Python added.

Sifting warnings

One test added

Two tests for camera and Perf tests added

* Perf sync and async tests for waitAny() added, waitAnyInterior() deleted, getDeviceHandle() deleted

* Variable OPENCV_TEST_CAMERA_LIST added

* Without fps set

* ASSERT_FAILED for environment variable

* Perf tests is DISABLED_

* --Trailing whitespace

* Return false from cap.cpp deleted

* Two functions deleted from interface, +range for, +environment variable in test_camera

* Space deleted

* printf deleted, perror added

* CV_WRAP deleted, cv2 cleared from stubs

* -- space

* default timeout added

* @param changed

* place of waitAny changed

* --whitespace

* ++function description

* function description changed

* revert unused changes

* videoio: rework API for VideoCapture::waitAny()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants