From e77bc24b96d485cee86c718e386b4975e1295d32 Mon Sep 17 00:00:00 2001 From: Arek Date: Sat, 22 Oct 2016 18:07:55 +0200 Subject: [PATCH] Merge pull request #7518 from ArkadiuszRaj:aravis-buffer-status Aravis several updates * Fix adressing camera with id=0 * Aravis buffer property control & status added * Modify of autoexposure algorith, ream frame ID from aravis + new properites * Change of macro name * VideoCapture now returns no frame on camera disconnecion * Allow aravis-0.4 usage, proper camera object release. --- CMakeLists.txt | 2 +- cmake/OpenCVFindLibsVideo.cmake | 4 +- modules/videoio/src/cap_aravis.cpp | 127 ++++++++++++++++++++++++++----------- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 399e07f..6b84989 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1125,7 +1125,7 @@ if(DEFINED WITH_GIGEAPI) endif(DEFINED WITH_GIGEAPI) if(DEFINED WITH_ARAVIS) - status(" Aravis SDK:" HAVE_ARAVIS_API THEN YES ELSE NO) + status(" Aravis SDK:" HAVE_ARAVIS_API THEN "YES (${ARAVIS_LIBRARIES})" ELSE NO) endif(DEFINED WITH_ARAVIS) if(DEFINED APPLE) diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index 4fe272f..3f43717 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -129,9 +129,9 @@ ocv_clear_vars(HAVE_ARAVIS_API) if(WITH_ARAVIS) find_path(ARAVIS_INCLUDE_PATH "arv.h" PATHS /usr/local /var /opt /usr ENV ProgramFiles ENV ProgramW6432 - PATH_SUFFIXES include "aravis-0.6" + PATH_SUFFIXES include "aravis-0.6" "aravis-0.4" DOC "The path to Aravis SDK headers") - find_library(ARAVIS_LIBRARIES "aravis-0.6") + find_library(ARAVIS_LIBRARIES NAMES "aravis-0.6" "aravis-0.4" ) if(ARAVIS_LIBRARIES AND ARAVIS_INCLUDE_PATH) set(HAVE_ARAVIS_API TRUE) endif() diff --git a/modules/videoio/src/cap_aravis.cpp b/modules/videoio/src/cap_aravis.cpp index 3a82f3d..3423ca6 100644 --- a/modules/videoio/src/cap_aravis.cpp +++ b/modules/videoio/src/cap_aravis.cpp @@ -51,7 +51,8 @@ // // 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. +// Aravis library (version 0.4 or 0.6) 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. @@ -60,11 +61,17 @@ // Basic usage: VideoCapture cap(CAP_ARAVIS + ); // // Supported properties: +// read/write // 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) +// CAP_PROP_BUFFERSIZE(n) +// read only: +// CAP_PROP_POS_MSEC +// CAP_PROP_FRAME_WIDTH +// CAP_PROP_FRAME_HEIGHT // // Supported types of data: // video/x-raw, fourcc:'GREY' -> 8bit, 1 channel @@ -76,7 +83,7 @@ #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) )) +#define CLIP(a,b,c) (cv::max(cv::min((a),(c)),(b))) /********************* Capturing video from camera via Aravis *********************/ @@ -141,15 +148,22 @@ protected: int num_buffers; // number of payload transmission buffers - ArvPixelFormat pixelFormat; // current pixel format - int width; // current width of frame - int height; // current height of image - double fps; // current fps + ArvPixelFormat pixelFormat; // pixel format + + int xoffset; // current frame region x offset + int yoffset; // current frame region y offset + int width; // current frame width of frame + int height; // current frame height of image + + double fps; // current value of fps double exposure; // current value of exposure time double gain; // current value of gain + double midGrey; // current value of mid grey (brightness) + + unsigned frameID; // current frame id + unsigned prevFrameID; IplImage *frame; // local frame copy - uint64_t framesCnt; // number of retrieved frames }; @@ -162,10 +176,11 @@ CvCaptureCAM_Aravis::CvCaptureCAM_Aravis() payload = 0; widthMin = widthMax = heightMin = heightMax = 0; + xoffset = yoffset = width = height = 0; fpsMin = fpsMax = gainMin = gainMax = exposureMin = exposureMax = 0; controlExposure = false; targetGrey = 0; - framesCnt = 0; + frameID = prevFrameID = 0; num_buffers = 50; frame = NULL; @@ -175,13 +190,16 @@ void CvCaptureCAM_Aravis::close() { if(camera) stopCapture(); + + g_object_unref(camera); + camera = NULL; } bool CvCaptureCAM_Aravis::getDeviceNameById(int id, std::string &device) { arv_update_device_list(); - if(id > 0 && id < arv_get_n_devices()){ + if((id >= 0) && (id < (int)arv_get_n_devices())) { device = arv_get_device_id(id); return true; } @@ -268,11 +286,15 @@ bool CvCaptureCAM_Aravis::grabFrame() arv_stream_push_buffer (stream, arv_buffer); } else break; } - if (tries < max_tries) { + if(arv_buffer != NULL && 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); + // retieve image size properites + arv_buffer_get_image_region (arv_buffer, &xoffset, &yoffset, &width, &height); + + // retieve image ID set by camera + frameID = arv_buffer_get_frame_id(arv_buffer); arv_stream_push_buffer(stream, arv_buffer); return true; @@ -311,13 +333,12 @@ IplImage* CvCaptureCAM_Aravis::retrieveFrame(int) } cvCopy(&src, frame); - if(controlExposure && !(framesCnt % 2)) { + if(controlExposure && ((frameID - prevFrameID) > 1)) { // control exposure every second frame // i.e. skip frame taken with previous exposure setup autoExposureControl(frame); } - framesCnt++; return frame; } } @@ -344,18 +365,21 @@ void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image) // distance from optimal value as a percentage double d = (targetGrey * dmid) / brightness; + if(d >= dmid) d = ( d + (dmid * 2) ) / 3; + + prevFrameID = frameID; + midGrey = brightness; + + double maxe = 1e6 / fps; + double ne = CLIP( ( exposure * d ) / dmid, exposureMin, maxe); // 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); + double ev, ng = 0; 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); + ev = log( d / dmid ) / log(2); + ng = CLIP( gain + ev, gainMin, gainMax); if( ng < gain ) { // piority 1 - reduce gain @@ -365,13 +389,9 @@ void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image) } 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; } } @@ -379,28 +399,39 @@ void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image) 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)); - } + if(ng > gain && ng < gainMax && ne >= maxe) { + 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 { + // priority 3 - increase gain arv_camera_set_gain(camera, (gain = ng)); + return; } } } + + // if gain can be reduced - do it + if(gainAvailable && autoGain && exposureAvailable) { + if(gain > gainMin && exposure < maxe) { + exposure = CLIP( ne * 1.05, exposureMin, maxe); + arv_camera_set_exposure_time(camera, exposure ); + } + } } double CvCaptureCAM_Aravis::getProperty( int property_id ) const { switch(property_id) { + case CV_CAP_PROP_POS_MSEC: + return (double)frameID/fps; + + case CV_CAP_PROP_FRAME_WIDTH: + return width; + + case CV_CAP_PROP_FRAME_HEIGHT: + return height; + case CV_CAP_PROP_AUTO_EXPOSURE: return (controlExposure ? 1 : 0); @@ -433,6 +464,16 @@ double CvCaptureCAM_Aravis::getProperty( int property_id ) const return MODE_Y12; } } + break; + + case CV_CAP_PROP_BUFFERSIZE: + if(stream) { + int in, out; + arv_stream_get_n_buffers(stream, &in, &out); + // return number of available buffers in Aravis output queue + return out; + } + break; } return -1.0; } @@ -454,13 +495,13 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value ) /* 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)); + arv_camera_set_exposure_time(camera, exposure = CLIP(value, exposureMin, exposureMax)); break; } else return false; case CV_CAP_PROP_FPS: if(fpsAvailable) { - arv_camera_set_frame_rate(camera, fps = BETWEEN(value, fpsMin, fpsMax)); + arv_camera_set_frame_rate(camera, fps = CLIP(value, fpsMin, fpsMax)); break; } else return false; @@ -469,7 +510,7 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value ) if ( (autoGain = (-1 == value) ) ) break; - arv_camera_set_gain(camera, gain = BETWEEN(value, gainMin, gainMax)); + arv_camera_set_gain(camera, gain = CLIP(value, gainMin, gainMax)); break; } else return false; @@ -495,6 +536,18 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value ) } break; + case CV_CAP_PROP_BUFFERSIZE: + { + int x = (int)value; + if((x > 0) && (x != num_buffers)) { + stopCapture(); + num_buffers = x; + startCapture(); + } + } + break; + + default: return false; } -- 2.7.4