Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/videoio/src/cap_aravis.cpp
16342 views
1
////////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// Intel License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Third party copyrights are property of their respective owners.
15
//
16
// Redistribution and use in source and binary forms, with or without modification,
17
// are permitted provided that the following conditions are met:
18
//
19
// * Redistribution's of source code must retain the above copyright notice,
20
// this list of conditions and the following disclaimer.
21
//
22
// * Redistribution's in binary form must reproduce the above copyright notice,
23
// this list of conditions and the following disclaimer in the documentation
24
// and/or other materials provided with the distribution.
25
//
26
// * The name of Intel Corporation may not be used to endorse or promote products
27
// derived from this software without specific prior written permission.
28
//
29
// This software is provided by the copyright holders and contributors "as is" and
30
// any express or implied warranties, including, but not limited to, the implied
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
33
// indirect, incidental, special, exemplary, or consequential damages
34
// (including, but not limited to, procurement of substitute goods or services;
35
// loss of use, data, or profits; or business interruption) however caused
36
// and on any theory of liability, whether in contract, strict liability,
37
// or tort (including negligence or otherwise) arising in any way out of
38
// the use of this software, even if advised of the possibility of such damage.
39
//
40
//
41
42
//
43
// The code has been contributed by Arkadiusz Raj on 2016 Oct
44
//
45
46
#include "precomp.hpp"
47
48
#ifdef HAVE_ARAVIS_API
49
50
#include <arv.h>
51
52
//
53
// This file provides wrapper for using Aravis SDK library to access GigE Vision cameras.
54
// Aravis library (version 0.4 or 0.6) shall be installed else this code will not be included in build.
55
//
56
// To include this module invoke cmake with -DWITH_ARAVIS=ON
57
//
58
// Please obvserve, that jumbo frames are required when high fps & 16bit data is selected.
59
// (camera, switches/routers and the computer this software is running on)
60
//
61
// Basic usage: VideoCapture cap(CAP_ARAVIS + <camera id>);
62
//
63
// Supported properties:
64
// read/write
65
// CAP_PROP_AUTO_EXPOSURE(0|1)
66
// CAP_PROP_EXPOSURE(t), t in seconds
67
// CAP_PROP_BRIGHTNESS (ev), exposure compensation in EV for auto exposure algorithm
68
// CAP_PROP_GAIN(g), g >=0 or -1 for automatic control if CAP_PROP_AUTO_EXPOSURE is true
69
// CAP_PROP_FPS(f)
70
// CAP_PROP_FOURCC(type)
71
// CAP_PROP_BUFFERSIZE(n)
72
// read only:
73
// CAP_PROP_POS_MSEC
74
// CAP_PROP_FRAME_WIDTH
75
// CAP_PROP_FRAME_HEIGHT
76
//
77
// Supported types of data:
78
// video/x-raw, fourcc:'GREY' -> 8bit, 1 channel
79
// video/x-raw, fourcc:'Y800' -> 8bit, 1 channel
80
// video/x-raw, fourcc:'Y12 ' -> 12bit, 1 channel
81
// video/x-raw, fourcc:'Y16 ' -> 16bit, 1 channel
82
// video/x-raw, fourcc:'GRBG' -> 8bit, 1 channel
83
//
84
85
#define MODE_GREY CV_FOURCC_MACRO('G','R','E','Y')
86
#define MODE_Y800 CV_FOURCC_MACRO('Y','8','0','0')
87
#define MODE_Y12 CV_FOURCC_MACRO('Y','1','2',' ')
88
#define MODE_Y16 CV_FOURCC_MACRO('Y','1','6',' ')
89
#define MODE_GRBG CV_FOURCC_MACRO('G','R','B','G')
90
91
#define CLIP(a,b,c) (cv::max(cv::min((a),(c)),(b)))
92
93
/********************* Capturing video from camera via Aravis *********************/
94
95
class CvCaptureCAM_Aravis : public CvCapture
96
{
97
public:
98
CvCaptureCAM_Aravis();
99
virtual ~CvCaptureCAM_Aravis()
100
{
101
close();
102
}
103
104
virtual bool open(int);
105
virtual void close();
106
virtual double getProperty(int) const CV_OVERRIDE;
107
virtual bool setProperty(int, double) CV_OVERRIDE;
108
virtual bool grabFrame() CV_OVERRIDE;
109
virtual IplImage* retrieveFrame(int) CV_OVERRIDE;
110
virtual int getCaptureDomain() CV_OVERRIDE
111
{
112
return cv::CAP_ARAVIS;
113
}
114
115
protected:
116
bool create(int);
117
bool init_buffers();
118
119
void stopCapture();
120
bool startCapture();
121
122
bool getDeviceNameById(int id, std::string &device);
123
124
void autoExposureControl(IplImage*);
125
126
ArvCamera *camera; // Camera to control.
127
ArvStream *stream; // Object for video stream reception.
128
void *framebuffer; //
129
130
unsigned int payload; // Width x height x Pixel width.
131
132
int widthMin; // Camera sensor minimum width.
133
int widthMax; // Camera sensor maximum width.
134
int heightMin; // Camera sensor minimum height.
135
int heightMax; // Camera sensor maximum height.
136
bool fpsAvailable;
137
double fpsMin; // Camera minimum fps.
138
double fpsMax; // Camera maximum fps.
139
bool gainAvailable;
140
double gainMin; // Camera minimum gain.
141
double gainMax; // Camera maximum gain.
142
bool exposureAvailable;
143
double exposureMin; // Camera's minimum exposure time.
144
double exposureMax; // Camera's maximum exposure time.
145
146
bool controlExposure; // Flag if automatic exposure shall be done by this SW
147
double exposureCompensation;
148
bool autoGain;
149
double targetGrey; // Target grey value (mid grey))
150
151
gint64 *pixelFormats;
152
guint pixelFormatsCnt;
153
154
155
int num_buffers; // number of payload transmission buffers
156
157
ArvPixelFormat pixelFormat; // pixel format
158
159
int xoffset; // current frame region x offset
160
int yoffset; // current frame region y offset
161
int width; // current frame width of frame
162
int height; // current frame height of image
163
164
double fps; // current value of fps
165
double exposure; // current value of exposure time
166
double gain; // current value of gain
167
double midGrey; // current value of mid grey (brightness)
168
169
unsigned frameID; // current frame id
170
unsigned prevFrameID;
171
172
IplImage *frame; // local frame copy
173
};
174
175
176
CvCaptureCAM_Aravis::CvCaptureCAM_Aravis()
177
{
178
camera = NULL;
179
stream = NULL;
180
framebuffer = NULL;
181
182
payload = 0;
183
184
widthMin = widthMax = heightMin = heightMax = 0;
185
xoffset = yoffset = width = height = 0;
186
fpsMin = fpsMax = gainMin = gainMax = exposureMin = exposureMax = 0;
187
controlExposure = false;
188
exposureCompensation = 0;
189
targetGrey = 0;
190
frameID = prevFrameID = 0;
191
192
num_buffers = 10;
193
frame = NULL;
194
}
195
196
void CvCaptureCAM_Aravis::close()
197
{
198
if(camera) {
199
stopCapture();
200
201
g_object_unref(camera);
202
camera = NULL;
203
}
204
}
205
206
bool CvCaptureCAM_Aravis::getDeviceNameById(int id, std::string &device)
207
{
208
arv_update_device_list();
209
210
if((id >= 0) && (id < (int)arv_get_n_devices())) {
211
device = arv_get_device_id(id);
212
return true;
213
}
214
215
return false;
216
}
217
218
bool CvCaptureCAM_Aravis::create( int index )
219
{
220
std::string deviceName;
221
if(!getDeviceNameById(index, deviceName))
222
return false;
223
224
return NULL != (camera = arv_camera_new(deviceName.c_str()));
225
}
226
227
bool CvCaptureCAM_Aravis::init_buffers()
228
{
229
if(stream) {
230
g_object_unref(stream);
231
stream = NULL;
232
}
233
if( (stream = arv_camera_create_stream(camera, NULL, NULL)) ) {
234
if( arv_camera_is_gv_device(camera) ) {
235
g_object_set(stream,
236
"socket-buffer", ARV_GV_STREAM_SOCKET_BUFFER_AUTO,
237
"socket-buffer-size", 0, NULL);
238
g_object_set(stream,
239
"packet-resend", ARV_GV_STREAM_PACKET_RESEND_NEVER, NULL);
240
g_object_set(stream,
241
"packet-timeout", (unsigned) 40000,
242
"frame-retention", (unsigned) 200000, NULL);
243
}
244
payload = arv_camera_get_payload (camera);
245
246
for (int i = 0; i < num_buffers; i++)
247
arv_stream_push_buffer(stream, arv_buffer_new(payload, NULL));
248
249
return true;
250
}
251
252
return false;
253
}
254
255
bool CvCaptureCAM_Aravis::open( int index )
256
{
257
if(create(index)) {
258
// fetch properties bounds
259
pixelFormats = arv_camera_get_available_pixel_formats(camera, &pixelFormatsCnt);
260
261
arv_camera_get_width_bounds(camera, &widthMin, &widthMax);
262
arv_camera_get_height_bounds(camera, &heightMin, &heightMax);
263
arv_camera_set_region(camera, 0, 0, widthMax, heightMax);
264
265
if( (fpsAvailable = arv_camera_is_frame_rate_available(camera)) )
266
arv_camera_get_frame_rate_bounds(camera, &fpsMin, &fpsMax);
267
if( (gainAvailable = arv_camera_is_gain_available(camera)) )
268
arv_camera_get_gain_bounds (camera, &gainMin, &gainMax);
269
if( (exposureAvailable = arv_camera_is_exposure_time_available(camera)) )
270
arv_camera_get_exposure_time_bounds (camera, &exposureMin, &exposureMax);
271
272
// get initial values
273
pixelFormat = arv_camera_get_pixel_format(camera);
274
exposure = exposureAvailable ? arv_camera_get_exposure_time(camera) : 0;
275
gain = gainAvailable ? arv_camera_get_gain(camera) : 0;
276
fps = arv_camera_get_frame_rate(camera);
277
278
return startCapture();
279
}
280
return false;
281
}
282
283
bool CvCaptureCAM_Aravis::grabFrame()
284
{
285
// remove content of previous frame
286
framebuffer = NULL;
287
288
if(stream) {
289
ArvBuffer *arv_buffer = NULL;
290
int max_tries = 10;
291
int tries = 0;
292
for(; tries < max_tries; tries ++) {
293
arv_buffer = arv_stream_timeout_pop_buffer (stream, 200000);
294
if (arv_buffer != NULL && arv_buffer_get_status (arv_buffer) != ARV_BUFFER_STATUS_SUCCESS) {
295
arv_stream_push_buffer (stream, arv_buffer);
296
} else break;
297
}
298
if(arv_buffer != NULL && tries < max_tries) {
299
size_t buffer_size;
300
framebuffer = (void*)arv_buffer_get_data (arv_buffer, &buffer_size);
301
302
// retieve image size properites
303
arv_buffer_get_image_region (arv_buffer, &xoffset, &yoffset, &width, &height);
304
305
// retieve image ID set by camera
306
frameID = arv_buffer_get_frame_id(arv_buffer);
307
308
arv_stream_push_buffer(stream, arv_buffer);
309
return true;
310
}
311
}
312
return false;
313
}
314
315
IplImage* CvCaptureCAM_Aravis::retrieveFrame(int)
316
{
317
if(framebuffer) {
318
int depth = 0, channels = 0;
319
switch(pixelFormat) {
320
case ARV_PIXEL_FORMAT_MONO_8:
321
case ARV_PIXEL_FORMAT_BAYER_GR_8:
322
depth = IPL_DEPTH_8U;
323
channels = 1;
324
break;
325
case ARV_PIXEL_FORMAT_MONO_12:
326
case ARV_PIXEL_FORMAT_MONO_16:
327
depth = IPL_DEPTH_16U;
328
channels = 1;
329
break;
330
}
331
if(depth && channels) {
332
IplImage src;
333
cvInitImageHeader( &src, cvSize( width, height ), depth, channels, IPL_ORIGIN_TL, 4 );
334
335
cvSetData( &src, framebuffer, src.widthStep );
336
if( !frame ||
337
frame->width != src.width ||
338
frame->height != src.height ||
339
frame->depth != src.depth ||
340
frame->nChannels != src.nChannels) {
341
342
cvReleaseImage( &frame );
343
frame = cvCreateImage( cvGetSize(&src), src.depth, channels );
344
}
345
cvCopy(&src, frame);
346
347
if(controlExposure && ((frameID - prevFrameID) >= 3)) {
348
// control exposure every third frame
349
// i.e. skip frame taken with previous exposure setup
350
autoExposureControl(frame);
351
}
352
353
return frame;
354
}
355
}
356
return NULL;
357
}
358
359
void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image)
360
{
361
// Software control of exposure parameters utilizing
362
// automatic change of exposure time & gain
363
364
// Priority is set as follows:
365
// - to increase brightness, first increase time then gain
366
// - to decrease brightness, first decrease gain then time
367
368
cv::Mat m = cv::cvarrToMat(image);
369
370
// calc mean value for luminance or green channel
371
double brightness = cv::mean(m)[image->nChannels > 1 ? 1 : 0];
372
if(brightness < 1) brightness = 1;
373
374
// mid point - 100 % means no change
375
static const double dmid = 100;
376
377
// distance from optimal value as a percentage
378
double d = (targetGrey * dmid) / brightness;
379
if(d >= dmid) d = ( d + (dmid * 2) ) / 3;
380
381
prevFrameID = frameID;
382
midGrey = brightness;
383
384
double maxe = 1e6 / fps;
385
double ne = CLIP( ( exposure * d ) / ( dmid * pow(sqrt(2), -2 * exposureCompensation) ), exposureMin, maxe);
386
387
// if change of value requires intervention
388
if(std::fabs(d-dmid) > 5) {
389
double ev, ng = 0;
390
391
if(gainAvailable && autoGain) {
392
ev = log( d / dmid ) / log(2);
393
ng = CLIP( gain + ev + exposureCompensation, gainMin, gainMax);
394
395
if( ng < gain ) {
396
// priority 1 - reduce gain
397
arv_camera_set_gain(camera, (gain = ng));
398
return;
399
}
400
}
401
402
if(exposureAvailable) {
403
// priority 2 - control of exposure time
404
if(std::fabs(exposure - ne) > 2) {
405
// we have not yet reach the max-e level
406
arv_camera_set_exposure_time(camera, (exposure = ne) );
407
return;
408
}
409
}
410
411
if(gainAvailable && autoGain) {
412
if(exposureAvailable) {
413
// exposure at maximum - increase gain if possible
414
if(ng > gain && ng < gainMax && ne >= maxe) {
415
arv_camera_set_gain(camera, (gain = ng));
416
return;
417
}
418
} else {
419
// priority 3 - increase gain
420
arv_camera_set_gain(camera, (gain = ng));
421
return;
422
}
423
}
424
}
425
426
// if gain can be reduced - do it
427
if(gainAvailable && autoGain && exposureAvailable) {
428
if(gain > gainMin && exposure < maxe) {
429
exposure = CLIP( ne * 1.05, exposureMin, maxe);
430
arv_camera_set_exposure_time(camera, exposure );
431
}
432
}
433
}
434
435
double CvCaptureCAM_Aravis::getProperty( int property_id ) const
436
{
437
switch(property_id) {
438
case CV_CAP_PROP_POS_MSEC:
439
return (double)frameID/fps;
440
441
case CV_CAP_PROP_FRAME_WIDTH:
442
return width;
443
444
case CV_CAP_PROP_FRAME_HEIGHT:
445
return height;
446
447
case CV_CAP_PROP_AUTO_EXPOSURE:
448
return (controlExposure ? 1 : 0);
449
450
case CV_CAP_PROP_BRIGHTNESS:
451
return exposureCompensation;
452
453
case CV_CAP_PROP_EXPOSURE:
454
if(exposureAvailable) {
455
/* exposure time in seconds, like 1/100 s */
456
return arv_camera_get_exposure_time(camera) / 1e6;
457
}
458
break;
459
460
case CV_CAP_PROP_FPS:
461
if(fpsAvailable) {
462
return arv_camera_get_frame_rate(camera);
463
}
464
break;
465
466
case CV_CAP_PROP_GAIN:
467
if(gainAvailable) {
468
return arv_camera_get_gain(camera);
469
}
470
break;
471
472
case CV_CAP_PROP_FOURCC:
473
{
474
ArvPixelFormat currFormat = arv_camera_get_pixel_format(camera);
475
switch( currFormat ) {
476
case ARV_PIXEL_FORMAT_MONO_8:
477
return MODE_Y800;
478
case ARV_PIXEL_FORMAT_MONO_12:
479
return MODE_Y12;
480
case ARV_PIXEL_FORMAT_MONO_16:
481
return MODE_Y16;
482
case ARV_PIXEL_FORMAT_BAYER_GR_8:
483
return MODE_GRBG;
484
}
485
}
486
break;
487
488
case CV_CAP_PROP_BUFFERSIZE:
489
if(stream) {
490
int in, out;
491
arv_stream_get_n_buffers(stream, &in, &out);
492
// return number of available buffers in Aravis output queue
493
return out;
494
}
495
break;
496
}
497
return -1.0;
498
}
499
500
bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )
501
{
502
switch(property_id) {
503
case CV_CAP_PROP_AUTO_EXPOSURE:
504
if(exposureAvailable || gainAvailable) {
505
if( (controlExposure = (bool)(int)value) ) {
506
exposure = exposureAvailable ? arv_camera_get_exposure_time(camera) : 0;
507
gain = gainAvailable ? arv_camera_get_gain(camera) : 0;
508
}
509
}
510
break;
511
case CV_CAP_PROP_BRIGHTNESS:
512
exposureCompensation = CLIP(value, -3., 3.);
513
break;
514
515
case CV_CAP_PROP_EXPOSURE:
516
if(exposureAvailable) {
517
/* exposure time in seconds, like 1/100 s */
518
value *= 1e6; // -> from s to us
519
520
arv_camera_set_exposure_time(camera, exposure = CLIP(value, exposureMin, exposureMax));
521
break;
522
} else return false;
523
524
case CV_CAP_PROP_FPS:
525
if(fpsAvailable) {
526
arv_camera_set_frame_rate(camera, fps = CLIP(value, fpsMin, fpsMax));
527
break;
528
} else return false;
529
530
case CV_CAP_PROP_GAIN:
531
if(gainAvailable) {
532
if ( (autoGain = (-1 == value) ) )
533
break;
534
535
arv_camera_set_gain(camera, gain = CLIP(value, gainMin, gainMax));
536
break;
537
} else return false;
538
539
case CV_CAP_PROP_FOURCC:
540
{
541
ArvPixelFormat newFormat = pixelFormat;
542
switch((int)value) {
543
case MODE_GREY:
544
case MODE_Y800:
545
newFormat = ARV_PIXEL_FORMAT_MONO_8;
546
targetGrey = 128;
547
break;
548
case MODE_Y12:
549
newFormat = ARV_PIXEL_FORMAT_MONO_12;
550
targetGrey = 2048;
551
break;
552
case MODE_Y16:
553
newFormat = ARV_PIXEL_FORMAT_MONO_16;
554
targetGrey = 32768;
555
break;
556
case MODE_GRBG:
557
newFormat = ARV_PIXEL_FORMAT_BAYER_GR_8;
558
targetGrey = 128;
559
break;
560
}
561
if(newFormat != pixelFormat) {
562
stopCapture();
563
arv_camera_set_pixel_format(camera, pixelFormat = newFormat);
564
startCapture();
565
}
566
}
567
break;
568
569
case CV_CAP_PROP_BUFFERSIZE:
570
{
571
int x = (int)value;
572
if((x > 0) && (x != num_buffers)) {
573
stopCapture();
574
num_buffers = x;
575
startCapture();
576
}
577
}
578
break;
579
580
581
default:
582
return false;
583
}
584
585
return true;
586
}
587
588
void CvCaptureCAM_Aravis::stopCapture()
589
{
590
arv_camera_stop_acquisition(camera);
591
592
if(stream) {
593
g_object_unref(stream);
594
stream = NULL;
595
}
596
}
597
598
bool CvCaptureCAM_Aravis::startCapture()
599
{
600
if(init_buffers() ) {
601
arv_camera_set_acquisition_mode(camera, ARV_ACQUISITION_MODE_CONTINUOUS);
602
arv_camera_start_acquisition(camera);
603
604
return true;
605
}
606
return false;
607
}
608
609
CvCapture* cvCreateCameraCapture_Aravis( int index )
610
{
611
CvCaptureCAM_Aravis* capture = new CvCaptureCAM_Aravis;
612
613
if(capture->open(index)) {
614
return capture;
615
}
616
617
delete capture;
618
return NULL;
619
}
620
#endif
621
622