Explanation.
- Batch capture. Requesting N frames and process them.
bool Camera::batchCapture()
{
m_abortBatchCapture = false;
std::thread t{ & Camera::dispatch, this };
for( size_t i{}; i < m_captureEveryFrameN * m_scanShiftNumber * m_camerasNum; ++ i )
{
Argus::Status status{};
const auto result{ m_iCaptureSession->capture( m_request.get(), Argus::TIMEOUT_INFINITE, & status ) };
if( result == 0 )
ORIGINATE_ERROR( "Failed to submit capture request (status %x)", status );
if( m_abortBatchCapture ) break;
}
t.join();
return true;
}
void Camera::dispatch()
{
size_t frameCounter{};
while( true )
{
std::vector< EGLStream::Image * > images( m_camerasNum );
size_t cameraId{};
for( cameraId = 0; cameraId < m_camerasNum; ++ cameraId )
{
Argus::Status status{};
Argus::UniqueObj< EGLStream::Frame > frame{ m_iFrameConsumers.at( cameraId )->acquireFrame( Argus::TIMEOUT_INFINITE, & status ) };
EGLStream::IFrame * iFrame{ Argus::interface_cast< EGLStream::IFrame >( frame ) };
images.at( cameraId ) = iFrame->getImage();
}
processFrames( images, m_captureCropYLeft, m_captureCropYRight, frameCounter );
frameCounter ++;
if( frameCounter >= m_scanShiftNumber ) break;
if( m_abortBatchCapture ) break;
}
}
- Single capture. Requesting 1 frame and process it.
bool capture()
{
Argus::Status status{};
const auto result{ m_iCaptureSession->capture( m_request.get(), Argus::TIMEOUT_INFINITE, & status ) };
if( result == 0 )
ORIGINATE_ERROR( "Failed to submit capture request (status %x)", status );
size_t cameraId{};
for( cameraId = 0; cameraId < m_camerasNum; ++ cameraId )
{
Argus::Status status{};
Argus::UniqueObj< EGLStream::Frame > frame{ m_iFrameConsumers.at( cameraId )->acquireFrame( Argus::TIMEOUT_INFINITE, & status ) };
EGLStream::IFrame * iFrame{ Argus::interface_cast< EGLStream::IFrame >( frame ) };
images.at( cameraId ) = iFrame->getImage();
}
processFrames( images, m_captureCropYLeft, m_captureCropYRight, counter );
return true;
}
Green picture shows the difference of these 2 cases. Frames stitched together.
Top side: capture N frames using case 2 code.
Bottom side: request N frames and dispatch them using case 1 code.
Top side has stable exposure as we can see (every request ISP takes 3-5 frames and latest frame is a result, it takes ~200ms). There is shadow from lights, but it is not floating exposure.
Bottom has floating exposure (all requested frames has ~33ms framerate).
configureSensor() code the same for both cases.
So “single capture” case is a hack, for fixing exposure bug. Cause 200ms was ok for our task.
But now we need batch capture with real fps.
It is old bug existing in all Jetson platforms (or Argus or Leopard Imaging drivers/hardware). Or my misunderstanding or Jetson hardware limitation.
It is not lights or power supply issue. We did many tests with different power sources and all type of lights.
To reproduce it you can take lightgray background, any led lights and take N frames from 50cm distance inside closed box. Our target exposure is 10e6.