void DistanceTransformInv(vector<double>& D, const vector<unsigned char>& L, int mode, int ndim, const int* dims) { vector<unsigned char> invL(L.size()); int i; for(i=0; i<L.size(); ++i) { if(L[i]==0) invL[i]=1; else invL[i]=0; } DistanceTransform(D,invL,mode,ndim,dims); }
void GenerateDistanceFieldMap(const unsigned char* const imagePixels, const Size& imageSize, unsigned char* const distanceMap, const Size& distanceMapSize, const unsigned int fieldBorder, const Vector2& maxSize, bool highQuality) { // constants to reduce redundant calculations const int originalWidth( static_cast<int>(imageSize.width) ); const int originalHeight( static_cast<int>(imageSize.height) ); const int paddedWidth( originalWidth + (fieldBorder * 2 ) ); const int paddedHeight( originalHeight + (fieldBorder * 2 ) ); const int scaledWidth( static_cast<int>(distanceMapSize.width) ); const int scaledHeight( static_cast<int>(distanceMapSize.height) ); const int maxWidth( static_cast<int>(maxSize.width) + (fieldBorder * 2 )); const int maxHeight( static_cast<int>(maxSize.height) + (fieldBorder * 2 ) ); const int bufferLength( std::max( maxWidth, std::max(paddedWidth, scaledWidth) ) * std::max( maxHeight, std::max(paddedHeight, scaledHeight) ) ); std::vector<float> outsidePixels( bufferLength, 0.0f ); std::vector<float> insidePixels( bufferLength, 0.0f ); float* outside( outsidePixels.data() ); float* inside( insidePixels.data() ); for( int y = 0; y < paddedHeight; ++y ) { for ( int x = 0; x < paddedWidth; ++x) { if( y < (int)fieldBorder || y >= (paddedHeight - (int)fieldBorder) || x < (int)fieldBorder || x >= (paddedWidth - (int)fieldBorder) ) { outside[ y * paddedWidth + x ] = MAX_DISTANCE; inside[ y * paddedWidth + x ] = 0.0f; } else { unsigned int pixel( imagePixels[ (y - fieldBorder) * originalWidth + (x - fieldBorder) ] ); outside[ y * paddedWidth + x ] = (pixel == 0) ? MAX_DISTANCE : SQUARE((255 - pixel) / 255.0f); inside[ y * paddedWidth + x ] = (pixel == 255) ? MAX_DISTANCE : SQUARE(pixel / 255.0f); } } } // perform distance transform if high quality requested, else use original figure if( highQuality ) { // create temporary buffers for DistanceTransform() const int tempBufferLength( std::max(paddedWidth, paddedHeight) ); std::vector<float> tempSourceBuffer( tempBufferLength, 0.0f ); std::vector<float> tempDestBuffer( tempBufferLength, 0.0f ); // Perform distance transform for pixels 'outside' the figure DistanceTransform( outside, paddedWidth, paddedHeight, tempSourceBuffer.data(), tempDestBuffer.data() ); // Perform distance transform for pixels 'inside' the figure DistanceTransform( inside, paddedWidth, paddedHeight, tempSourceBuffer.data(), tempDestBuffer.data() ); } // distmap = outside - inside; % Bipolar distance field for( int y = 0; y < paddedHeight; ++y) { for( int x = 0; x < paddedWidth; ++x ) { const int offset( y * paddedWidth + x ); float pixel( sqrtf(outside[offset]) - sqrtf(inside[offset]) ); pixel = 128.0f + pixel * 16.0f; pixel = Clamp( pixel, 0.0f, 255.0f ); outside[offset] = (255.0f - pixel) / 255.0f; } } // scale the figure to the distance field tile size ScaleField( paddedWidth, paddedHeight, outside, scaledWidth, scaledHeight, inside ); // convert from floats to integers for( int y = 0; y < scaledHeight; ++y ) { for( int x = 0; x < scaledWidth; ++x ) { float pixel( inside[ y * scaledWidth + x ] ); distanceMap[y * scaledWidth + x ] = static_cast< unsigned char >(pixel * 255.0f); } } }