Path: blob/master/modules/videoio/src/cap_aravis.cpp
16342 views
////////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//4041//42// The code has been contributed by Arkadiusz Raj on 2016 Oct43//4445#include "precomp.hpp"4647#ifdef HAVE_ARAVIS_API4849#include <arv.h>5051//52// This file provides wrapper for using Aravis SDK library to access GigE Vision cameras.53// Aravis library (version 0.4 or 0.6) shall be installed else this code will not be included in build.54//55// To include this module invoke cmake with -DWITH_ARAVIS=ON56//57// Please obvserve, that jumbo frames are required when high fps & 16bit data is selected.58// (camera, switches/routers and the computer this software is running on)59//60// Basic usage: VideoCapture cap(CAP_ARAVIS + <camera id>);61//62// Supported properties:63// read/write64// CAP_PROP_AUTO_EXPOSURE(0|1)65// CAP_PROP_EXPOSURE(t), t in seconds66// CAP_PROP_BRIGHTNESS (ev), exposure compensation in EV for auto exposure algorithm67// CAP_PROP_GAIN(g), g >=0 or -1 for automatic control if CAP_PROP_AUTO_EXPOSURE is true68// CAP_PROP_FPS(f)69// CAP_PROP_FOURCC(type)70// CAP_PROP_BUFFERSIZE(n)71// read only:72// CAP_PROP_POS_MSEC73// CAP_PROP_FRAME_WIDTH74// CAP_PROP_FRAME_HEIGHT75//76// Supported types of data:77// video/x-raw, fourcc:'GREY' -> 8bit, 1 channel78// video/x-raw, fourcc:'Y800' -> 8bit, 1 channel79// video/x-raw, fourcc:'Y12 ' -> 12bit, 1 channel80// video/x-raw, fourcc:'Y16 ' -> 16bit, 1 channel81// video/x-raw, fourcc:'GRBG' -> 8bit, 1 channel82//8384#define MODE_GREY CV_FOURCC_MACRO('G','R','E','Y')85#define MODE_Y800 CV_FOURCC_MACRO('Y','8','0','0')86#define MODE_Y12 CV_FOURCC_MACRO('Y','1','2',' ')87#define MODE_Y16 CV_FOURCC_MACRO('Y','1','6',' ')88#define MODE_GRBG CV_FOURCC_MACRO('G','R','B','G')8990#define CLIP(a,b,c) (cv::max(cv::min((a),(c)),(b)))9192/********************* Capturing video from camera via Aravis *********************/9394class CvCaptureCAM_Aravis : public CvCapture95{96public:97CvCaptureCAM_Aravis();98virtual ~CvCaptureCAM_Aravis()99{100close();101}102103virtual bool open(int);104virtual void close();105virtual double getProperty(int) const CV_OVERRIDE;106virtual bool setProperty(int, double) CV_OVERRIDE;107virtual bool grabFrame() CV_OVERRIDE;108virtual IplImage* retrieveFrame(int) CV_OVERRIDE;109virtual int getCaptureDomain() CV_OVERRIDE110{111return cv::CAP_ARAVIS;112}113114protected:115bool create(int);116bool init_buffers();117118void stopCapture();119bool startCapture();120121bool getDeviceNameById(int id, std::string &device);122123void autoExposureControl(IplImage*);124125ArvCamera *camera; // Camera to control.126ArvStream *stream; // Object for video stream reception.127void *framebuffer; //128129unsigned int payload; // Width x height x Pixel width.130131int widthMin; // Camera sensor minimum width.132int widthMax; // Camera sensor maximum width.133int heightMin; // Camera sensor minimum height.134int heightMax; // Camera sensor maximum height.135bool fpsAvailable;136double fpsMin; // Camera minimum fps.137double fpsMax; // Camera maximum fps.138bool gainAvailable;139double gainMin; // Camera minimum gain.140double gainMax; // Camera maximum gain.141bool exposureAvailable;142double exposureMin; // Camera's minimum exposure time.143double exposureMax; // Camera's maximum exposure time.144145bool controlExposure; // Flag if automatic exposure shall be done by this SW146double exposureCompensation;147bool autoGain;148double targetGrey; // Target grey value (mid grey))149150gint64 *pixelFormats;151guint pixelFormatsCnt;152153154int num_buffers; // number of payload transmission buffers155156ArvPixelFormat pixelFormat; // pixel format157158int xoffset; // current frame region x offset159int yoffset; // current frame region y offset160int width; // current frame width of frame161int height; // current frame height of image162163double fps; // current value of fps164double exposure; // current value of exposure time165double gain; // current value of gain166double midGrey; // current value of mid grey (brightness)167168unsigned frameID; // current frame id169unsigned prevFrameID;170171IplImage *frame; // local frame copy172};173174175CvCaptureCAM_Aravis::CvCaptureCAM_Aravis()176{177camera = NULL;178stream = NULL;179framebuffer = NULL;180181payload = 0;182183widthMin = widthMax = heightMin = heightMax = 0;184xoffset = yoffset = width = height = 0;185fpsMin = fpsMax = gainMin = gainMax = exposureMin = exposureMax = 0;186controlExposure = false;187exposureCompensation = 0;188targetGrey = 0;189frameID = prevFrameID = 0;190191num_buffers = 10;192frame = NULL;193}194195void CvCaptureCAM_Aravis::close()196{197if(camera) {198stopCapture();199200g_object_unref(camera);201camera = NULL;202}203}204205bool CvCaptureCAM_Aravis::getDeviceNameById(int id, std::string &device)206{207arv_update_device_list();208209if((id >= 0) && (id < (int)arv_get_n_devices())) {210device = arv_get_device_id(id);211return true;212}213214return false;215}216217bool CvCaptureCAM_Aravis::create( int index )218{219std::string deviceName;220if(!getDeviceNameById(index, deviceName))221return false;222223return NULL != (camera = arv_camera_new(deviceName.c_str()));224}225226bool CvCaptureCAM_Aravis::init_buffers()227{228if(stream) {229g_object_unref(stream);230stream = NULL;231}232if( (stream = arv_camera_create_stream(camera, NULL, NULL)) ) {233if( arv_camera_is_gv_device(camera) ) {234g_object_set(stream,235"socket-buffer", ARV_GV_STREAM_SOCKET_BUFFER_AUTO,236"socket-buffer-size", 0, NULL);237g_object_set(stream,238"packet-resend", ARV_GV_STREAM_PACKET_RESEND_NEVER, NULL);239g_object_set(stream,240"packet-timeout", (unsigned) 40000,241"frame-retention", (unsigned) 200000, NULL);242}243payload = arv_camera_get_payload (camera);244245for (int i = 0; i < num_buffers; i++)246arv_stream_push_buffer(stream, arv_buffer_new(payload, NULL));247248return true;249}250251return false;252}253254bool CvCaptureCAM_Aravis::open( int index )255{256if(create(index)) {257// fetch properties bounds258pixelFormats = arv_camera_get_available_pixel_formats(camera, &pixelFormatsCnt);259260arv_camera_get_width_bounds(camera, &widthMin, &widthMax);261arv_camera_get_height_bounds(camera, &heightMin, &heightMax);262arv_camera_set_region(camera, 0, 0, widthMax, heightMax);263264if( (fpsAvailable = arv_camera_is_frame_rate_available(camera)) )265arv_camera_get_frame_rate_bounds(camera, &fpsMin, &fpsMax);266if( (gainAvailable = arv_camera_is_gain_available(camera)) )267arv_camera_get_gain_bounds (camera, &gainMin, &gainMax);268if( (exposureAvailable = arv_camera_is_exposure_time_available(camera)) )269arv_camera_get_exposure_time_bounds (camera, &exposureMin, &exposureMax);270271// get initial values272pixelFormat = arv_camera_get_pixel_format(camera);273exposure = exposureAvailable ? arv_camera_get_exposure_time(camera) : 0;274gain = gainAvailable ? arv_camera_get_gain(camera) : 0;275fps = arv_camera_get_frame_rate(camera);276277return startCapture();278}279return false;280}281282bool CvCaptureCAM_Aravis::grabFrame()283{284// remove content of previous frame285framebuffer = NULL;286287if(stream) {288ArvBuffer *arv_buffer = NULL;289int max_tries = 10;290int tries = 0;291for(; tries < max_tries; tries ++) {292arv_buffer = arv_stream_timeout_pop_buffer (stream, 200000);293if (arv_buffer != NULL && arv_buffer_get_status (arv_buffer) != ARV_BUFFER_STATUS_SUCCESS) {294arv_stream_push_buffer (stream, arv_buffer);295} else break;296}297if(arv_buffer != NULL && tries < max_tries) {298size_t buffer_size;299framebuffer = (void*)arv_buffer_get_data (arv_buffer, &buffer_size);300301// retieve image size properites302arv_buffer_get_image_region (arv_buffer, &xoffset, &yoffset, &width, &height);303304// retieve image ID set by camera305frameID = arv_buffer_get_frame_id(arv_buffer);306307arv_stream_push_buffer(stream, arv_buffer);308return true;309}310}311return false;312}313314IplImage* CvCaptureCAM_Aravis::retrieveFrame(int)315{316if(framebuffer) {317int depth = 0, channels = 0;318switch(pixelFormat) {319case ARV_PIXEL_FORMAT_MONO_8:320case ARV_PIXEL_FORMAT_BAYER_GR_8:321depth = IPL_DEPTH_8U;322channels = 1;323break;324case ARV_PIXEL_FORMAT_MONO_12:325case ARV_PIXEL_FORMAT_MONO_16:326depth = IPL_DEPTH_16U;327channels = 1;328break;329}330if(depth && channels) {331IplImage src;332cvInitImageHeader( &src, cvSize( width, height ), depth, channels, IPL_ORIGIN_TL, 4 );333334cvSetData( &src, framebuffer, src.widthStep );335if( !frame ||336frame->width != src.width ||337frame->height != src.height ||338frame->depth != src.depth ||339frame->nChannels != src.nChannels) {340341cvReleaseImage( &frame );342frame = cvCreateImage( cvGetSize(&src), src.depth, channels );343}344cvCopy(&src, frame);345346if(controlExposure && ((frameID - prevFrameID) >= 3)) {347// control exposure every third frame348// i.e. skip frame taken with previous exposure setup349autoExposureControl(frame);350}351352return frame;353}354}355return NULL;356}357358void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image)359{360// Software control of exposure parameters utilizing361// automatic change of exposure time & gain362363// Priority is set as follows:364// - to increase brightness, first increase time then gain365// - to decrease brightness, first decrease gain then time366367cv::Mat m = cv::cvarrToMat(image);368369// calc mean value for luminance or green channel370double brightness = cv::mean(m)[image->nChannels > 1 ? 1 : 0];371if(brightness < 1) brightness = 1;372373// mid point - 100 % means no change374static const double dmid = 100;375376// distance from optimal value as a percentage377double d = (targetGrey * dmid) / brightness;378if(d >= dmid) d = ( d + (dmid * 2) ) / 3;379380prevFrameID = frameID;381midGrey = brightness;382383double maxe = 1e6 / fps;384double ne = CLIP( ( exposure * d ) / ( dmid * pow(sqrt(2), -2 * exposureCompensation) ), exposureMin, maxe);385386// if change of value requires intervention387if(std::fabs(d-dmid) > 5) {388double ev, ng = 0;389390if(gainAvailable && autoGain) {391ev = log( d / dmid ) / log(2);392ng = CLIP( gain + ev + exposureCompensation, gainMin, gainMax);393394if( ng < gain ) {395// priority 1 - reduce gain396arv_camera_set_gain(camera, (gain = ng));397return;398}399}400401if(exposureAvailable) {402// priority 2 - control of exposure time403if(std::fabs(exposure - ne) > 2) {404// we have not yet reach the max-e level405arv_camera_set_exposure_time(camera, (exposure = ne) );406return;407}408}409410if(gainAvailable && autoGain) {411if(exposureAvailable) {412// exposure at maximum - increase gain if possible413if(ng > gain && ng < gainMax && ne >= maxe) {414arv_camera_set_gain(camera, (gain = ng));415return;416}417} else {418// priority 3 - increase gain419arv_camera_set_gain(camera, (gain = ng));420return;421}422}423}424425// if gain can be reduced - do it426if(gainAvailable && autoGain && exposureAvailable) {427if(gain > gainMin && exposure < maxe) {428exposure = CLIP( ne * 1.05, exposureMin, maxe);429arv_camera_set_exposure_time(camera, exposure );430}431}432}433434double CvCaptureCAM_Aravis::getProperty( int property_id ) const435{436switch(property_id) {437case CV_CAP_PROP_POS_MSEC:438return (double)frameID/fps;439440case CV_CAP_PROP_FRAME_WIDTH:441return width;442443case CV_CAP_PROP_FRAME_HEIGHT:444return height;445446case CV_CAP_PROP_AUTO_EXPOSURE:447return (controlExposure ? 1 : 0);448449case CV_CAP_PROP_BRIGHTNESS:450return exposureCompensation;451452case CV_CAP_PROP_EXPOSURE:453if(exposureAvailable) {454/* exposure time in seconds, like 1/100 s */455return arv_camera_get_exposure_time(camera) / 1e6;456}457break;458459case CV_CAP_PROP_FPS:460if(fpsAvailable) {461return arv_camera_get_frame_rate(camera);462}463break;464465case CV_CAP_PROP_GAIN:466if(gainAvailable) {467return arv_camera_get_gain(camera);468}469break;470471case CV_CAP_PROP_FOURCC:472{473ArvPixelFormat currFormat = arv_camera_get_pixel_format(camera);474switch( currFormat ) {475case ARV_PIXEL_FORMAT_MONO_8:476return MODE_Y800;477case ARV_PIXEL_FORMAT_MONO_12:478return MODE_Y12;479case ARV_PIXEL_FORMAT_MONO_16:480return MODE_Y16;481case ARV_PIXEL_FORMAT_BAYER_GR_8:482return MODE_GRBG;483}484}485break;486487case CV_CAP_PROP_BUFFERSIZE:488if(stream) {489int in, out;490arv_stream_get_n_buffers(stream, &in, &out);491// return number of available buffers in Aravis output queue492return out;493}494break;495}496return -1.0;497}498499bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )500{501switch(property_id) {502case CV_CAP_PROP_AUTO_EXPOSURE:503if(exposureAvailable || gainAvailable) {504if( (controlExposure = (bool)(int)value) ) {505exposure = exposureAvailable ? arv_camera_get_exposure_time(camera) : 0;506gain = gainAvailable ? arv_camera_get_gain(camera) : 0;507}508}509break;510case CV_CAP_PROP_BRIGHTNESS:511exposureCompensation = CLIP(value, -3., 3.);512break;513514case CV_CAP_PROP_EXPOSURE:515if(exposureAvailable) {516/* exposure time in seconds, like 1/100 s */517value *= 1e6; // -> from s to us518519arv_camera_set_exposure_time(camera, exposure = CLIP(value, exposureMin, exposureMax));520break;521} else return false;522523case CV_CAP_PROP_FPS:524if(fpsAvailable) {525arv_camera_set_frame_rate(camera, fps = CLIP(value, fpsMin, fpsMax));526break;527} else return false;528529case CV_CAP_PROP_GAIN:530if(gainAvailable) {531if ( (autoGain = (-1 == value) ) )532break;533534arv_camera_set_gain(camera, gain = CLIP(value, gainMin, gainMax));535break;536} else return false;537538case CV_CAP_PROP_FOURCC:539{540ArvPixelFormat newFormat = pixelFormat;541switch((int)value) {542case MODE_GREY:543case MODE_Y800:544newFormat = ARV_PIXEL_FORMAT_MONO_8;545targetGrey = 128;546break;547case MODE_Y12:548newFormat = ARV_PIXEL_FORMAT_MONO_12;549targetGrey = 2048;550break;551case MODE_Y16:552newFormat = ARV_PIXEL_FORMAT_MONO_16;553targetGrey = 32768;554break;555case MODE_GRBG:556newFormat = ARV_PIXEL_FORMAT_BAYER_GR_8;557targetGrey = 128;558break;559}560if(newFormat != pixelFormat) {561stopCapture();562arv_camera_set_pixel_format(camera, pixelFormat = newFormat);563startCapture();564}565}566break;567568case CV_CAP_PROP_BUFFERSIZE:569{570int x = (int)value;571if((x > 0) && (x != num_buffers)) {572stopCapture();573num_buffers = x;574startCapture();575}576}577break;578579580default:581return false;582}583584return true;585}586587void CvCaptureCAM_Aravis::stopCapture()588{589arv_camera_stop_acquisition(camera);590591if(stream) {592g_object_unref(stream);593stream = NULL;594}595}596597bool CvCaptureCAM_Aravis::startCapture()598{599if(init_buffers() ) {600arv_camera_set_acquisition_mode(camera, ARV_ACQUISITION_MODE_CONTINUOUS);601arv_camera_start_acquisition(camera);602603return true;604}605return false;606}607608CvCapture* cvCreateCameraCapture_Aravis( int index )609{610CvCaptureCAM_Aravis* capture = new CvCaptureCAM_Aravis;611612if(capture->open(index)) {613return capture;614}615616delete capture;617return NULL;618}619#endif620621622