static void output_once_( const boost::posix_time::ptime& t ) { std::pair< boost::posix_time::ptime, cv::Mat > output; if( polar ) { static unsigned int polar_size = ( row_size + offset_from_center ) * 2 + 1; static unsigned int type = output_options.get_header().type; static cv::Mat polar_image( polar_size, polar_size * ids.size(), type ); ::memset( const_cast< unsigned char* >( polar_image.datastart ), 0, polar_image.dataend - polar_image.datastart ); for( unsigned int i = 0; i < ids.size(); ++i ) { unsigned int offset = row_size * i; unsigned int polar_offset = polar_size * i; for( unsigned int row = 0; row < block_size; ++row ) { double x_step = sin_cos[row].second; double y_step = sin_cos[row].first * sign; double x = row_size + offset_from_center + polar_offset; double y = row_size + offset_from_center; x += sin_cos[row].second * offset_from_center; y += sin_cos[row].first * sign * offset_from_center; for( unsigned int column = 0; column < row_size; ++column, x += x_step, y += y_step ) { ::memcpy( const_cast< unsigned char* >( polar_image.datastart ) + ( int( y ) * ( polar_image.cols ) + int( x ) ) * pixel_size , image.datastart + ( int( row ) * image.cols + offset + column ) * pixel_size , pixel_size ); } } } output.second = polar_image; } else { output.second = image; } output.first = t; serialization->write( std::cout, output ); }
static void write_( ChunkPair p ) { if( p.second.size().width == 0 || std::cout.bad() || !std::cout.good() || is_shutdown ) { return; } static comma::csv::binary_output_stream< Header > ostream( std::cout, csv ); static Header header( options.get_header() ); header.header.timestamp = p.first.timestamp; header.counters.ticks = p.first.ticks; static ChunkData first_chunk_data; if( first_chunk_data.timestamp.is_not_a_date_time() ) { first_chunk_data = p.first; header.counters.adjusted_timestamp = p.first.timestamp; } else { static const double factor = 8.0 / 1000; // 8ns per tick header.counters.adjusted_timestamp = first_chunk_data.timestamp + boost::posix_time::microseconds( factor * first_chunk_data.ticks ); // todo: factor in network delay? } header.counters.line_count += p.first.line_trigger_ignored + 1; header.counters.line = header.counters.line_count % encoder_ticks; ostream.write( header ); std::cout.write( ( const char* )( p.second.datastart ), p.second.dataend - p.second.datastart ); std::cout.flush(); }
int main( int ac, char** av ) { int result = 0; try { comma::command_line_options options( ac, av ); if( options.exists( "--help,-h" ) ) { usage(); } verbose = options.exists( "--verbose,-v" ); csv = comma::csv::options( options, "values" ); csv.full_xpath = true; row_number_offset = options.value( "--row-number-offset,--offset", 0 ); polar = options.exists( "--polar" ); as_radians = !options.exists( "--degrees" ); clockwise = options.exists( "--clockwise" ); offset_from_center = options.value( "--offset-from-center", 0 ); // quick and dirty z_up = options.value< std::string >( "--z", "up" ) == "up"; sign = ( z_up && !clockwise ) || ( !z_up && clockwise ) ? 1 : -1; if( options.exists( "--fps" ) ) { dial_size = options.value( "--dial-size,--dial", 0 ); } std::string s = options.value< std::string >( "--size" ); std::vector< std::string > v = comma::split( s, ',' ); if( v.size() != 2 && v.size() != 3 ) { std::cerr << "image-accumulate: expected --size=<value>; got \"" << s << "\"" << std::endl; return 1; } block_size = boost::lexical_cast< unsigned int >( v[0] ); row_size = boost::lexical_cast< unsigned int >( v[1] ); scale = comma::csv::ascii< std::pair< double, double > >().get( options.value< std::string >( "--scale", "0,255" ) ); scaled< unsigned char > scaled( scale ); fps = options.optional< double >( "--fps" ); sin_cos = precomputed_sin_cos_(); channel::options default_channel_options( options ); std::vector< channel::options > channel_options; if( csv.has_field( "id" ) ) { const std::vector< std::string >& v = options.values< std::string >( "--id" ); if( v.empty() ) { std::cerr << "image-accumulate: 'id' field given, please specify at least one --id" << std::endl; return 1; } for( unsigned int i = 0; i < v.size(); ++i ) { channel_options.push_back( comma::name_value::parser( ';', '=' ).get< channel::options >( v[i], default_channel_options ) ); ids[ boost::lexical_cast< unsigned int >( comma::split( v[i], ';' )[0] ) ] = i; } } else { ids[0] = 0; channel_options.push_back( default_channel_options ); } in.values.resize( row_size ); has_block = csv.has_field( "block" ); has_row = csv.has_field( "row" ); has_angle = csv.has_field( "angle" ); if( has_row && has_angle ) { std::cerr << "image-accumulate: in input fields, expected either 'row' or 'angle'; got both" << std::endl; return 1; } comma::csv::input_stream< input > istream( std::cin, csv, in ); // todo: watch performance! std::string default_output_options = "no-header;rows=" + boost::lexical_cast< std::string >( polar ? row_size * 2 + 1 : block_size ) + ";cols=" + boost::lexical_cast< std::string >( polar ? ( row_size * 2 + 1 ) * ids.size() : row_size * ids.size() ) + ";type=3ub"; std::string output_options_string = options.value( "--output", default_output_options ); output_options = comma::name_value::parser( ';', '=' ).get< snark::cv_mat::serialization::options >( output_options_string ); if( options.exists( "--output-options" ) ) { std::cout << comma::name_value::parser( ';', '=' ).put< snark::cv_mat::serialization::options >( output_options ) << std::endl; return 0; } serialization.reset( new snark::cv_mat::serialization( output_options ) ); image = cv::Mat::zeros( block_size, row_size * ids.size(), output_options.get_header().type ); pixel_size = output_options.get_header().type == CV_8UC3 ? 3 : 1; // quick and dirty boost::ptr_vector< channel > channels; for( unsigned int i = 0; i < ids.size(); ++i ) { channels.push_back( new channel( i, channel_options[i] ) ); } if( fps ) { output_thread.reset( new boost::thread( &output_ ) ); } while( !is_shutdown && std::cin.good() && !std::cin.eof() ) { const input* p = istream.read(); if( p ) { Ids::const_iterator it = ids.find( p->id ); if( it == ids.end() ) { continue; } if( !channels[ it->second ].draw( p ) ) { break; } } else { for( Ids::const_iterator it = ids.begin(); it != ids.end(); ++it ) { channels[ it->second ].draw( p ); } break; } } } catch( std::exception& ex ) { std::cerr << "image-accumulate: " << ex.what() << std::endl; result = 1; } catch( ... ) { std::cerr << "image-accumulate: unknown exception" << std::endl; result = 1; } done = true; if( fps ) { output_thread->join(); } return result; }
int main( int argc, char** argv ) { ::setenv( "PYLON_ROOT", STRINGIZED( BASLER_PYLON_DIR ), 0 ); ::setenv( "GENICAM_ROOT_V2_1", STRINGIZED( BASLER_PYLON_GENICAM_DIR ), 0 ); try { unsigned int id; std::string address; std::string setAttributes; unsigned int discard; boost::program_options::options_description description( "options" ); unsigned int packet_size; unsigned int exposure; unsigned int gain; unsigned int offset_x; unsigned int offset_y; unsigned int width; unsigned int height; std::string frame_trigger; std::string line_trigger; unsigned int line_rate; double timeout_seconds; description.add_options() ( "help,h", "display help message" ) ( "address", boost::program_options::value< std::string >( &address ), "camera ip address; default: connect to the first available camera" ) ( "discard", "discard frames, if cannot keep up; same as --buffer=1" ) ( "buffer", boost::program_options::value< unsigned int >( &discard )->default_value( 0 ), "maximum buffer size before discarding frames, default: unlimited" ) ( "list-cameras", "output camera list and exit" ) ( "fields,f", boost::program_options::value< std::string >( &options.fields )->default_value( "t,rows,cols,type" ), "header fields, possible values: t,rows,cols,type,size,counters" ) ( "image-type", boost::program_options::value< std::string >( &options.type )->default_value( "3ub" ), "image type, e.g. '3ub'; also see --long-help for details" ) ( "offset-x", boost::program_options::value< unsigned int >( &offset_x )->default_value( 0 ), "offset in pixels in the line" ) ( "offset-y", boost::program_options::value< unsigned int >( &offset_y )->default_value( 0 ), "offset in lines in the frame" ) ( "width", boost::program_options::value< unsigned int >( &width )->default_value( std::numeric_limits< unsigned int >::max() ), "line width in pixels; default: max" ) ( "height", boost::program_options::value< unsigned int >( &height )->default_value( std::numeric_limits< unsigned int >::max() ), "number of lines in frame (in chunk mode always 1); default: max" ) ( "frame-trigger", boost::program_options::value< std::string >( &frame_trigger ), "'line1', 'line2', 'line3', 'encoder'" ) //; if absent while --line-trigger present, same as --line-trigger" ) ( "line-trigger", boost::program_options::value< std::string >( &line_trigger ), "'line1', 'line2', 'line3', 'encoder'" ) ( "line-rate", boost::program_options::value< unsigned int >( &line_rate ), "line aquisition rate" ) ( "encoder-ticks", boost::program_options::value< unsigned int >( &encoder_ticks ), "number of encoder ticks until the counter resets (reused for line number in frame in chunk mode)" ) ( "header-only", "output header only" ) ( "no-header", "output image data only" ) ( "packet-size", boost::program_options::value< unsigned int >( &packet_size ), "mtu size on camera side, should be not greater than your lan and network interface set to" ) ( "exposure", boost::program_options::value< unsigned int >( &exposure )->default_value( 100 ), "exposure" ) ( "gain", boost::program_options::value< unsigned int >( &gain )->default_value( 100 ), "gain" ) ( "timeout", boost::program_options::value< double >( &timeout_seconds )->default_value( 3.0 ), " frame acquisition timeout" ) ( "test-colour", "output colour test image" ) ( "verbose,v", "be more verbose" ); boost::program_options::variables_map vm; boost::program_options::store( boost::program_options::parse_command_line( argc, argv, description), vm ); boost::program_options::parsed_options parsed = boost::program_options::command_line_parser(argc, argv).options( description ).allow_unregistered().run(); boost::program_options::notify( vm ); if ( vm.count( "help" ) || vm.count( "long-help" ) ) { std::cerr << "acquire images from a basler camera (for now gige only)" << std::endl; std::cerr << "output to stdout as serialized cv::Mat" << std::endl; std::cerr << std::endl; std::cerr << "usage: basler-cat [<options>] [<filters>]" << std::endl; std::cerr << std::endl; std::cerr << description << std::endl; if( vm.count( "long-help" ) ) { std::cerr << std::endl; std::cerr << snark::cv_mat::filters::usage() << std::endl; std::cerr << std::endl; std::cerr << snark::cv_mat::serialization::options::type_usage() << std::endl; } std::cerr << std::endl; std::cerr << "note: there is a glitch or a subtle feature in basler line camera:" << std::endl; std::cerr << " - power-cycle camera" << std::endl; std::cerr << " - view colour images: it works" << std::endl; std::cerr << " - view grey-scale images: it works" << std::endl; std::cerr << " - view colour images: it still displays grey-scale" << std::endl; std::cerr << " even in their native viewer you need to set colour image" << std::endl; std::cerr << " repeatedly and with pure luck it works, but we have not" << std::endl; std::cerr << " managed to do it in software; the remedy: power-cycle the camera" << std::endl; std::cerr << std::endl; return 1; } verbose = vm.count( "verbose" ); if( verbose ) { std::cerr << "basler-cat: PYLON_ROOT=" << ::getenv( "PYLON_ROOT" ) << std::endl; std::cerr << "basler-cat: GENICAM_ROOT_V2_1=" << ::getenv( "GENICAM_ROOT_V2_1" ) << std::endl; std::cerr << "basler-cat: initializing camera..." << std::endl; } Pylon::PylonAutoInitTerm auto_init_term; Pylon::CTlFactory& factory = Pylon::CTlFactory::GetInstance(); Pylon::ITransportLayer* transport_layer( Pylon::CTlFactory::GetInstance().CreateTl( Pylon::CBaslerGigECamera::DeviceClass() ) ); if( !transport_layer ) { std::cerr << "basler-cat: failed to create transport layer" << std::endl; std::cerr << " most likely PYLON_ROOT and GENICAM_ROOT_V2_1 environment variables not set" << std::endl; std::cerr << " point them to your pylon installation, e.g:" << std::endl; std::cerr << " export PYLON_ROOT=/opt/pylon" << std::endl; std::cerr << " export GENICAM_ROOT_V2_1=/opt/pylon/genicam" << std::endl; return 1; } if( vm.count( "list-cameras" ) ) { Pylon::DeviceInfoList_t devices; factory.EnumerateDevices( devices ); for( unsigned int i = 0; i < devices.size(); ++i ) { std::cerr << devices[i].GetFullName() << std::endl; } return 0; } timeout = timeout_seconds * 1000.0; std::string filters = comma::join( boost::program_options::collect_unrecognized( parsed.options, boost::program_options::include_positional ), ';' ); options.header_only = vm.count( "header-only" ); options.no_header = vm.count( "no-header" ); csv = comma::csv::options( argc, argv ); bool chunk_mode = csv.has_field( "counters" ) // quick and dirty || csv.has_field( "adjusted-t" ) || csv.has_field( "line" ) || csv.has_field( "line-count" ) || csv.has_field( "ticks" ) || csv.has_field( "counters/adjusted-t" ) || csv.has_field( "counters/line" ) || csv.has_field( "counters/line-count" ) || csv.has_field( "counters/ticks" ); if( chunk_mode ) { if( vm.count( "encoder-ticks" ) == 0 ) { std::cerr << "basler-cat: chunk mode, please specify --encoder-ticks" << std::endl; return 1; } if( !filters.empty() ) { std::cerr << "basler-cat: chunk mode, cannot handle filters; use: basler-cat | cv-cat <filters> instead" << std::endl; return 1; } if( height != 1 && height != std::numeric_limits< unsigned int >::max() ) { std::cerr << "basler-cat: only --height=1 implemented in chunk mode" << std::endl; return 1; } height = 1; std::vector< std::string > v = comma::split( csv.fields, ',' ); std::string format; for( unsigned int i = 0; i < v.size(); ++i ) { if( v[i] == "t" ) { v[i] = "header/" + v[i]; format += "t"; } else if( v[i] == "rows" || v[i] == "cols" || v[i] == "size" || v[i] == "type" ) { v[i] = "header/" + v[i]; format += "ui"; } else if( v[i] == "adjusted-t" ) { v[i] = "counters/" + v[i]; format += "t"; } else if( v[i] == "line-count" || v[i] == "ticks" ) { v[i] = "counters/" + v[i]; format += "ul"; } else if( v[i] == "line" ) { v[i] = "counters/" + v[i]; format += "ui"; } else { std::cerr << "basler-cat: expected field, got '" << v[i] << "'" << std::endl; return 1; } } csv.fields = comma::join( v, ',' ); csv.full_xpath = true; csv.format( format ); } if( !vm.count( "buffer" ) && vm.count( "discard" ) ) { discard = 1; } Pylon::CBaslerGigECamera camera; if( vm.count( "address" ) ) { Pylon::CBaslerGigEDeviceInfo info; info.SetIpAddress( address.c_str() ); camera.Attach( factory.CreateDevice( info ) ); } else { Pylon::DeviceInfoList_t devices; factory.EnumerateDevices( devices ); if( devices.empty() ) { std::cerr << "basler-cat: no camera found" << std::endl; return 1; } std::cerr << "basler-cat: will connect to the first of " << devices.size() << " found device(s):" << std::endl; for( unsigned int i = 0; i < devices.size(); ++i ) { std::cerr << " " << devices[i].GetFullName() << std::endl; } camera.Attach( transport_layer->CreateDevice( devices[0] ) ); } if( verbose ) { std::cerr << "basler-cat: initialized camera" << std::endl; } if( verbose ) { std::cerr << "basler-cat: opening camera " << camera.GetDevice()->GetDeviceInfo().GetFullName() << "..." << std::endl; } camera.Open(); if( verbose ) { std::cerr << "basler-cat: opened camera " << camera.GetDevice()->GetDeviceInfo().GetFullName() << std::endl; } Pylon::CBaslerGigECamera::StreamGrabber_t grabber( camera.GetStreamGrabber( 0 ) ); grabber.Open(); unsigned int channels; switch( options.get_header().type ) // quick and dirty { case CV_8UC1: channels = set_pixel_format_( camera, Basler_GigECamera::PixelFormat_Mono8 ); break; case CV_8UC3: channels = set_pixel_format_( camera, Basler_GigECamera::PixelFormat_RGB8Packed ); break; default: std::cerr << "basler-cat: type \"" << options.type << "\" not implemented or not supported by camera" << std::endl; return 1; } unsigned int max_width = camera.Width.GetMax(); if( offset_x >= max_width ) { std::cerr << "basler-cat: expected --offset-x less than " << max_width << ", got " << offset_x << std::endl; return 1; } camera.OffsetX.SetValue( offset_x ); width = ( ( unsigned long long )( offset_x ) + width ) < max_width ? width : max_width - offset_x; camera.Width.SetValue( width ); unsigned int max_height = camera.Height.GetMax(); //if( height < 512 ) { std::cerr << "basler-cat: expected height greater than 512, got " << height << std::endl; return 1; } // todo: is the colour line 2098 * 3 or ( 2098 / 3 ) * 3 ? //offset_y *= channels; //height *= channels; if( offset_y >= max_height ) { std::cerr << "basler-cat: expected --offset-y less than " << max_height << ", got " << offset_y << std::endl; return 1; } camera.OffsetY.SetValue( offset_y ); height = ( ( unsigned long long )( offset_y ) + height ) < max_height ? height : ( max_height - offset_y ); camera.Height.SetValue( height ); if( verbose ) { std::cerr << "basler-cat: set width,height to " << width << "," << height << std::endl; } if( vm.count( "packet-size" ) ) { camera.GevSCPSPacketSize.SetValue( packet_size ); } // todo: giving up... the commented code throws, but failure to stop acquisition, if active // seems to lead to the following scenario: // - power-cycle camera // - view colour images: it works // - view grey-scale images: it works // - view colour images: it still displays grey-scale //if( verbose ) { std::cerr << "basler-cat: getting aquisition status... (frigging voodoo...)" << std::endl; } //GenApi::IEnumEntry* acquisition_status = camera.AcquisitionStatusSelector.GetEntry( Basler_GigECamera::AcquisitionStatusSelector_AcquisitionActive ); //if( acquisition_status && GenApi::IsAvailable( acquisition_status ) && camera.AcquisitionStatus() ) //{ // if( verbose ) { std::cerr << "basler-cat: stopping aquisition..." << std::endl; } // camera.AcquisitionStop.Execute(); // if( verbose ) { std::cerr << "basler-cat: aquisition stopped" << std::endl; } //} // todo: a hack for now GenApi::IEnumEntry* acquisitionStart = camera.TriggerSelector.GetEntry( Basler_GigECamera::TriggerSelector_AcquisitionStart ); if( acquisitionStart && GenApi::IsAvailable( acquisitionStart ) ) { camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_AcquisitionStart ); camera.TriggerMode.SetValue( frame_trigger.empty() ? Basler_GigECamera::TriggerMode_Off : Basler_GigECamera::TriggerMode_On ); } GenApi::IEnumEntry* frameStart = camera.TriggerSelector.GetEntry( Basler_GigECamera::TriggerSelector_FrameStart ); if( frameStart && GenApi::IsAvailable( frameStart ) ) { //if( frame_trigger.empty() ) { frame_trigger = line_trigger; } if( frame_trigger.empty() ) { camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_FrameStart ); camera.TriggerMode.SetValue( Basler_GigECamera::TriggerMode_Off ); } else { camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_FrameStart ); camera.TriggerMode.SetValue( Basler_GigECamera::TriggerMode_On ); Basler_GigECamera::TriggerSourceEnums t; if( frame_trigger == "line1" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_Line1 ); } if( frame_trigger == "line2" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_Line2 ); } if( frame_trigger == "line3" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_Line3 ); } else if( frame_trigger == "encoder" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_ShaftEncoderModuleOut ); } else { std::cerr << "basler-cat: frame trigger '" << frame_trigger << "' not implemented or invalid" << std::endl; return 1; } camera.TriggerActivation.SetValue( Basler_GigECamera::TriggerActivation_RisingEdge ); camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_LineStart ); camera.TriggerMode.SetValue( Basler_GigECamera::TriggerMode_On ); camera.TriggerActivation.SetValue( Basler_GigECamera::TriggerActivation_RisingEdge ); if( frame_trigger == "encoder" ) { // todo: make configurable camera.ShaftEncoderModuleLineSelector.SetValue( Basler_GigECamera::ShaftEncoderModuleLineSelector_PhaseA ); camera.ShaftEncoderModuleLineSource.SetValue( Basler_GigECamera::ShaftEncoderModuleLineSource_Line1 ); camera.ShaftEncoderModuleLineSelector.SetValue( Basler_GigECamera::ShaftEncoderModuleLineSelector_PhaseB ); camera.ShaftEncoderModuleLineSource.SetValue( Basler_GigECamera::ShaftEncoderModuleLineSource_Line2 ); camera.ShaftEncoderModuleCounterMode.SetValue( Basler_GigECamera::ShaftEncoderModuleCounterMode_FollowDirection ); camera.ShaftEncoderModuleMode.SetValue( Basler_GigECamera::ShaftEncoderModuleMode_ForwardOnly ); camera.ShaftEncoderModuleCounterMax.SetValue( encoder_ticks - 1 ); /// @todo compensate for mechanical jitter, if needed /// see Runner_Users_manual.pdf, 8.3, Case 2 camera.ShaftEncoderModuleReverseCounterMax.SetValue( 0 ); camera.ShaftEncoderModuleCounterReset.Execute(); camera.ShaftEncoderModuleReverseCounterReset.Execute(); } } } GenApi::IEnumEntry* lineStart = camera.TriggerSelector.GetEntry( Basler_GigECamera::TriggerSelector_LineStart ); if( lineStart && GenApi::IsAvailable( lineStart ) ) { if( line_trigger.empty() ) { camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_LineStart ); camera.TriggerMode.SetValue( Basler_GigECamera::TriggerMode_Off ); } else { camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_LineStart ); camera.TriggerMode.SetValue( Basler_GigECamera::TriggerMode_On ); Basler_GigECamera::TriggerSourceEnums t; if( line_trigger == "line1" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_Line1 ); } else if( line_trigger == "line2" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_Line2 ); } else if( line_trigger == "line3" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_Line3 ); } else if( line_trigger == "encoder" ) { camera.TriggerSource.SetValue( Basler_GigECamera::TriggerSource_ShaftEncoderModuleOut ); } else { std::cerr << "basler-cat: line trigger '" << line_trigger << "' not implemented or invalid" << std::endl; return 1; } camera.TriggerActivation.SetValue( Basler_GigECamera::TriggerActivation_RisingEdge ); camera.TriggerSelector.SetValue( Basler_GigECamera::TriggerSelector_LineStart ); camera.TriggerMode.SetValue( Basler_GigECamera::TriggerMode_On ); camera.TriggerActivation.SetValue( Basler_GigECamera::TriggerActivation_RisingEdge ); } } if( chunk_mode ) { std::cerr << "basler-cat: setting chunk mode..." << std::endl; if( !GenApi::IsWritable( camera.ChunkModeActive ) ) { std::cerr << "basler-cat: camera does not support chunk features" << std::endl; camera.Close(); return 1; } camera.ChunkModeActive.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_Framecounter ); camera.ChunkEnable.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_Timestamp ); camera.ChunkEnable.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_LineTriggerIgnoredCounter ); camera.ChunkEnable.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_FrameTriggerIgnoredCounter ); camera.ChunkEnable.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_LineTriggerEndToEndCounter ); camera.ChunkEnable.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_FrameTriggerCounter ); camera.ChunkEnable.SetValue( true ); camera.ChunkSelector.SetValue( Basler_GigECameraParams::ChunkSelector_FramesPerTriggerCounter ); camera.ChunkEnable.SetValue( true ); parser = camera.CreateChunkParser(); if( !parser ) { std::cerr << "basler-cat: failed to create chunk parser" << std::endl; camera.Close(); return 1; } std::cerr << "basler-cat: set chunk mode" << std::endl; } camera.ExposureMode.SetValue( Basler_GigECamera::ExposureMode_Timed ); if( vm.count( "exposure" ) ) { camera.ExposureTimeRaw.SetValue( exposure ); } // todo? auto exposure (see ExposureAutoEnums) if( vm.count( "gain" ) ) { camera.GainSelector.SetValue( Basler_GigECamera::GainSelector_All ); camera.GainRaw.SetValue( gain ); if( channels == 3 ) // todo: make configurable; also is not setting all not enough? { camera.GainSelector.SetValue( Basler_GigECamera::GainSelector_Red ); camera.GainRaw.SetValue( gain ); camera.GainSelector.SetValue( Basler_GigECamera::GainSelector_Green ); camera.GainRaw.SetValue( gain ); camera.GainSelector.SetValue( Basler_GigECamera::GainSelector_Blue ); camera.GainRaw.SetValue( gain ); } } if( vm.count( "line-rate" ) ) { camera.AcquisitionLineRateAbs.SetValue( line_rate ); } if( vm.count( "test-colour" ) ) { camera.TestImageSelector.SetValue( Basler_GigECamera::TestImageSelector_Testimage6 ); } else { camera.TestImageSelector.SetValue( Basler_GigECamera::TestImageSelector_Off ); } unsigned int payload_size = camera.PayloadSize.GetValue(); if( verbose ) { std::cerr << "basler-cat: camera mtu size: " << camera.GevSCPSPacketSize.GetValue() << std::endl; std::cerr << "basler-cat: exposure: " << camera.ExposureTimeRaw.GetValue() << std::endl; std::cerr << "basler-cat: payload size: " << payload_size << std::endl; } std::vector< std::vector< char > > buffers( 2 ); // todo? make number of buffers configurable for( std::size_t i = 0; i < buffers.size(); ++i ) { buffers[i].resize( payload_size ); } grabber.MaxBufferSize.SetValue( buffers[0].size() ); grabber.SocketBufferSize.SetValue( 127 ); if( verbose ) { std::cerr << "basler-cat: socket buffer size: " << grabber.SocketBufferSize.GetValue() << std::endl; std::cerr << "basler-cat: max buffer size: " << grabber.MaxBufferSize.GetValue() << std::endl; } grabber.MaxNumBuffer.SetValue( buffers.size() ); // todo: use --buffer value for number of buffered images grabber.PrepareGrab(); // image size now must not be changed until FinishGrab() is called. std::vector< Pylon::StreamBufferHandle > buffer_handles( buffers.size() ); for( std::size_t i = 0; i < buffers.size(); ++i ) { buffer_handles[i] = grabber.RegisterBuffer( &buffers[i][0], buffers[i].size() ); grabber.QueueBuffer( buffer_handles[i], NULL ); } if( chunk_mode ) { snark::tbb::bursty_reader< ChunkPair > read( boost::bind( &capture_< ChunkPair >, boost::ref( camera ), boost::ref( grabber ) ), discard ); tbb::filter_t< ChunkPair, void > write( tbb::filter::serial_in_order, boost::bind( &write_, _1 ) ); snark::tbb::bursty_pipeline< ChunkPair > pipeline; camera.AcquisitionMode.SetValue( Basler_GigECamera::AcquisitionMode_Continuous ); camera.AcquisitionStart.Execute(); // continuous acquisition mode if( verbose ) { std::cerr << "basler-cat: running in chunk mode..." << std::endl; } pipeline.run( read, write ); if( verbose ) { std::cerr << "basler-cat: shutting down..." << std::endl; } camera.AcquisitionStop(); camera.DestroyChunkParser( parser ); } else { snark::cv_mat::serialization serialization( options ); snark::tbb::bursty_reader< Pair > reader( boost::bind( &capture_< Pair >, boost::ref( camera ), boost::ref( grabber ) ), discard ); snark::imaging::applications::pipeline pipeline( serialization, filters, reader ); camera.AcquisitionMode.SetValue( Basler_GigECamera::AcquisitionMode_Continuous ); camera.AcquisitionStart.Execute(); // continuous acquisition mode if( verbose ) { std::cerr << "basler-cat: running..." << std::endl; } pipeline.run(); if( verbose ) { std::cerr << "basler-cat: shutting down..." << std::endl; } camera.AcquisitionStop(); } if( verbose ) { std::cerr << "basler-cat: acquisition stopped" << std::endl; } is_shutdown = true; while( !done ) { boost::thread::sleep( boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds( 100 ) ); } grabber.FinishGrab(); Pylon::GrabResult result; while( grabber.RetrieveResult( result ) ); // get all buffers back for( std::size_t i = 0; i < buffers.size(); ++i ) { grabber.DeregisterBuffer( buffer_handles[i] ); } grabber.Close(); camera.Close(); if( verbose ) { std::cerr << "basler-cat: done" << std::endl; } return 0; } catch( std::exception& ex ) { std::cerr << "basler-cat: " << ex.what() << std::endl; } catch( ... ) { std::cerr << "basler-cat: unknown exception" << std::endl; } return 1; }
static P capture_( Pylon::CBaslerGigECamera& camera, Pylon::CBaslerGigECamera::StreamGrabber_t& grabber ) //static Pair capture( Ark::Robotics::Camera::Gige& camera ) { /// @todo if color spatial correction implemented, mind the following: /// /// Runner_Users_manual.pdf, 8.2.2.3: /// /// If you are using a color camera, you have spatial correction enabled /// and you have the frame start trigger mode set to off, you must discard /// the first n x 2 lines from the first frame transmitted by the camera /// after an acquisition start command is issued (where n is the absolute /// value of the current spatial correction parameter setting). /// /// If you have spatial correction enabled and you have the frame start /// trigger mode set to on, you must discard the first n x 2 lines from /// each frame transmitted by the camera. static const unsigned int retries = 10; // quick and dirty: arbitrary for( unsigned int i = 0; !done && i < retries; ++i ) { Pylon::GrabResult result; //camera.AcquisitionStart.Execute(); // acquire single image (since acquisition mode set so) if( !grabber.GetWaitObject().Wait( timeout ) ) // quick and dirty: arbitrary timeout { std::cerr << "basler-cat: timeout" << std::endl; grabber.CancelGrab(); while( grabber.RetrieveResult( result ) ); // get all buffers back if( is_shutdown ) { done = true; } return P(); } boost::posix_time::ptime t = boost::get_system_time(); grabber.RetrieveResult( result ); if( !result.Succeeded() ) { std::cerr << "basler-cat: acquisition failed: " << result.GetErrorDescription() << " (" << result.GetErrorCode() << ")" << std::endl; std::cerr << " status: " << ( result.Status() == Pylon::Idle ? "idle" : result.Status() == Pylon::Queued ? "queued" : result.Status() == Pylon::Grabbed ? "grabbed" : result.Status() == Pylon::Canceled ? "canceled" : result.Status() == Pylon::Failed ? "failed" : "unknown" ) << std::endl; std::cerr << " run basler-cat --verbose and check your --packet-size settings" << std::endl; continue; } P pair; static const snark::cv_mat::serialization::header header = options.get_header(); switch( header.type ) { case CV_8UC1: pair.second = cv::Mat( result.GetSizeY(), result.GetSizeX(), header.type ); ::memcpy( pair.second.data, reinterpret_cast< const char* >( result.Buffer() ), pair.second.dataend - pair.second.datastart ); break; case CV_8UC3: // quick and dirty for now: rgb are not contiguous in basler camera frame pair.second = cv::Mat( result.GetSizeY(), result.GetSizeX(), header.type ); ::memcpy( pair.second.data, reinterpret_cast< const char* >( result.Buffer() ), pair.second.dataend - pair.second.datastart ); cv::cvtColor( pair.second, pair.second, CV_RGB2BGR ); break; default: // quick and dirty for now std::cerr << "basler-cat: cv::mat type " << options.type << " not supported" << std::endl; } set_( pair.first, t, result, camera ); grabber.QueueBuffer( result.Handle(), NULL ); // requeue buffer if( is_shutdown ) { done = true; } return pair; } if( is_shutdown ) { done = true; } return P(); }