Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Multi Camera Grabbing with Threads #11

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

inbangsa
Copy link
Contributor

example for Grabbing from multiple cameras using thread.

@inbangsa
Copy link
Contributor Author

This pull request is the example solution for the issue

Copy link
Contributor

@tpanzarella tpanzarella left a comment

Choose a reason for hiding this comment

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

I made some specific comments in-line below and I do have a few more.

I think we should revise this a bit before publishing it as the idiomatic way to handle multiple cameras across a thread pool. I do think the triggering chain shown is informative but I believe the example should be more fully worked out. For example, how do you cleanly terminate each thread (e.g., while (true) {...})? Also, I think the callbacks that receive the data should do something with the actual image data (it could simply be accessing one of the underlying image arrays) not just print to the console. Again, just to make the example more realistic and applicable for those looking for instruction.

I have not had the time to actually build and run this code, so, I apologize for not having more concrete observations, but, this is my initial feedback from reading the diffs.

while(true)
{
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(1));
ifm3d::ImageBuffer::Ptr image_buffer = std::make_shared<ifm3d::ImageBuffer>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is a new ImageBuffer being allocated on each loop iteration? This is inefficient. The internals of the ifm-supported image containers intentionally use the .create(...) factory functions on the internally wrapped cv::Mat objects so that memory allocations are kept to a minimum in high frequency frame grabbing loops. Writing the code this way will incur expensive heap allocations for every frame acquired from the camera.

std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(1));
ifm3d::ImageBuffer::Ptr image_buffer = std::make_shared<ifm3d::ImageBuffer>();
const bool in_time = frame_grabber->WaitForFrame(image_buffer.get(), 10000);
callback(image_buffer,in_time);
Copy link
Contributor

Choose a reason for hiding this comment

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

In general, it is an anti-pattern to pass a std::shared_ptr to a function that does not participate in the ownership of the underlying pointer. This is mostly due to performance. For each callback you are incurring a lock -> ref count increment -> unlock then at the end of the function lock -> ref count decrement -> unlock. As with my comment above, in high frequency frame grabbing loops this cost will accumulate to something non-trivial. It would be recommended to pass the naked pointer as callback(...) (I assume) does not participate in the ownership of the ImageBuffer.

Copy link
Member

Choose a reason for hiding this comment

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

So the idea of passing the std::shared_ptr as copy was to have a clean ownership handling. If I do pass the naked pointer the ownership is not defined in a clean way. What happens if the user in the callback enqueue the ImageBuffer in an input queue of another thread for example? The callback goes out of scope the image buffer will be destroyed because the reference count is zero. We will get an dangling pointer. I agree this is not the most performant way but a trade off between performance and a robust example.

Copy link
Contributor

Choose a reason for hiding this comment

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

So, I think the signature of callback does in fact express ownership intentions. In this case, I think you are saying that you expect callback to participate in the ownership of the ImageBuffer. As noted in my message above, I assumed it did not participate in the ownership which is why I made my comment.

I think that perhaps more realistically, the user should pass in the ImageBuffer. This alleviates both of my concerns: 1) too many costly heap allocations; 2) clarity on ownership. Of course, this brings up thread synchronization issues as ImageBuffer is not thread safe, so, perhaps also a mutex (or other lock) should be passed in as well -- better yet, an interface which wraps/subclasses (not sure if a subclass would work) the ImageBuffer, perhaps a ThreadSafeImageBuffer or something like that. This approach solves the two issues called out above and thread safety.

Copy link
Member

Choose a reason for hiding this comment

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

@tpanzarella thanks for pointing out the thread safety issue of the ImageBuffer

@inbangsa inbangsa force-pushed the feature/ex-multiple-camera-parallel-grabber branch from 2337cd6 to 307ebb5 Compare July 8, 2019 11:45
@inbangsa
Copy link
Contributor Author

inbangsa commented Jul 8, 2019

Resolved the issue clean exit of threads, Imagebuffer is now created outside the grabbing loop.
Encapsulated the camera related classes with grabbing inside a struct CameraObject.
Amplitude images are enhance in individual thread and a common thready displays all the images.

@inbangsa
Copy link
Contributor Author

@graugans @theseankelly I have resolved all the issues can we Merge this PR

Copy link
Contributor

@theseankelly theseankelly left a comment

Choose a reason for hiding this comment

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

This still needs some additional work. In addition to the specific comments in the code review:

  • The code doesn't compile for me without changes -- has it been tested??
  • Please audit formatting and consistency, specifically:
    • 2-space tabs everywhere
    • sanitze for trailing whitespace (present on several lines)
    • break up long lines (80 character columns)

CMakeLists.txt Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved

//for configuration of required trigger on camera
void configuration(ifm3d::Camera::Ptr& camera, trigger_mode type)
{
Copy link
Contributor

Choose a reason for hiding this comment

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

consistency: use 2 space tabs everywhere

@inbangsa inbangsa force-pushed the feature/ex-multiple-camera-parallel-grabber branch from a8385c1 to c2da04f Compare August 6, 2020 16:54
ifm-csr pushed a commit that referenced this pull request Mar 29, 2024
Resolve "[Maintenance] OVP8xx dir README"

Closes #11

See merge request syntron/support/csr/ifm3d/ifm3d-examples!14
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