本文整理汇总了C++中imath::Box2i::size方法的典型用法代码示例。如果您正苦于以下问题:C++ Box2i::size方法的具体用法?C++ Box2i::size怎么用?C++ Box2i::size使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类imath::Box2i
的用法示例。
在下文中一共展示了Box2i::size方法的13个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: readTypedChannel
DataPtr JPEGImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow, int channelOffset )
{
int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
assert( area >= 0 );
int dataWidth = 1 + dataWindow.size().x;
int dataY = 0;
typedef TypedData< std::vector< V > > TargetVector;
typename TargetVector::Ptr dataContainer = new TargetVector();
typename TargetVector::ValueType &data = dataContainer->writable();
data.resize( area );
ScaledDataConversion< unsigned char, V> converter;
for ( int y = dataWindow.min.y; y <= dataWindow.max.y; ++y, ++dataY )
{
typename TargetVector::ValueType::size_type dataOffset = dataY * dataWidth;
for ( int x = dataWindow.min.x; x <= dataWindow.max.x; ++x, ++dataOffset )
{
assert( dataOffset < data.size() );
data[dataOffset] = converter( m_buffer[ m_numChannels * ( y * m_bufferWidth + x ) + channelOffset ] );
}
}
return dataContainer;
}
示例2: compute
void ImageStats::compute( ValuePlug *output, const Context *context ) const
{
const int colorIndex = ::colorIndex( output );
if( colorIndex == -1 )
{
// Not a plug we know about
ComputeNode::compute( output, context );
return;
}
const std::string channelName = this->channelName( colorIndex );
const Imath::Box2i area = areaPlug()->getValue();
if( channelName.empty() || BufferAlgo::empty( area ) )
{
output->setToDefault();
return;
}
// Loop over the ROI and compute the min, max and average channel values and then set our outputs.
Sampler s( inPlug(), channelName, area );
float min = Imath::limits<float>::max();
float max = Imath::limits<float>::min();
double sum = 0.;
for( int y = area.min.y; y < area.max.y; ++y )
{
for( int x = area.min.x; x < area.max.x; ++x )
{
float v = s.sample( x, y );
min = std::min( v, min );
max = std::max( v, max );
sum += v;
}
}
if( output->parent<Plug>() == minPlug() )
{
static_cast<FloatPlug *>( output )->setValue( min );
}
else if( output->parent<Plug>() == maxPlug() )
{
static_cast<FloatPlug *>( output )->setValue( max );
}
else if( output->parent<Plug>() == averagePlug() )
{
static_cast<FloatPlug *>( output )->setValue(
sum / double( (area.size().x) * (area.size().y) )
);
}
}
示例3: make_color_bars
void make_color_bars( const image_view_t& view, const Imath::Box2i& domain, const Imath::Box2i& defined)
{
typedef detail::color_bars_fn deref_t;
typedef deref_t::point_t point_t;
typedef boost::gil::virtual_2d_locator<deref_t,false> locator_t;
typedef boost::gil::image_view<locator_t> my_virt_view_t;
point_t dims( domain.size().x+1, domain.size().y+1);
my_virt_view_t bars( dims, locator_t( point_t(0,0), point_t(1,1), deref_t( dims)));
boost::gil::copy_pixels( boost::gil::subimage_view( bars, defined.min.x - domain.min.x,
defined.min.y - domain.min.y,
defined.size().x+1, defined.size().y+1), view);
}
示例4: pivotPlug
Imath::M33f Transform2DPlug::matrix( const Imath::Box2i &displayWindow, double pixelAspect ) const
{
// We need to transform from image space (with 0x0 being the bottom left)
// to Gadget space (where 0x0 is the top left). To do this, we need to know the
// size of the Format.
///\todo: We don't handle the pixel aspect of the format here but we should!
float formatHeight = displayWindow.size().y + 1;
M33f p;
V2f pivotVec = pivotPlug()->getValue();
pivotVec.y = formatHeight - pivotVec.y;
p.translate( pivotVec );
M33f t;
V2f translateVec = translatePlug()->getValue();
translateVec.y *= -1.;
t.translate( translateVec );
M33f r;
r.rotate( IECore::degreesToRadians( rotatePlug()->getValue() ) );
M33f s;
s.scale( scalePlug()->getValue() );
M33f pi;
pi.translate( pivotVec*Imath::V2f(-1.f) );
M33f result = pi * s * r * t * p;
return result;
}
示例5: imageData
virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize )
{
Box2i yUpBox = m_gafferFormat.yDownToFormatSpace( box );
const V2i boxMinTileOrigin = ImagePlug::tileOrigin( yUpBox.min );
const V2i boxMaxTileOrigin = ImagePlug::tileOrigin( yUpBox.max );
for( int tileOriginY = boxMinTileOrigin.y; tileOriginY <= boxMaxTileOrigin.y; tileOriginY += ImagePlug::tileSize() )
{
for( int tileOriginX = boxMinTileOrigin.x; tileOriginX <= boxMaxTileOrigin.x; tileOriginX += ImagePlug::tileSize() )
{
for( int channelIndex = 0, numChannels = channelNames().size(); channelIndex < numChannels; ++channelIndex )
{
const V2i tileOrigin( tileOriginX, tileOriginY );
ConstFloatVectorDataPtr tileData = getTile( tileOrigin, channelIndex );
if( !tileData )
{
// we've been sent data outside of the data window
continue;
}
// we must create a new object to hold the updated tile data,
// because the old one might well have been returned from
// computeChannelData and be being held in the cache.
FloatVectorDataPtr updatedTileData = tileData->copy();
vector<float> &updatedTile = updatedTileData->writable();
const Box2i tileBound( tileOrigin, tileOrigin + Imath::V2i( GafferImage::ImagePlug::tileSize() - 1 ) );
const Box2i transferBound = IECore::boxIntersection( tileBound, yUpBox );
for( int y = transferBound.min.y; y<=transferBound.max.y; ++y )
{
int srcY = m_gafferFormat.formatToYDownSpace( y );
size_t srcIndex = ( ( srcY - box.min.y ) * ( box.size().x + 1 ) * numChannels ) + ( transferBound.min.x - box.min.x ) + channelIndex;
size_t dstIndex = ( y - tileBound.min.y ) * ImagePlug::tileSize() + transferBound.min.x - tileBound.min.x;
const size_t srcEndIndex = srcIndex + transferBound.size().x * numChannels;
while( srcIndex <= srcEndIndex )
{
updatedTile[dstIndex] = data[srcIndex];
srcIndex += numChannels;
dstIndex++;
}
}
setTile( tileOrigin, channelIndex, updatedTileData );
}
}
}
dataReceivedSignal()( this, box );
}
示例6: readTypedChannel
DataPtr CINImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow )
{
typedef TypedData< std::vector< V > > TargetVector;
// figure out the offset into the bitstream for the given channel
assert( m_header->m_channelOffsets.find( name ) != m_header->m_channelOffsets.end() );
int channelOffset = m_header->m_channelOffsets[name];
assert( (int)m_header->m_imageInformation.channel_information[channelOffset].bpp == 10 );
int bpp = m_header->m_imageInformation.channel_information[channelOffset].bpp;
// todo: make sure ushort is enough for the current bpp
int ushortShift = sizeof(unsigned short)*8 - bpp;
// form the mask for this channel
unsigned int mask = 0;
for (int pi = 0; pi < bpp; ++pi)
{
mask = 1 + (mask << 1);
}
mask <<= ((32 - bpp) - channelOffset * bpp);
ScaledDataConversion< unsigned short, V> converter;
typename TargetVector::Ptr dataContainer = new TargetVector();
typename TargetVector::ValueType &data = dataContainer->writable();
int area = ( dataWindow.size().x + 1 ) * ( dataWindow.size().y + 1 );
assert( area >= 0 );
data.resize( area );
int dataWidth = 1 + dataWindow.size().x;
Box2i wholeDataWindow = this->dataWindow();
const int yMin = dataWindow.min.y - wholeDataWindow.min.y;
const int yMax = dataWindow.max.y - wholeDataWindow.min.y;
const int xMin = dataWindow.min.x - wholeDataWindow.min.x;
const int xMax = dataWindow.max.x - wholeDataWindow.min.x;
int dataY = 0;
for ( int y = yMin ; y <= yMax ; ++y, ++dataY )
{
typename TargetVector::ValueType::size_type dataOffset = dataY * dataWidth;
std::vector<unsigned int>::size_type bufferOffset = y * m_bufferWidth + xMin;
for ( int x = xMin; x <= xMax ; ++x, ++dataOffset, ++bufferOffset )
{
assert( dataOffset < data.size() );
unsigned int cell = m_buffer[ bufferOffset ];
if ( m_reverseBytes )
{
cell = reverseBytes( cell );
}
// assume we have 10bit log, two wasted bits aligning to 32 longword
unsigned short cv = (unsigned short) ( ( mask & cell ) >> ( 2 + ( 2 - channelOffset ) * bpp ) );
assert( cv < 1024 );
data[dataOffset] = converter( (cv << ushortShift) + ((1 << ushortShift) - 1) );
}
}
return dataContainer;
}
示例7: gray_subimage_view
gray_image_view_t buffer_t::gray_subimage_view( const Imath::Box2i& area) const
{
check_area_inside_image( area);
return boost::gil::subimage_view( gray_view(), area.min.x - bounds_.min.x, area.min.y - bounds_.min.y,
area.size().x+1, area.size().y+1);
}
示例8: execute
///\todo: It seems that if a JPG is written with RGBA channels the output is wrong but it should be supported. Find out why and fix it.
/// There is a test case in ImageWriterTest which checks the output of the jpg writer against an incorrect image and it will fail if it is equal to the writer output.
void ImageWriter::execute( const Contexts &contexts ) const
{
if( !inPlug()->getInput<ImagePlug>() )
{
throw IECore::Exception( "No input image." );
}
// Loop over the execution contexts...
for( Contexts::const_iterator it = contexts.begin(), eIt = contexts.end(); it != eIt; it++ )
{
Context::Scope scopedContext( it->get() );
std::string fileName = fileNamePlug()->getValue();
fileName = (*it)->substitute( fileName );
boost::shared_ptr< ImageOutput > out( ImageOutput::create( fileName.c_str() ) );
if ( !out )
{
throw IECore::Exception( boost::str( boost::format( "Invalid filename: %s" ) % fileName ) );
}
// Grab the intersection of the channels from the "channels" plug and the image input to see which channels we are to write out.
IECore::ConstStringVectorDataPtr channelNamesData = inPlug()->channelNamesPlug()->getValue();
std::vector<std::string> maskChannels = channelNamesData->readable();
channelsPlug()->maskChannels( maskChannels );
const int nChannels = maskChannels.size();
// Get the image channel data.
IECore::ImagePrimitivePtr imagePtr( inPlug()->image() );
// Get the image's display window.
const Imath::Box2i displayWindow( imagePtr->getDisplayWindow() );
const int displayWindowWidth = displayWindow.size().x+1;
const int displayWindowHeight = displayWindow.size().y+1;
// Get the image's data window and if it then set a flag.
bool imageIsBlack = false;
Imath::Box2i dataWindow( imagePtr->getDataWindow() );
if ( inPlug()->dataWindowPlug()->getValue().isEmpty() )
{
dataWindow = displayWindow;
imageIsBlack = true;
}
int dataWindowWidth = dataWindow.size().x+1;
int dataWindowHeight = dataWindow.size().y+1;
// Create the image header.
ImageSpec spec( dataWindowWidth, dataWindowHeight, nChannels, TypeDesc::FLOAT );
// Add the channel names to the header whilst getting pointers to the channel data.
std::vector<const float*> channelPtrs;
spec.channelnames.clear();
for ( std::vector<std::string>::iterator channelIt( maskChannels.begin() ); channelIt != maskChannels.end(); channelIt++ )
{
spec.channelnames.push_back( *channelIt );
IECore::FloatVectorDataPtr dataPtr = imagePtr->getChannel<float>( *channelIt );
channelPtrs.push_back( &(dataPtr->readable()[0]) );
// OIIO has a special attribute for the Alpha and Z channels. If we find some, we should tag them...
if ( *channelIt == "A" )
{
spec.alpha_channel = channelIt-maskChannels.begin();
} else if ( *channelIt == "Z" )
{
spec.z_channel = channelIt-maskChannels.begin();
}
}
// Specify the display window.
spec.full_x = displayWindow.min.x;
spec.full_y = displayWindow.min.y;
spec.full_width = displayWindowWidth;
spec.full_height = displayWindowHeight;
spec.x = dataWindow.min.x;
spec.y = dataWindow.min.y;
if ( !out->open( fileName, spec ) )
{
throw IECore::Exception( boost::str( boost::format( "Could not open \"%s\", error = %s" ) % fileName % out->geterror() ) );
}
// Only allow tiled output if our file format supports it.
int writeMode = writeModePlug()->getValue() & out->supports( "tile" );
if ( writeMode == Scanline )
{
// Create a buffer for the scanline.
float scanline[ nChannels*dataWindowWidth ];
if ( imageIsBlack )
{
memset( scanline, 0, sizeof(float) * nChannels*dataWindowWidth );
for ( int y = spec.y; y < spec.y + dataWindowHeight; ++y )
{
if ( !out->write_scanline( y, 0, TypeDesc::FLOAT, &scanline[0] ) )
{
//.........这里部分代码省略.........
示例9: readTypedChannel
DataPtr EXRImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow, const Imf::Channel *channel )
{
assert( channel );
Imath::V2i pixelDimensions = dataWindow.size() + Imath::V2i( 1 );
unsigned numPixels = pixelDimensions.x * pixelDimensions.y;
typedef TypedData<vector<T> > DataType;
typename DataType::Ptr data = new DataType;
data->writable().resize( numPixels );
Imath::Box2i fullDataWindow = this->dataWindow();
if( fullDataWindow.min.x==dataWindow.min.x && fullDataWindow.max.x==dataWindow.max.x )
{
// the width we want to read matches the width in the file, so we can read straight
// into the result buffer
FrameBuffer frameBuffer;
T *buffer00 = data->baseWritable() - dataWindow.min.y * pixelDimensions.x - fullDataWindow.min.x;
Slice slice( channel->type, (char *)buffer00, sizeof(T), sizeof(T) * pixelDimensions.x );
frameBuffer.insert( name.c_str(), slice );
m_inputFile->setFrameBuffer( frameBuffer );
// exr library will choose the best order to read scanlines automatically (increasing or decreasing)
try
{
m_inputFile->readPixels( dataWindow.min.y, dataWindow.max.y );
}
catch( Iex::InputExc &e )
{
// so we can read incomplete files
msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
return data;
}
}
else
{
// widths don't match, we need to read into a temporary buffer and then transfer just
// the bits we need into the result buffer.
int numTmpPixels = fullDataWindow.size().x + 1;
vector<T> tmpBuffer( numTmpPixels );
T *tmpBufferTransferStart = &(tmpBuffer[0]) + dataWindow.min.x - fullDataWindow.min.x;
size_t tmpBufferTransferLength = pixelDimensions.x * sizeof( T );
T *transferDestination = &(data->writable()[0]);
// slice has yStride of 0 so each successive scanline just overwrites the previous one
Slice slice( channel->type, (char *)(&(tmpBuffer[0]) - fullDataWindow.min.x), sizeof(T), 0 );
FrameBuffer frameBuffer;
frameBuffer.insert( name.c_str(), slice );
m_inputFile->setFrameBuffer( frameBuffer );
int yStart = dataWindow.min.y;
int yEnd = dataWindow.max.y;
int yStep = 1;
try
{
for( int y=yStart; y!=(yEnd+yStep); y+=yStep )
{
m_inputFile->readPixels( y );
memcpy( (char *)transferDestination, (const char *)tmpBufferTransferStart, tmpBufferTransferLength );
transferDestination += pixelDimensions.x;
}
}
catch( Iex::InputExc &e )
{
// so we can read incomplete files
msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
return data;
}
}
#ifndef NDEBUG
for ( typename DataType::ValueType::const_iterator it = data->readable().begin(); it != data->readable().end(); ++it )
{
assert( *it == *it ); // Will fail iff NaN
}
#endif
return data;
}
示例10: resize
void viewport_t::resize( const Imath::Box2i& device)
{
world_.max.x = world_.min.x + ( device.size().x / zoom_x());
world_.max.y = world_.min.y + ( device.size().y / zoom_y());
device_ = device;
}
示例11: composite
void ImageCompositeOp::composite( CompositeFn fn, DataWindowResult dwr, ImagePrimitive * imageB, const CompoundObject * operands )
{
assert( fn );
assert( imageB );
assert( operands );
const StringVectorParameter::ValueType &channelNames = channelNamesParameter()->getTypedValue();
if ( !channelNames.size() )
{
throw InvalidArgumentException( "ImageCompositeOp: No channels specified" );
}
ImagePrimitivePtr imageA = runTimeCast< ImagePrimitive > ( imageAParameter()->getValue() );
assert( imageA );
const std::string &alphaChannel = alphaChannelNameParameter()->getTypedValue();
if ( !imageA->arePrimitiveVariablesValid() )
{
throw InvalidArgumentException( "ImageCompositeOp: Input image has invalid channels" );
}
const int inputMode = m_inputModeParameter->getNumericValue();
if ( inputMode == Unpremultiplied )
{
ImagePremultiplyOpPtr premultOp = new ImagePremultiplyOp();
premultOp->alphaChannelNameParameter()->setTypedValue( alphaChannel );
premultOp->channelNamesParameter()->setTypedValue( channelNames );
if ( imageA->variables.find( alphaChannel ) != imageA->variables.end() )
{
/// Make a new imageA, premultiplied
premultOp->copyParameter()->setTypedValue( true );
premultOp->inputParameter()->setValue( imageA );
imageA = assertedStaticCast< ImagePrimitive >( premultOp->operate() );
assert( imageA->arePrimitiveVariablesValid() );
}
if ( imageB->variables.find( alphaChannel ) != imageB->variables.end() )
{
/// Premultiply imageB in-place
premultOp->copyParameter()->setTypedValue( false );
premultOp->inputParameter()->setValue( imageB );
premultOp->operate();
}
}
else
{
assert( inputMode == Premultiplied );
}
const Imath::Box2i displayWindow = imageB->getDisplayWindow();
Imath::Box2i newDataWindow = imageB->getDataWindow();
if ( dwr == Union )
{
newDataWindow.extendBy( imageA->getDataWindow() );
}
else
{
assert( dwr == Intersection );
newDataWindow = boxIntersection( newDataWindow, imageA->getDataWindow() );
}
newDataWindow = boxIntersection( newDataWindow, displayWindow );
ImageCropOpPtr cropOp = new ImageCropOp();
/// Need to make sure that we don't create a new image here - we want to modify the current one in-place. So,
/// we turn off the "copy" parameter of ModifyOp.
cropOp->copyParameter()->setTypedValue( false );
cropOp->inputParameter()->setValue( imageB );
cropOp->cropBoxParameter()->setTypedValue( newDataWindow );
cropOp->matchDataWindowParameter()->setTypedValue( true );
cropOp->resetOriginParameter()->setTypedValue( false );
cropOp->operate();
assert( imageB->arePrimitiveVariablesValid() );
assert( imageB->getDataWindow() == newDataWindow );
/// \todo Use the "reformat" parameter of the ImageCropOp to do this, when it's implemented
imageB->setDisplayWindow( displayWindow );
FloatVectorDataPtr aAlphaData = getChannelData( imageA.get(), alphaChannel, false );
FloatVectorDataPtr bAlphaData = getChannelData( imageB, alphaChannel, false );
const int newWidth = newDataWindow.size().x + 1;
const int newHeight = newDataWindow.size().y + 1;
const int newArea = newWidth * newHeight;
assert( newArea == (int)imageB->variableSize( PrimitiveVariable::Vertex ) );
for( unsigned i=0; i<channelNames.size(); i++ )
{
const StringVectorParameter::ValueType::value_type &channelName = channelNames[i];
FloatVectorDataPtr aData = getChannelData( imageA.get(), channelName );
//.........这里部分代码省略.........
示例12: modifyChannels
void HitMissTransform::modifyChannels( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, ChannelVector &channels )
{
// process the structuring elements, including making rotated versions if requested.
bool rotateElements = rotateStructuringElementsParameter()->getTypedValue();
vector<int> masks;
vector<int> elements;
const std::vector<M33f> &matrices = structuringElementsParameter()->getTypedValue();
for( unsigned i=0; i<matrices.size(); i++ )
{
int mask = 0;
int element = 0;
processMatrix( matrices[i], mask, element );
masks.push_back( mask );
elements.push_back( element );
if( rotateElements )
{
M33f m = matrices[i];
for( unsigned r=0; r<3; r++ )
{
M33f m2( m[0][2], m[1][2], m[2][2], m[0][1], m[1][1], m[2][1], m[0][0], m[1][0], m[2][0] );
processMatrix( m2, mask, element );
masks.push_back( mask );
elements.push_back( element );
m = m2;
}
}
}
// apply the operation to each channel
char value = valueParameter()->getNumericValue() > thresholdParameter()->getNumericValue() ? 1 : 0;
char borderValue = borderValueParameter()->getNumericValue() > thresholdParameter()->getNumericValue() ? 1 : 0;
bool applyAlternately = applyElementsAlternatelyParameter()->getTypedValue();
int numIterations = iterationsParameter()->getNumericValue();
if( applyAlternately )
{
numIterations *= elements.size();
}
V2i size = dataWindow.size() + V2i( 1 );
V2i paddedSize = size + V2i( 2 );
std::vector<char> pixels;
std::vector<char> pixels2;
for( unsigned i=0; i<channels.size(); i++ )
{
// threshold the image into a temporary pixels structure
Thresholder thresholder( thresholdParameter()->getNumericValue(), borderValue, size, pixels );
despatchTypedData<Thresholder, TypeTraits::IsNumericVectorTypedData>( channels[i], thresholder );
pixels2.clear(); pixels2.resize( pixels.size(), borderValue );
// do the work
unsigned iterationsSinceChange = 0;
for( int n=0; n<numIterations || numIterations==0; n++ )
{
iterationsSinceChange++;
for( int y=0; y<size.y; y++ )
{
const char *r0 = &(pixels[y * paddedSize.x]) + 1;
const char *r1 = r0 + paddedSize.x;
const char *r2 = r1 + paddedSize.x;
char *ro = &(pixels2[(y+1) * paddedSize.x]) + 1;
for( int x=0; x<size.x; x++ )
{
if( *r1==value )
{
// no point doing the work if the existing value is the one we'd change it to anyway
*ro = value;
}
else
{
int v = r0[-1] | r0[0] << 2 | r0[1] << 4 |
r1[-1] << 6 | r1[0] << 8 | r1[1] << 10 |
r2[-1] << 12 | r2[0] << 14 | r2[1] << 16;
bool matches = false;
if( applyAlternately )
{
size_t e = n % elements.size();
if( (v & masks[e])==elements[e] )
{
matches = true;
}
}
else
{
for( size_t e=0; e<elements.size(); e++ )
{
if( (v & masks[e])==elements[e] )
{
matches = true;
break;
}
}
}
if( matches )
//.........这里部分代码省略.........
示例13: modifyChannels
void ImageThinner::modifyChannels( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, ChannelVector &channels )
{
float threshold = thresholdParameter()->getNumericValue();
const V2i size = dataWindow.size() + V2i( 1 );
for( unsigned i=0; i<channels.size(); i++ )
{
FloatVectorDataPtr floatData = runTimeCast<FloatVectorData>( channels[i] );
if( !floatData )
{
throw Exception( "ImageThinner::modifyChannels : only float channels supported." );
}
std::vector<float> &channel = floatData->writable();
// threshold the image first
for( std::vector<float>::iterator it=channel.begin(); it!=channel.end(); it++ )
{
*it = *it < threshold ? 0.0f : 1.0f;
}
// then apply the graphics gems magic that i don't understand in the slightest
//////////////////////////////////////////////////////////////////////////////
boost::multi_array_ref<float, 2> image( &channel[0], boost::extents[size.y][size.x] );
int p, q; // Neighborhood maps of adjacent cells
std::vector<unsigned char> qb; // Neighborhood maps of previous scanline
qb.resize( size.x );
qb[qb.size()-1] = 0; // Used for lower-right pixel
int count = 1; // Deleted pixel count
while( count )
{
count = 0;
for( int i = 0; i < 4 ; i++ )
{
int m = g_masks[i];
// Build initial previous scan buffer
p = image[0][0] > 0.5f;
for( int x = 0; x < size.x-1; x++ )
{
qb[x] = p = ((p<<1)&0006) | (image[0][x+1] > 0.5f);
}
// Scan image for pixel deletion candidates
for( int y = 0; y < size.y-1; y++ )
{
q = qb[0];
p = ((q<<3)&0110) | (image[y+1][0] > 0.5f);
for( int x = 0; x < size.x-1; x++ )
{
q = qb[x];
p = ((p<<1)&0666) | ((q<<3)&0110) |
(image[y+1][x+1] > 0.5f);
qb[x] = p;
if( ((p&m) == 0) && g_delete[p] )
{
count++;
image[y][x] = 0.f;
}
}
// Process right edge pixel
p = (p<<1)&0666;
if( (p&m) == 0 && g_delete[p] )
{
count++;
image[y][size.x-1] = 0.f;
}
}
// Process bottom scan line
for( int x = 0 ; x < size.x ; x++ )
{
q = qb[x];
p = ((p<<1)&0666) | ((q<<3)&0110);
if( (p&m) == 0 && g_delete[p] )
{
count++;
image[size.y-1][x] = 0.f;
}
}
}
}
}
}