SeparableFilter KernelFilter::AsSeparableFilter( float tolerance ) const { if ( IsEmpty() ) return SeparableFilter(); FSVD svd( coefficients ); // Find the largest singular value int i = svd.IndexOfLargestSingularValue(); // Scaling factor to preserve the original filter weight float k = Sqrt( svd.W[i] ); // Column vector FVector v = svd.U.ColumnVector( i ); v *= k; // Row vector FVector h = svd.V.ColumnVector( i ); h *= k; // Product matrix FMatrix A = FMatrix::FromColumnVector( v ) * FMatrix::FromRowVector( h ); // Verify separability const float* a = A.Begin(); const float* b = coefficients.Begin(); const float* c = coefficients.End(); for ( ; b < c; ++a, ++b ) if ( Abs( *a - *b ) > tolerance ) return SeparableFilter(); return SeparableFilter( h, v, filterName ); }
void FilterParser::Parse( const token_list& tokens ) { filters.Clear(); int filterType = UnknownFilterType; String filterName; int filterSize = 0; KernelFilter::coefficient_matrix filterMatrix; SeparableFilter::coefficient_vector rowVector, colVector; int state = FilterTypeState; for ( token_list::const_iterator i = tokens.Begin(); i != tokens.End(); ) { switch ( state ) { case FilterTypeState: { if ( i->token == "KernelFilter" ) filterType = KernelFilterType; else if ( i->token == "SeparableFilter" ) filterType = SeparableFilterType; else if ( i->token == '{' || i->token == '}' ) PARSE_ERROR( "Misplaced bracket", i ); else if ( !i->token.IsValidIdentifier() ) PARSE_ERROR( "Invalid filter type \'" + i->token + '\'', i ); else PARSE_ERROR( "Unknown filter type \'" + i->token + '\'', i ); if ( ++i == tokens.End() || i->token != '{' ) PARSE_ERROR( "Expected left bracket", i ); state = FilterParameterState; ++i; } break; case FilterParameterState: { if ( i->token == '}' ) { if ( filterName.IsEmpty() ) PARSE_ERROR( "Missing filter name", i ); if ( filterSize == 0 ) PARSE_ERROR( "Empty filter definition", i ); if ( filterType == KernelFilterType ) { if ( filterMatrix.IsEmpty() ) PARSE_ERROR( "Missing kernel filter coefficients", i ); filters.Add( Filter( KernelFilter( filterMatrix, filterName ) ) ); } else if ( filterType == SeparableFilterType ) { if ( rowVector.IsEmpty() || colVector.IsEmpty() ) PARSE_ERROR( "Missing separable filter coefficients", i ); filters.Add( Filter( SeparableFilter( rowVector, colVector, filterName ) ) ); } else PARSE_ERROR( "Internal parser error", i ); filterName.Clear(); filterSize = 0; filterMatrix = KernelFilter::coefficient_matrix(); rowVector = colVector = SeparableFilter::coefficient_vector(); state = FilterTypeState; ++i; } else { token_list::const_iterator j = i; ++j; token_list::const_iterator k = tokens.End(); CaptureParameterValueTokens( j, k ); int n = Distance( j, k ); if ( i->token == "name" ) { if ( n == 0 ) PARSE_ERROR( "Expected a filter name", i ); if ( !filterName.IsEmpty() ) PARSE_ERROR( "Duplicate filter name", i ); filterName = j->token; for ( ; ++j < k; ) filterName += ' ' + j->token; } else if ( i->token == "coefficients" ) { if ( filterType != KernelFilterType ) PARSE_ERROR( "Invalid kernel filter parameter", i ); if ( !filterMatrix.IsEmpty() ) PARSE_ERROR( "Duplicate kernel filter coefficients", i ); token_list::const_iterator p = j; GenericVector<KernelFilter::coefficient> C( n ); for ( KernelFilter::coefficient* c = C.Begin(); c < C.End(); ++c, ++p ) *c = p->token.ToFloat(); int numberOfCoefficients = filterSize*filterSize; if ( numberOfCoefficients != 0 ) { if ( numberOfCoefficients != n ) PARSE_ERROR( "Incongruent kernel filter size; expected " + String( numberOfCoefficients ) + " coefficients", j ); } else { filterSize = TruncI( Sqrt( double( n ) ) ); if ( filterSize*filterSize != n ) PARSE_ERROR( "Non-square kernel filter defined", j ); if ( filterSize < 3 ) PARSE_ERROR( "The kernel filter is too small - 3x3 is the minimum required", j ); if ( (filterSize & 0x01) == 0 ) PARSE_ERROR( "Invalid even kernel filter dimension (" + String( filterSize ) + ')', j ); } filterMatrix = KernelFilter::coefficient_matrix( C.Begin(), filterSize, filterSize ); j = p; } else if ( i->token == "row-vector" ) { if ( filterType != SeparableFilterType ) PARSE_ERROR( "Invalid separable filter parameter", i ); if ( !rowVector.IsEmpty() ) PARSE_ERROR( "Duplicate row vector specification", i ); token_list::const_iterator p = j; rowVector = SeparableFilter::coefficient_vector( n ); for ( SeparableFilter::coefficient* c = rowVector.Begin(); c < rowVector.End(); ++c, ++p ) *c = p->token.ToFloat(); if ( filterSize != 0 ) { if ( filterSize != n ) PARSE_ERROR( "Incongruent separable row filter length; expected " + String( filterSize ) + " coefficients", j ); } else { if ( n < 3 ) PARSE_ERROR( "Too few row filter coefficients specified - three or more coefficients are required", j ); if ( (n & 0x01) == 0 ) PARSE_ERROR( "Invalid even row filter length (" + String( n ) + ')', j ); filterSize = n; } j = p; } else if ( i->token == "col-vector" || i->token == "column-vector" ) { if ( filterType != SeparableFilterType ) PARSE_ERROR( "Invalid separable filter parameter", i ); if ( !colVector.IsEmpty() ) PARSE_ERROR( "Duplicate column vector specification", i ); token_list::const_iterator p = j; colVector = SeparableFilter::coefficient_vector( n ); for ( SeparableFilter::coefficient* c = colVector.Begin(); c != colVector.End(); ++c, ++p ) *c = p->token.ToFloat(); if ( filterSize != 0 ) { if ( filterSize != n ) PARSE_ERROR( "Incongruent separable column filter length; expected " + String( filterSize ) + " coefficients", j ); } else { if ( n < 3 ) PARSE_ERROR( "Too few column filter coefficients specified - three or more coefficients are required", j ); if ( (n & 0x01) == 0 ) PARSE_ERROR( "Invalid even column filter length (" + String( n ) + ')', j ); filterSize = n; } j = p; } else PARSE_ERROR( "Unknown filter parameter '" + i->token + '\'', i ); int d = Distance( i, j ); i = k; if ( d > 1 ) // j-i > 1 if and only if value is enclosed by brackets ++i; } } break; default: PARSE_ERROR( "Internal parser error", i ); } } if ( state != FilterTypeState ) PARSE_ERROR( "Missing right bracket", tokens.At(tokens.UpperBound())); }