@ -49,12 +49,32 @@
# include <arv.h>
//
// This file provides wrapper for using Aravis SDK library to access GigE Vision cameras.
// aravis-0.6 library shall be installed else this code will not be included in build.
// To include this module invoke cmake with -DWITH_ARAVIS=ON
//
// Please obvserve, that jumbo frames are required when high fps & 16bit data is selected.
// (camera, switches/routers and the computer this software is running on)
//
// Basic usage: VideoCapture cap(CAP_ARAVIS + <camera id>);
//
// Supported properties:
// CAP_PROP_AUTO_EXPOSURE(0|1)
// CAP_PROP_EXPOSURE(t), t in seconds
// CAP_PROP_GAIN(g), g >=0 or -1 for automatic control if CAP_PROP_AUTO_EXPOSURE is true
// CAP_PROP_FPS(f)
// CAP_PROP_FOURCC(type)
//
// Supported types of data:
// video/x-raw, fourcc:'GRAY' -> 8bit, 1 channel
// video/x-raw, fourcc:'GREY' -> 8bit, 1 channel
// video/x-raw, fourcc:'Y800' -> 8bit, 1 channel
// video/x-raw, fourcc:'Y12 ' -> 12bit, 1 channel
//
# define MODE_GRAY8 CV_FOURCC_MACRO('G','R','E','Y')
# define MODE_GRAY12 CV_FOURCC_MACRO('Y','1','2',' ')
# define MODE_GREY CV_FOURCC_MACRO('G','R','E','Y')
# define MODE_Y800 CV_FOURCC_MACRO('Y','8','0','0')
# define MODE_Y12 CV_FOURCC_MACRO('Y','1','2',' ')
# define BETWEEN(a,b,c) ((a) < (b) ? (b) : ((a) > (c) ? (c) : (a) ))
@ -89,6 +109,8 @@ protected:
bool getDeviceNameById ( int id , std : : string & device ) ;
void autoExposureControl ( IplImage * ) ;
ArvCamera * camera ; // Camera to control.
ArvStream * stream ; // Object for video stream reception.
void * framebuffer ; //
@ -108,6 +130,11 @@ protected:
bool exposureAvailable ;
double exposureMin ; // Camera's minimum exposure time.
double exposureMax ; // Camera's maximum exposure time.
bool controlExposure ; // Flag if automatic exposure shall be done by this SW
bool autoGain ;
double targetGrey ; // Target grey value (mid grey))
gint64 * pixelFormats ;
guint pixelFormatsCnt ;
@ -122,6 +149,7 @@ protected:
double gain ; // current value of gain
IplImage * frame ; // local frame copy
uint64_t framesCnt ; // number of retrieved frames
} ;
@ -135,6 +163,9 @@ CvCaptureCAM_Aravis::CvCaptureCAM_Aravis()
widthMin = widthMax = heightMin = heightMax = 0 ;
fpsMin = fpsMax = gainMin = gainMax = exposureMin = exposureMax = 0 ;
controlExposure = false ;
targetGrey = 0 ;
framesCnt = 0 ;
num_buffers = 50 ;
frame = NULL ;
@ -142,20 +173,17 @@ CvCaptureCAM_Aravis::CvCaptureCAM_Aravis()
void CvCaptureCAM_Aravis : : close ( )
{
stopCapture ( ) ;
if ( camera )
stopCapture ( ) ;
}
bool CvCaptureCAM_Aravis : : getDeviceNameById ( int id , std : : string & device )
{
arv_update_device_list ( ) ;
int n_devices = arv_get_n_devices ( ) ;
for ( int i = 0 ; i < n_devices ; i + + ) {
if ( id = = i ) {
device = arv_get_device_id ( i ) ;
return true ;
}
if ( id > 0 & & id < arv_get_n_devices ( ) ) {
device = arv_get_device_id ( id ) ;
return true ;
}
return false ;
@ -172,7 +200,7 @@ bool CvCaptureCAM_Aravis::create( int index )
bool CvCaptureCAM_Aravis : : init_buffers ( )
{
if ( stream ) {
if ( stream ) {
g_object_unref ( stream ) ;
stream = NULL ;
}
@ -199,7 +227,7 @@ bool CvCaptureCAM_Aravis::init_buffers()
bool CvCaptureCAM_Aravis : : open ( int index )
{
if ( create ( index ) ) {
if ( create ( index ) ) {
// fetch properties bounds
pixelFormats = arv_camera_get_available_pixel_formats ( camera , & pixelFormatsCnt ) ;
@ -216,8 +244,8 @@ bool CvCaptureCAM_Aravis::open( int index )
// get initial values
pixelFormat = arv_camera_get_pixel_format ( camera ) ;
exposure = arv_camera_get_exposure_time ( camera ) ;
gain = arv_camera_get_gain ( camera ) ;
exposure = exposureAvailable ? arv_camera_get_exposure_time ( camera ) : 0 ;
gain = gainAvailable ? arv_camera_get_gain ( camera ) : 0 ;
fps = arv_camera_get_frame_rate ( camera ) ;
return startCapture ( ) ;
@ -227,26 +255,30 @@ bool CvCaptureCAM_Aravis::open( int index )
bool CvCaptureCAM_Aravis : : grabFrame ( )
{
ArvBuffer * arv_buffer = NULL ;
int max_tries = 10 ;
int tries = 0 ;
for ( ; tries < max_tries ; tries + + ) {
arv_buffer = arv_stream_timeout_pop_buffer ( stream , 200000 ) ;
if ( arv_buffer ! = NULL & & arv_buffer_get_status ( arv_buffer ) ! = ARV_BUFFER_STATUS_SUCCESS ) {
arv_stream_push_buffer ( stream , arv_buffer ) ;
} else break ;
}
if ( tries = = max_tries )
return false ;
// remove content of previous frame
framebuffer = NULL ;
size_t buffer_size ;
framebuffer = ( void * ) arv_buffer_get_data ( arv_buffer , & buffer_size ) ;
if ( stream ) {
ArvBuffer * arv_buffer = NULL ;
int max_tries = 10 ;
int tries = 0 ;
for ( ; tries < max_tries ; tries + + ) {
arv_buffer = arv_stream_timeout_pop_buffer ( stream , 200000 ) ;
if ( arv_buffer ! = NULL & & arv_buffer_get_status ( arv_buffer ) ! = ARV_BUFFER_STATUS_SUCCESS ) {
arv_stream_push_buffer ( stream , arv_buffer ) ;
} else break ;
}
if ( tries < max_tries ) {
size_t buffer_size ;
framebuffer = ( void * ) arv_buffer_get_data ( arv_buffer , & buffer_size ) ;
arv_buffer_get_image_region ( arv_buffer , NULL , NULL , & width , & height ) ;
arv_buffer_get_image_region ( arv_buffer , NULL , NULL , & width , & height ) ;
arv_stream_push_buffer ( stream , arv_buffer ) ;
return true ;
arv_stream_push_buffer ( stream , arv_buffer ) ;
return true ;
}
}
return false ;
}
IplImage * CvCaptureCAM_Aravis : : retrieveFrame ( int )
@ -279,15 +311,99 @@ IplImage* CvCaptureCAM_Aravis::retrieveFrame(int)
}
cvCopy ( & src , frame ) ;
if ( controlExposure & & ! ( framesCnt % 2 ) ) {
// control exposure every second frame
// i.e. skip frame taken with previous exposure setup
autoExposureControl ( frame ) ;
}
framesCnt + + ;
return frame ;
}
}
return NULL ;
}
void CvCaptureCAM_Aravis : : autoExposureControl ( IplImage * image )
{
// Software control of exposure parameters utilizing
// automatic change of exposure time & gain
// Priority is set as follows:
// - to increase brightness, first increase time then gain
// - to decrease brightness, first decrease gain then time
cv : : Mat m = cv : : cvarrToMat ( image ) ;
// calc mean value for luminance or green channel
double brightness = cv : : mean ( m ) [ image - > nChannels > 1 ? 1 : 0 ] ;
if ( brightness < 1 ) brightness = 1 ;
// mid point - 100 % means no change
static const double dmid = 100 ;
// distance from optimal value as a percentage
double d = ( targetGrey * dmid ) / brightness ;
// if change of value requires intervention
if ( fabs ( d - dmid ) > 5 ) {
if ( d > = dmid ) d = ( d + ( dmid * 2 ) ) / 3 ;
double ng = 0 , ne = 0 , maxe = 1e6 / fps ;
double ev = log ( d / dmid ) / log ( 2 ) ;
if ( gainAvailable & & autoGain ) {
// depending on device single gain step may equal to 1 or 1/3 EV
double ngg = gain + ev ;
ng = BETWEEN ( ngg , gainMin , gainMax ) ;
if ( ng < gain ) {
// piority 1 - reduce gain
arv_camera_set_gain ( camera , ( gain = ng ) ) ;
return ;
}
}
if ( exposureAvailable ) {
double nee = ( exposure * d ) / dmid ;
ne = BETWEEN ( nee , exposureMin , maxe ) ;
if ( abs ( exposure - ne ) > 2 ) {
// priority 2 - control of exposure time
arv_camera_set_exposure_time ( camera , ( exposure = ne ) ) ;
return ;
}
}
if ( gainAvailable & & autoGain ) {
if ( exposureAvailable ) {
// exposure at maximum - increase gain if possible
if ( ng > gain & & ne > = maxe ) {
if ( ng < gainMax ) {
arv_camera_set_gain ( camera , ( gain = ng ) ) ;
}
return ;
}
// if gain can be reduced - do it
if ( gain > gainMin & & exposure < maxe ) {
exposure = BETWEEN ( ne * 1.05 , exposureMin , maxe ) ;
arv_camera_set_exposure_time ( camera , exposure ) ;
}
} else {
arv_camera_set_gain ( camera , ( gain = ng ) ) ;
}
}
}
}
double CvCaptureCAM_Aravis : : getProperty ( int property_id ) const
{
switch ( property_id ) {
switch ( property_id ) {
case CV_CAP_PROP_AUTO_EXPOSURE :
return ( controlExposure ? 1 : 0 ) ;
case CV_CAP_PROP_EXPOSURE :
if ( exposureAvailable ) {
/* exposure time in seconds, like 1/100 s */
@ -312,9 +428,9 @@ double CvCaptureCAM_Aravis::getProperty( int property_id ) const
ArvPixelFormat currFormat = arv_camera_get_pixel_format ( camera ) ;
switch ( currFormat ) {
case ARV_PIXEL_FORMAT_MONO_8 :
return MODE_GRA Y8 ;
return MODE_Y800 ;
case ARV_PIXEL_FORMAT_MONO_12 :
return MODE_GRA Y12 ;
return MODE_Y12 ;
}
}
}
@ -323,11 +439,21 @@ double CvCaptureCAM_Aravis::getProperty( int property_id ) const
bool CvCaptureCAM_Aravis : : setProperty ( int property_id , double value )
{
switch ( property_id ) {
switch ( property_id ) {
case CV_CAP_PROP_AUTO_EXPOSURE :
if ( exposureAvailable | | gainAvailable ) {
if ( ( controlExposure = ( bool ) ( int ) value ) ) {
exposure = exposureAvailable ? arv_camera_get_exposure_time ( camera ) : 0 ;
gain = gainAvailable ? arv_camera_get_gain ( camera ) : 0 ;
}
}
break ;
case CV_CAP_PROP_EXPOSURE :
if ( exposureAvailable ) {
/* exposure time in seconds, like 1/100 s */
value * = 1e6 ; // -> from s to us
arv_camera_set_exposure_time ( camera , exposure = BETWEEN ( value , exposureMin , exposureMax ) ) ;
break ;
} else return false ;
@ -340,6 +466,9 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )
case CV_CAP_PROP_GAIN :
if ( gainAvailable ) {
if ( ( autoGain = ( - 1 = = value ) ) )
break ;
arv_camera_set_gain ( camera , gain = BETWEEN ( value , gainMin , gainMax ) ) ;
break ;
} else return false ;
@ -348,11 +477,14 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )
{
ArvPixelFormat newFormat = pixelFormat ;
switch ( ( int ) value ) {
case MODE_GRAY8 :
case MODE_GREY :
case MODE_Y800 :
newFormat = ARV_PIXEL_FORMAT_MONO_8 ;
targetGrey = 128 ;
break ;
case MODE_GRA Y12 :
case MODE_Y12 :
newFormat = ARV_PIXEL_FORMAT_MONO_12 ;
targetGrey = 2048 ;
break ;
}
if ( newFormat ! = pixelFormat ) {
@ -380,7 +512,7 @@ void CvCaptureCAM_Aravis::stopCapture()
bool CvCaptureCAM_Aravis : : startCapture ( )
{
if ( init_buffers ( ) ) {
if ( init_buffers ( ) ) {
arv_camera_set_acquisition_mode ( camera , ARV_ACQUISITION_MODE_CONTINUOUS ) ;
arv_device_set_string_feature_value ( arv_camera_get_device ( camera ) , " TriggerMode " , " Off " ) ;
arv_camera_start_acquisition ( camera ) ;
@ -394,8 +526,9 @@ CvCapture* cvCreateCameraCapture_Aravis( int index )
{
CvCaptureCAM_Aravis * capture = new CvCaptureCAM_Aravis ;
if ( capture - > open ( index ) )
if ( capture - > open ( index ) ) {
return capture ;
}
delete capture ;
return NULL ;