Repository navigation
Spinnaker Driver Rework - #45
guyfleeman wants to merge 8 commits into
Conversation
…-processor into dev/will/spinnaker_driver_rework
lixfel
left a comment
There was a problem hiding this comment.
I'm not yet completely through, but these are my first thoughts on the pull request.
I would also prefer if this PR would be based and intended to be merged to master, as this should be independent of the new UI interface.
| - Renamed: `GammaEnabled` instead of `GammaEnable`. | ||
| - Missing: `AcquisitionResultingFrameRate`, `AutoExposureMeteringMode`, `AutoExposureControlPriority`, | ||
| `BalanceWhiteAutoProfile`. | ||
| - Gamma is unavailable in Raw/Bayer pixel formats. |
There was a problem hiding this comment.
This is definitely not the case on the league camera.
There was a problem hiding this comment.
Okay. I think in this case the code does work but the docs are wrong. I'll confirm and address both as needed.
| # Spinnaker, mvIMPACT or OpenCV(v4l2) camera id | ||
| #id: 0 | ||
| # Spinnaker camera serial number (if set id is ignored). Recommended with multiple cameras, as id order is not stable. | ||
| #serial: "12345678" |
There was a problem hiding this comment.
As I want to keep the API (especially with the new network interface) uniform across drivers: How about sorting cameras by serial id? Then you have a guaranteed linear numerical id (even though the id order has never been observed as unstable).
Because otherwise we would need some tooling advertising available cameras.
There was a problem hiding this comment.
A few potential gotchas here. If you are running multiple cameras and one drops and system restarts they'll all renumber sorting by serial ID, but I think that's trending in the right direction. This could occur with PoE power cycle, or USB DC. This only impacts setups where more than one camera is connect to a physical machine. e.g. not SSL comp, but does affect PTO, and at least two labs I know of (A-Team and RJ).
What if we sort by serial to assign ID as you suggest. OpenCV already takes a path, we could do something similar and change it to "device" or some other key, and then that would be uniform across drivers. For OpenCV that'd be a path (one of the by UUID or bus paths), on spinnaker or mvimpact a serial number. Future drivers should be able to offer one or the other.
The spinnaker_probe binary here does have basic enumeration capability. We could rip that subset out.
There was a problem hiding this comment.
Yeah, or reuse the path, i think that's a good idea, maybe renaming it to "device", for OpenCV it's a path, for Spinnaker the serial id, for Mvimpact unused for now.
| configurePacketSize(); | ||
| } | ||
|
|
||
| void SpinnakerDriver::reportOnce(const std::string& message) { |
There was a problem hiding this comment.
I think this feature makes a lot of sense in a generic context. Maybe move to log.h?
| Spinnaker::CameraPtr pCam; | ||
|
|
||
| // Acquisition starts on the first readImage(), so the settings applied after construction | ||
| // (resolution in particular) can still be written; the camera locks them while streaming. |
There was a problem hiding this comment.
As this will be unintuitive when doing reconfiguration via the web ui (and possibly impossible): When changing resolution, we should instead do in setResolution(): stop streaming, change resolution, restart streaming. Because we will hit readImage with 99% certainty before receiving our first config...
And then we don't need the acquiring stuff
|
|
||
| if(frametime == 0.0) | ||
| WARN("Camera reports no frame rate, frame time overruns will not be detected"); | ||
| frametime = INFINITY; |
There was a problem hiding this comment.
I would set it to 30 FPS (like in OpenCV with files), as this I would consider a bottom line we should definitely warn about.
And maybe we should warnOnce about the no reported framerate.
| if(!acquiring) | ||
| startAcquisition(); | ||
|
|
||
| // The resulting frame rate changes with (auto) exposure, so poll it occasionally |
There was a problem hiding this comment.
To detect a runaway exposure I would recommend against regularily polling the frame rate, maybe just once after setting the exposure? (would simplify things as well)
There was a problem hiding this comment.
This should be conditional. With AutoExposure + frame-rate control off, this will drift. We can only poll when the combo exists to reduce overhead since the league unlikely to want AutoExposure + no frame rate control.
| // Spinnaker buffer sizes need to be 1024 byte aligned | ||
| std::shared_ptr<RawImage> buffer = std::make_shared<RawImage>(CLArray((width * height + 1023)/1024 * 1024), &PixelFormat::RGGB8, width/2, height/2, "spinnaker"); | ||
| const int width = (int)pCam->Width.GetValue(); | ||
| const int height = (int)pCam->Height.GetValue(); |
There was a problem hiding this comment.
Is there an issue with just allocating max size buffers once?
There was a problem hiding this comment.
Yes but RawImage is const w/h. We can push this down to the RawImgae wrapper layer and only allocate once at max size.
| float SpinnakerDriver::getGamma() { | ||
| return pCam->Gamma.GetValue(); | ||
| // First generation cameras apply no gamma to Raw/Bayer formats, the node is unavailable then | ||
| Spinnaker::GenApi::CFloatPtr gamma = pCam->GetNodeMap().GetNode("Gamma"); |
There was a problem hiding this comment.
Is there a difference between pCam->Gamma and pCam->GetNodeMap().GetNode("Gamma")? If not I would prefer the former.
There was a problem hiding this comment.
This can be done.
| return nullptr; | ||
| } | ||
|
|
||
| bool SpinnakerDriver::setBool(const SpinnakerFeature& feature, bool value) { |
There was a problem hiding this comment.
I'm not 100% familiar with C++ template shenanigans, but wouldn't it be possible to have a generic set-function which templates to the different types?
There was a problem hiding this comment.
This can be done.
| } | ||
| } | ||
|
|
||
| bool SpinnakerDriver::setEnum(const SpinnakerFeature& feature, const char* entry) { |
There was a problem hiding this comment.
As the API Enums shouldn't change depending on camera, can't we use the actual enum constants and enum entries instead of strings?
There was a problem hiding this comment.
This can mostly be done, but will have some mapping for Bayer matching still. I'll take a crack at cleaning it up.
| const std::string pattern = entry != "Raw8" ? entry.substr(0, entry.size() - 1) | ||
| : IsReadable(pCam->PixelColorFilter) ? pCam->PixelColorFilter.ToString().c_str() : ""; |
There was a problem hiding this comment.
While a little more verbose, an immediately-invoked lambda may be more readable than nested conditional operators. This is just a preference thing.
| const std::string pattern = entry != "Raw8" ? entry.substr(0, entry.size() - 1) | |
| : IsReadable(pCam->PixelColorFilter) ? pCam->PixelColorFilter.ToString().c_str() : ""; | |
| const std::string pattern = []{ | |
| if (entry != "Raw8") { | |
| return entry.substr(0, entry.size() - 1); | |
| } else if (IsReadable(pCam->PixelColorFilter)) { | |
| return pCam->PixelColorFilter.ToString().c_str(); | |
| } else { | |
| return ""; | |
| } | |
| }(); |
This is the initial attempt at a spinnaker driver rework, properly supporting mix-generation spinnaker cameras and covering configuration edge cases that were not supported. These changes were tested on two BFLY-PGE-13E4C cameras, and still need testing on league cameras.
This PR incorporates #42 and #44.
Let me know you want this split in to multiple PRs.
Summary:
Items discovered and fixed:
New features: