Implement Camera Multiplexing API#15100
Conversation
mshabunin
left a comment
There was a problem hiding this comment.
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.
mshabunin
left a comment
There was a problem hiding this comment.
Did you manage to run these tests? Do they pass for you?
modules/videoio/test/test_camera.cpp
Outdated
| TEST_P(DISABLED_videoio_timeout, v4l_poll_timeout) | ||
| { | ||
| //Two identical cameras | ||
| VideoCapture cap1(0); |
There was a problem hiding this comment.
Please add explicit backend parameter to all constructors: cap(0, CAP_V4L)
modules/videoio/perf/perf_input.cpp
Outdated
| { | ||
| if(state[i] == CAP_CAM_READY) | ||
| { | ||
| EXPECT_TRUE(VCM[i].retrieve(forMAt[i])); |
There was a problem hiding this comment.
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
1b098cc to
0c11e06
Compare
modules/videoio/src/cap.cpp
Outdated
| { | ||
| if(!(bcknd == v_captures[bcknd_num].icap->getCaptureDomain())) | ||
| { | ||
| CV_Error(Error::StsError, "Backend equality expected"); |
There was a problem hiding this comment.
Something like "All captures must have same backend"
modules/videoio/src/cap.cpp
Outdated
| return true; | ||
| } | ||
| else | ||
| CV_Error(Error::StsError, "Vector is empty"); |
There was a problem hiding this comment.
Something like "capture list is empty"
modules/videoio/src/cap.cpp
Outdated
| { | ||
| int bcknd = v_captures[0].icap->getCaptureDomain(); | ||
|
|
||
| for (unsigned int bcknd_num = 0; bcknd_num < v_captures.size(); ++bcknd_num) |
modules/videoio/src/cap.cpp
Outdated
| return false; | ||
| } | ||
|
|
||
| bool VideoCapture::waitAnyInterior(std::vector<VideoCapture>& v_captures, std::vector<int>& state, const int & timeout) |
There was a problem hiding this comment.
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; } |
There was a problem hiding this comment.
Device handles are implementation detail, remove from common interface
modules/videoio/src/videoio_c.cpp
Outdated
|
|
||
| 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; |
modules/videoio/test/test_camera.cpp
Outdated
| Mat frame1; | ||
|
|
||
| //false start | ||
| cap1>>frame1; |
modules/videoio/perf/perf_input.cpp
Outdated
| Mat frame1; | ||
| int ITERATION_COUNT = 500; | ||
|
|
||
| //false start |
There was a problem hiding this comment.
Why is this needed? Write some meaningful comment
|
Need test for "waitAny" with single VIdeoCapture. |
modules/videoio/src/cap.cpp
Outdated
| } | ||
| } | ||
|
|
||
| State.resize(v_captures.size()); |
There was a problem hiding this comment.
Instead of resizing better just check size and bail with error on mismatch
…ted, getDeviceHandle() deleted
| CV_WRAP virtual bool grab(); | ||
|
|
||
|
|
||
| CV_WRAP static bool waitAny(std::vector<VideoCapture>&, std::vector<int>&, const int &); |
There was a problem hiding this comment.
- just
intinstead ofconst int & - add names
- use int64
modules/videoio/perf/perf_input.cpp
Outdated
| #else | ||
| char* datapath_dir = OPENCV_TEST_CAMERA_LIST; | ||
| #endif | ||
| ASSERT_FALSE(datapath_dir == nullptr || datapath_dir[0] == '\0'); |
modules/videoio/perf/perf_input.cpp
Outdated
| PERF_TEST(, DISABLED_GetReadFrame) | ||
| { | ||
| int ITERATION_COUNT = 50; //number of expected frames from all cameras | ||
| #ifndef WINRT |
| { | ||
| std::vector< CvCapture * > capPtrs; | ||
|
|
||
| for (size_t capnum = 0; capnum < deviceHandles.size(); ++capnum) |
|
|
||
| for (size_t capnum = 0; capnum < deviceHandles.size(); ++capnum) | ||
| { | ||
| CV_Assert(dynamic_cast< LegacyCapture * >(deviceHandles[capnum]) != nullptr); |
modules/videoio/src/cap_v4l.cpp
Outdated
| 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; |
modules/videoio/src/cap_v4l.cpp
Outdated
|
|
||
| std::vector<pollfd> fds; | ||
|
|
||
| for (size_t dhand_num = 0; dhand_num < deviceHandles.size(); ++dhand_num) |
modules/videoio/test/test_camera.cpp
Outdated
| TEST_P(DISABLED_videoio_fps, v4l_poll_fps) | ||
| { | ||
| //Two identical cameras | ||
| VideoCapture cap1(0, CAP_V4L); |
modules/videoio/src/cap_v4l.cpp
Outdated
| { | ||
| if(pointers[ptr_num]) | ||
| { | ||
| CV_Assert(dynamic_cast< CvCaptureCAM_V4L * >(pointers[ptr_num]) != nullptr); |
| 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;} |
| 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; } |
modules/videoio/perf/perf_input.cpp
Outdated
| "highgui/video/big_buck_bunny.wmv" | ||
| }; | ||
|
|
||
| static char* set_environment_variable() |
modules/videoio/src/cap.cpp
Outdated
| } | ||
| if(state[cupture_num] == CAP_CAM_ERROR) | ||
| { | ||
| //printf("error cam no. %d \n", cupture_num); |
modules/videoio/src/cap_v4l.cpp
Outdated
| int ret = poll(fds.data(), fds.size(), timeout); | ||
|
|
||
| if(ret == -1) | ||
| return false; |
modules/videoio/src/cap_v4l.cpp
Outdated
| } | ||
| else | ||
| { | ||
| perror("CvCapture pointer is null"); |
There was a problem hiding this comment.
perror checks last errono. Is is not deeded there. Only after poll
modules/videoio/perf/perf_input.cpp
Outdated
| "highgui/video/big_buck_bunny.wmv" | ||
| }; | ||
|
|
||
| static char* set_environment_variable() |
|
|
Tests passed. |
| typedef std::vector<DMatch> vector_DMatch; | ||
| typedef std::vector<String> vector_String; | ||
| typedef std::vector<Scalar> vector_Scalar; | ||
|
|
There was a problem hiding this comment.
Please rollback unrelated changes
| //! @} videoio_flags_others | ||
|
|
||
|
|
||
| enum statecam |
There was a problem hiding this comment.
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 ); |
There was a problem hiding this comment.
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).
modules/videoio/perf/perf_input.cpp
Outdated
| #ifndef WINRT | ||
| return getenv("OPENCV_TEST_CAMERA_LIST"); | ||
| #else | ||
| return OPENCV_TEST_CAMERA_LIST; |
There was a problem hiding this comment.
There is no such variable, build for WinRT will be broken.
modules/videoio/perf/perf_input.cpp
Outdated
|
|
||
| static char* get_cameras_list() | ||
| { | ||
| #ifndef WINRT |
There was a problem hiding this comment.
Use #ifndef NO_GETENV check here
modules/videoio/perf/perf_input.cpp
Outdated
| path += datapath_dir[step]; | ||
| ++step; | ||
| } | ||
| Mat frame1, frame2, processed1, processed2; |
There was a problem hiding this comment.
ASSERT_EQUAL(VCM.size(), 2u);
Mat frame[2], processed[2];
modules/videoio/src/cap_v4l.cpp
Outdated
| std::vector<int> deviceHandles; | ||
| for(const auto& ptr_num : pointers) | ||
| { | ||
| if(ptr_num) |
There was a problem hiding this comment.
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();
modules/videoio/src/cap_v4l.cpp
Outdated
| state[struct_num] = CAP_CAM_READY; | ||
| } | ||
| else | ||
| if((fds[struct_num].revents & POLLERR) != 0) |
There was a problem hiding this comment.
Please balance braces, its either
if ()
foo();
else
bar();either
if ()
{
foo();
}
else
{
bar();
}
modules/videoio/src/cap_v4l.cpp
Outdated
| return false; | ||
| } | ||
|
|
||
| bool CvCaptureCAM_V4L::setFirstCapture() |
There was a problem hiding this comment.
What does this method do? There is duplicated code in grabFrame. Duplicated code is bad practice.
modules/videoio/src/cap_v4l.cpp
Outdated
|
|
||
| bool CvCaptureCAM_V4L::deviceHandlePoll(const std::vector<int>& deviceHandles, std::vector<int>& state, int64_t timeout) | ||
| { | ||
| if(!deviceHandles.empty()) |
There was a problem hiding this comment.
Please fix indents in this function.
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()
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()
Method WaitAny()
Parameters:
Net: Face-detection-adas-0001;
Size: (1, 3, 384, 672);
Launch time: 6.16 ms.
Method read()
Method WaitAny()