Merge pull request #7518 from ArkadiuszRaj:aravis-buffer-status
authorArek <arek@raj.priv.pl>
Sat, 22 Oct 2016 16:07:55 +0000 (18:07 +0200)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sat, 22 Oct 2016 16:07:55 +0000 (19:07 +0300)
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
cmake/OpenCVFindLibsVideo.cmake
modules/videoio/src/cap_aravis.cpp

index 399e07f..6b84989 100644 (file)
@@ -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)
index 4fe272f..3f43717 100644 (file)
@@ -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()
index 3a82f3d..3423ca6 100644 (file)
@@ -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.
 // Basic usage: VideoCapture cap(CAP_ARAVIS + <camera id>);
 //
 // 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;
     }