/*============================================================================= Copyright (C) 2012 Allied Vision Technologies. All Rights Reserved. Redistribution of this file, in original or modified form, without prior written consent of Allied Vision Technologies is prohibited. ------------------------------------------------------------------------------- File: LookUpTable.cpp Description: The LookUpTable example will demonstrate how to use the look up table feature of the camera using VimbaCPP. ------------------------------------------------------------------------------- THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include #include #include #include #include "LookUpTable.h" #include "Csv.h" #include "Exception.h" #include "VimbaFeatures.h" #include "VimbaCPP/Include/VimbaCPP.h" namespace AVT { namespace VmbAPI { namespace Examples { namespace { // toolset to handle network byte order, for production, use htons ntohs for int16 static const union { VmbUint8_t bytes[4]; VmbUint32_t v; } host_byte_order = {{0,1,2,3}}; enum { byte_oder_little_endian = 0x03020100ul, byte_oder_big_endian = 0x01000302ul, }; inline UcharVector ConvertToNetworkInt16( const UcharVector &d) { if (host_byte_order.v == byte_oder_little_endian) { UcharVector tmp( d ); for( size_t i = 0 ;i < tmp.size(); i +=2) { VmbUint16_t *p = reinterpret_cast( &tmp[i] ); *p = ((*p>>8) & 0xff) | ((*p<<8) & 0xff00); } return tmp; } return d; } inline UcharVector ConvertFromNetworkInt16( const UcharVector &d) { return ConvertToNetworkInt16( d ); } } bool LookUpTableCollection::HasLookUpTable(CameraPtr pCamera ) { return VimbaFeature::HasFeature( pCamera, "LUTSelector"); } LookUpTableCollection::LookUpTableCollection( CameraPtr pCamera ) : m_pCamera( pCamera ) { //Check parameters if( NULL == m_pCamera ) { throw Exception( __FUNCTION__,"LookUpTableCollection failed camera pointer NULL.", VmbErrorBadParameter ); } VmbInt64_t nCount = GetCount( ); if( 0 == nCount ) { throw Exception( __FUNCTION__,"LookUpTableCollection no entries.", VmbErrorNotFound ); } // for each lookup table create a control for( int i = 0; i < nCount; i++ ) { m_tables.push_back( LookUpTableControl( m_pCamera, i )); } } //Get look up table count VmbInt64_t LookUpTableCollection::GetCount( ) { // number of LUTs is the number of enum values fo the "LUTSelector" Feature VimbaFeatureEnum LutSelector( m_pCamera, "LUTSelector" ); return LutSelector.ValueCount(); } //Get look up table control LookUpTableControl LookUpTableCollection::GetControl( VmbInt64_t nIndex ) { VimbaFeatureEnum LutSelector( m_pCamera, "LUTSelector" ); //< get enum feature for supported LUTs StringVector Values = LutSelector.GetValues(); //< get list of supported LUTs if( static_cast(nIndex) >= Values.size() ) //< test index for out of range { throw Exception( __FUNCTION__,"selected index out of range",VmbErrorBadParameter ); } std::string SelectedValue = Values[ static_cast( nIndex ) ]; if( !LutSelector.IsAvailable( SelectedValue ) ) { throw Exception(__FUNCTION__,"selected LUT is not available", VmbErrorBadParameter ); } LutSelector.SetStringValue( SelectedValue ); //< activate the LUT at nIndex return m_tables[ static_cast( nIndex ) ]; //< get stored LUT control } //Get look up table active index VmbInt64_t LookUpTableCollection::GetActiveIndex( ) { VimbaFeatureEnum LutSelector( m_pCamera, "LUTSelector" ); //< get enum feture for supported luts const StringVector SupportedLuts = LutSelector.GetValues(); //< get list of supported LUTs std::string CurrentLut = LutSelector.GetStringValue( ); //< get the currently selected LUT StringVector::const_iterator find_pos = std::find( SupportedLuts.begin(), SupportedLuts.end(), CurrentLut );//< find current vallue in list if( SupportedLuts.end() == find_pos ) { throw Exception( __FUNCTION__,"could not find current selected lut index",VmbErrorNotFound ); } return std::distance( SupportedLuts.begin(), find_pos ); } LookUpTableControl::LookUpTableControl( CameraPtr pCamera, VmbInt64_t nIndex ) : m_pCamera( pCamera ) , m_nIndex( nIndex ) { //Check parameters if( NULL == m_pCamera ) { throw Exception( __FUNCTION__,"LookUpTableControl failed.", VmbErrorBadParameter ); } } //Enable look up table void LookUpTableControl::Enable( VmbBool_t bEnable ) { VimbaFeatureBool LutEnable( m_pCamera, "LUTEnable" ); //< create bool feature for lut enable LutEnable( bEnable ); //< set state to feature } //Is look up table enabled VmbBool_t LookUpTableControl::IsEnabled( ) const { VimbaFeatureBool LutEnable( m_pCamera,"LUTEnable" ); //< create bool feature for Lut enable return LutEnable(); //< return current value } //Get look up table index VmbInt64_t LookUpTableControl::GetIndex( ) const { VimbaFeatureInt LutIndex( m_pCamera, "LUTIndex" ); //< get feature for LUT index return LutIndex(); // return current index } //Get value count VmbInt64_t LookUpTableControl::GetValueCount( ) const { VimbaFeatureInt LutSize ( m_pCamera,"LUTSize"); //< get feature for LUT size in bytes VimbaFeatureInt LutBitDepthOut ( m_pCamera, "LUTBitDepthOut"); //< get feature for output bits per lut values VmbInt64_t nLUTBytePerValue = LutBitDepthOut() > 8 ? 2 : 1; //< calculate bytes used its either 2 bytes if larger than 8bits or 1 byte return LutSize() / nLUTBytePerValue; //< lut are elements without padding consecutive in memory } //Get look up table value VmbInt64_t LookUpTableControl::GetValue( ) const { VimbaFeatureInt LutValue( m_pCamera, "LUTValue" ); //< get feature for lUT element value this depends on LUTIndex return LutValue(); //< return current value } //Set look up table value void LookUpTableControl::SetValue( VmbInt64_t nValue ) { VimbaFeatureInt LutValue( m_pCamera,"LUTValue" ); //< get feature for LUT element value this depends on LUTIndex LutValue( nValue ); //< set new value } //Get bit depth in VmbInt64_t LookUpTableControl::GetBitDepthIn( ) const { VimbaFeatureInt LutBitDepthIn( m_pCamera, "LUTBitDepthIn" ); //< get feature for input bit depth of LUT return LutBitDepthIn(); //< return bit depth } //Get bit depth out VmbInt64_t LookUpTableControl::GetBitDepthOut( ) const { VimbaFeatureInt LutBitDepthOut( m_pCamera,"LUTBitDepthOut" ); //< get feature for output bit depth of LUT return LutBitDepthOut(); // return bit dept } //Download look up table void LookUpTableControl::Download() { // if any kind of LUT is implemented we should find the LUTSelector feature if( VmbBoolTrue != VimbaFeature::HasFeature( m_pCamera,"LUTSelector" ) ) { throw Exception( __FUNCTION__,"no LUT feature implemented",VmbErrorNotFound ); } // try reading LUT with FileAccess if( VmbBoolTrue == VimbaFeature::HasFeature( m_pCamera, "FileSelector" ) ) { VimbaFeatureEnum LutSelector ( m_pCamera, "LUTSelector"); //< selector feature for lookup table VimbaFeatureEnum FileSelector( m_pCamera, "FileSelector"); //< file selector VimbaFeatureEnum FileOpenMode( m_pCamera, "FileOpenMode"); //< selector for file open mode FileSelector.SetStringValue ( std::string("LUT") + LutSelector.GetStringValue()); //< get the lookup table name and set it to file selector if( VmbBoolTrue != FileOpenMode.IsAvailable( "Read" ) ) //< test if LUT feature is readable, Firewire does not support LUT read { throw Exception( __FUNCTION__,"camera does not support LUT download to host computer", VmbErrorNotSupported ); } FileOpenMode.SetStringValue( "Read" ); //< set the open mode to read VimbaFeatureInt LutSize( m_pCamera,"LUTSizeBytes" ); //< integer feature for bytes of lookup table m_data.resize( static_cast( LutSize() ) ); //< get the bytes VimbaFeatureEnum FileOperationSelector ( m_pCamera, "FileOperationSelector"); //< file operation selector to selector the file command VimbaFeatureCommand FileOperationExecute ( m_pCamera, "FileOperationExecute"); //< file operation command executer VimbaFeatureRaw FileAccessBuffer ( m_pCamera, "FileAccessBuffer"); //< raw data feature to access file buffer VimbaFeatureInt FileAccessOffset ( m_pCamera, "FileAccessOffset"); //< integer feature to get the data offset into the buffer VimbaFeatureInt FileAccessLength ( m_pCamera, "FileAccessLength"); //< integer feature for length of file access VimbaFeatureEnum FileOperationStatus ( m_pCamera, "FileOperationStatus"); //< enumeration value for state of file operation VimbaFeatureInt FileOperationResult ( m_pCamera, "FileOperationResult"); //< integer for file operation result VimbaFeatureEnum FileStatus ( m_pCamera, "FileStatus"); //< file state feature VimbaFeatureInt FileSize ( m_pCamera, "FileSize"); //< file size feature FileOperationSelector.SetStringValue( "Open" ); //< set open command for file access FileOperationExecute.Run(); //< execute command //File size VmbInt64_t nFileSize = FileSize( ); //< get lut file size FileOperationSelector.SetStringValue( "Read" ); //< set file operation to read VmbInt64_t nFileAccessOffset = 0; //< set start offset VmbInt64_t nFileAccessLength = min( LutSize(), FileAccessLength.Max() ); //< determine if we can read the lut in one go, or are limited by max access length UcharVector data( static_cast( nFileAccessLength ) ); //< prepare the temporary data buffer do { FileAccessLength( nFileAccessLength ); //< set the amount of data we want to read FileOperationExecute.Run(); //< commit the read request if( FileOperationStatus.GetStringValue( ) != "Success" ) //< test if read failed { throw Exception( __FUNCTION__,"reading LUT failed", VmbErrorOther ); } FileAccessBuffer.GetBuffer( data ); //< if read succeeded we can read the raw buffer data = ConvertFromNetworkInt16( data ); copy( data.begin(), data.end(), m_data.begin() + ( size_t )nFileAccessOffset ); //< copy it from temp storage to internal data buffer nFileAccessOffset = FileAccessOffset( ); //< get the new file offset nFileAccessLength = min( nFileSize - nFileAccessOffset, FileAccessLength.Max() ); //< get the next file length } while( nFileSize != nFileAccessOffset ); //Select close as file operation FileOperationSelector.SetStringValue( "Close" ); //< set file operation to close FileOperationExecute.Run(); //< commit the close operation if( FileOperationStatus.GetStringValue() != "Success" ) //< test if close succeeded { throw Exception( __FUNCTION__,"lut file operation failed", VmbErrorOther ); } } // try reading LUT address for GigE (indicator for direct memory access) else if( VmbBoolTrue == VimbaFeature::HasFeature( m_pCamera, "LUTAddress" ) ) { VimbaFeatureInt LutSize( m_pCamera,"LUTSizeBytes" ); //< get feature for lut byte size m_data.resize( static_cast( LutSize() ) ); //< prepare storage for LUT data VimbaFeatureInt LutAddress (m_pCamera, "LUTAddress"); //< try to get the LUT address feature VmbInt64_t nLUTAddress = LutAddress(); //< store address VmbUint32_t nCompletedReads = 0; VmbErrorType err = m_pCamera->ReadMemory( nLUTAddress, m_data, nCompletedReads ); if( VmbErrorSuccess != err ) { throw Exception( __FUNCTION__,": could not read memory from camera",err ); } m_data = ConvertFromNetworkInt16( m_data ); } // if non of the buffer read features are available try to read it value by value else { VimbaFeatureInt LUTIndex( m_pCamera, "LUTIndex" ); //< get the LUTIndex feature to control the index of the current value VimbaFeatureInt LUTValue( m_pCamera, "LUTValue" ); //< get the LUTValue feature to access the current value VimbaFeatureInt LutSize ( m_pCamera, "LUTSizeBytes" ); //< get the LUTSizeBytes feature to get LUT size info m_data.resize( static_cast( LutSize() ) ); //< resize storage for LUT data VmbInt64_t nLUTBitDepthOut = GetBitDepthOut( ); //< get bits per LUT value needed //Evaluate number of LUT entries VmbInt64_t nLUTBytePerValue = ( nLUTBitDepthOut > 8 ) ? 2 : 1; //< determine what size the LUT values occupy VmbInt64_t nLUTEntries = LutSize() / nLUTBytePerValue; //< entries are stored consecutive without padding //Get LUT values by iteration over indexes int iter = 0; for( VmbInt64_t i = 0; i < nLUTEntries ; i++ ) { LUTIndex( i ); //< set index VmbInt64_t nValue = LUTValue( ); //< get current value switch( nLUTBytePerValue ) { case 1: m_data[iter++] = static_cast( nValue ); break; case 2: { VmbUint16_t * p = (VmbUint16_t*)( &m_data[iter] ); *p = static_cast( nValue ); iter +=2; } break; } } } } //Upload look up table void LookUpTableControl::Upload() { //Look up table raw data empty if( m_data.empty() ) { throw Exception( __FUNCTION__,": lut data vector is empty", VmbErrorOther ); } if( VmbBoolTrue == VimbaFeature::HasFeature( m_pCamera, "FileSelector" ) ) { //Evaluate size of LUT VimbaFeatureInt LUTSize ( m_pCamera, "LUTSizeBytes"); //file access control VimbaFeatureEnum FileOperationSelector ( m_pCamera, "FileOperationSelector"); VimbaFeatureCommand FileOperationExecute ( m_pCamera, "FileOperationExecute" ); VimbaFeatureEnum FileOpenMode ( m_pCamera, "FileOpenMode" ); VimbaFeatureRaw FileAccessBuffer ( m_pCamera, "FileAccessBuffer" ); VimbaFeatureInt FileAccessOffset ( m_pCamera, "FileAccessOffset" ); VimbaFeatureInt FileAccessLength ( m_pCamera, "FileAccessLength" ); VimbaFeatureEnum FileOperationStatus ( m_pCamera, "FileOperationStatus" ); VimbaFeatureInt FileOperationResult ( m_pCamera, "FileOperationResult" ); VimbaFeatureEnum FileStatus ( m_pCamera, "FileStatus" ); VimbaFeatureInt FileSize ( m_pCamera, "FileSize" ); VimbaFeatureEnum FileSelector ( m_pCamera, "FileSelector" ); VimbaFeatureEnum LUTSelector ( m_pCamera, "LUTSelector" ); FileSelector.SetStringValue( std::string( "LUT" )+LUTSelector.GetStringValue() ); if( FileOpenMode.IsAvailable( "Write" ) ) { FileOpenMode.SetStringValue( "Write" ); FileOperationSelector.SetStringValue( "Open" ); FileOperationExecute.Run(); VmbInt64_t nFileSize = FileSize( ); if( m_data.size() != nFileSize ) { throw Exception( __FUNCTION__,"LUT to upload does not seam to have the correct size for this camera",VmbErrorBadParameter ); } //File access length VmbInt64_t nMaxFileAccessLength = FileAccessLength.Max( ); FileOperationSelector.SetStringValue( "Write" ); VmbInt64_t nFileAccessOffset = 0; VmbInt64_t nFileAccessLength = min( nFileSize, nMaxFileAccessLength ); UcharVector data( (size_t)nFileAccessLength ); do { //Set FileAccessLength FileAccessLength( nFileAccessLength ); //Fill buffer copy( &m_data[(size_t)nFileAccessOffset ], &m_data[(size_t)( nFileAccessLength+nFileAccessOffset-1 ) ], data.begin() ); data = ConvertToNetworkInt16( data ); FileAccessBuffer( data ); //Execute file operation FileOperationExecute.Run( ); //Get file operation status if( FileOperationStatus.GetStringValue() != "Success" ) { throw Exception( __FUNCTION__,"writing data failed",VmbErrorOther ); } nFileAccessOffset =FileAccessOffset(); nFileAccessLength = min( nFileSize - nFileAccessOffset, nMaxFileAccessLength ); } while( nFileSize != nFileAccessOffset ); FileOperationSelector.SetStringValue( "Close" ); FileOperationExecute.Run(); //Get file operation status if( FileOperationStatus.GetStringValue() != "Success" ) { throw Exception( __FUNCTION__,"could not close file", VmbErrorOther ); } } } else if( VmbBoolTrue == VimbaFeature::HasFeature( m_pCamera,"LUTIndex" ) ) { //Get LUT address for GigE (indicator for direct memory access) VimbaFeatureInt LUTAddress( m_pCamera, "LUTAddress" ); //< get feature for lut address VmbUint32_t nCompletedWrites = 0; UcharVector network_data( ConvertToNetworkInt16( m_data ) ); //< expect our camera to be big endian device, so if we are intel little endian we have to swap m_pCamera->WriteMemory( LUTAddress() , network_data, nCompletedWrites ); //< write data direct to camera } //Camera doesn't support direct memory access for LUT else { //Used LUT index and value as indicator for GigE VimbaFeatureInt LUTIndex( m_pCamera, "LUTIndex" ); //< get lUT index feature to set current index VimbaFeatureInt LUTValue( m_pCamera, "LUTValue" ); //< get LUT value feature to set current value VimbaFeatureInt LUTSize ( m_pCamera, "LUTSizeBytes"); //< get feature for size of LUT in bytes if( m_data.size() != LUTSize() ) //< compare data size to LUT size { throw Exception( __FUNCTION__,"data size is not equal lut size, they are incompatible",VmbErrorBadParameter ); } //Evaluate number of LUT entries VmbInt64_t nLUTBytePerValue = ( GetBitDepthOut() > 8 ) ? 2 : 1; //< determine if LUT values take one or two bytes VmbInt64_t nLUTEntries = LUTSize() / nLUTBytePerValue; //< calculate lement count, LUT values are unpadded and consecutive in memory //Set LUT values by iteration over indexes int iter( 0 ); VmbInt64_t nValue( 0 ); for( VmbInt64_t i = 0; i < nLUTEntries ; i++ ) { LUTIndex( i ); //< set current index switch( nLUTBytePerValue ) { case 1: nValue = m_data[iter++]; //< copy 8bit value break; case 2: { VmbUint16_t* p = (VmbUint16_t*)(&m_data[iter]); //< interpret data as host byte order uint 16 nValue = *p; iter +=2; } } LUTValue( nValue ); //< write data to camera } } } //Load look up table from Csv void LookUpTableControl::LoadFromCsv( const std::string &FileName, int nIndex ) { //Evaluate size of LUT VmbInt64_t nLUTBitDepthOut = GetBitDepthOut( ); //< get output bit depth of LUT VmbInt64_t nLUTBytePerValue = nLUTBitDepthOut > 8 ? 2 : 1; //< determine if LUT values take one or two byte // Load LUT from CSV CsvLoad load( FileName ); //< import the LUT from CSV file std::vector row; while( load.Row( row ) ) //< load rows until none left { if( row.size() <= ( size_t )nIndex ) //< test if index in range { throw Exception( __FUNCTION__,"index for the csv file is out of bounds",VmbErrorBadParameter ); } int nData; //< coonvert string to int std::stringstream ss( row[nIndex] ); ss >> nData; char data[2]; //< pack data for storage if( 2 == nLUTBytePerValue ) { VmbUint16_t *p = ( VmbUint16_t* )( data ); *p = static_cast( nData ); } else { data[0] = static_cast( nData&0xFF ); } copy( data, data + nLUTBytePerValue, std::back_inserter( m_data ) ); //< append data to internal storage } } //Save look up table to CSV void LookUpTableControl::SaveToCsv( const std::string &FileName ) { //Raw data empty if( m_data.empty() ) { throw Exception( __FUNCTION__,"no data to write to csv file", VmbErrorOther ); } //Evaluate size of LUT VimbaFeatureInt LUTSize( m_pCamera, "LUTSizeBytes" ); //< get feature for LUT size in bytes VmbInt64_t nLUTBitDepthOut = GetBitDepthOut( ); //< get output bit depth of LUT VmbInt64_t nLUTBytePerValue = nLUTBitDepthOut > 8 ? 2 : 1; //< determine if LUT values take one or two bytes VmbInt64_t nLUTEntries = LUTSize()/nLUTBytePerValue; //< calculate LUT element count, LUT values are unpadded and consecutive if( m_data.size() != LUTSize() ) //< if lut size and data size miss match they are not compatible { throw Exception( __FUNCTION__,"data does not equal the current cameras LUT",VmbErrorBadParameter ); } // Save LUT data to CSV CsvSave save( FileName ); //< create CSV file { for( int i = 0; i < nLUTEntries; i++ ) //< for each LUT value { int data ; //< unpack data to int if( 2 == nLUTBytePerValue ) { data = *( ( VmbUint16_t* )( &m_data[i*2] ) ); } else { data = m_data[i]; } stringstream ss; //< stream int to string ss << data; save.Row( ss.str() ); //< write a csv row } } } //Load look up table from flash void LookUpTableControl::LoadFromFlash() { VimbaFeatureCommand LUTLoad = CreateOneOf( m_pCamera, "LUTLoad", "LUTLoadAll" ); // there are two possible names for this feature LUTLoad.Run(); } //Save look up table to flash void LookUpTableControl::SaveToFlash() { VimbaFeatureCommand LUTSave = CreateOneOf( m_pCamera, "LUTSave", "LUTSaveAll" ); //< there are two possible names for this feature LUTSave.Run(); } }}} // namespace AVT::VmbAPI::Examples