Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

218 lines (192 sloc) 9.488 kB
// __BEGIN_LICENSE__
// Copyright (c) 2006-2012, United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration. All
// rights reserved.
//
// The NASA Vision Workbench is licensed under the Apache License,
// Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// __END_LICENSE__
/// \file BlockRasterizeView.h
///
/// Defines a wrapper view that causes an image view to be rasterized
/// one block at a time, rather than all at once, and supports multi-
/// threaded rasterization as well as block-level cacheing. Even when
/// you don't need those features, in some situations rasterizing one
/// block at a time can dramatically improve performance by reducing
/// memory utilization.
///
#ifndef __VW_IMAGE_BLOCKRASTERIZE_H__
#define __VW_IMAGE_BLOCKRASTERIZE_H__
#include <vw/Core/Cache.h>
#include <vw/Image/ImageViewBase.h>
#include <vw/Image/PixelAccessors.h>
#include <vw/Image/Manipulation.h>
#include <vw/Image/BlockProcessor.h>
namespace vw {
/// A wrapper view that rasterizes its child in blocks.
template <class ImageT>
class BlockRasterizeView : public ImageViewBase<BlockRasterizeView<ImageT> > {
public:
typedef typename ImageT::pixel_type pixel_type;
typedef typename ImageT::pixel_type result_type;
typedef ProceduralPixelAccessor<BlockRasterizeView> pixel_accessor;
BlockRasterizeView( ImageT const& image, Vector2i const& block_size,
int num_threads = 0, Cache *cache = NULL )
: m_child( new ImageT(image) ),
m_block_size( block_size ),
m_num_threads( num_threads ),
m_cache_ptr( cache )
{
initialize();
}
inline int32 cols() const { return m_child->cols(); }
inline int32 rows() const { return m_child->rows(); }
inline int32 planes() const { return m_child->planes(); }
inline pixel_accessor origin() const { return pixel_accessor( *this, 0, 0, 0 ); }
inline result_type operator()( int32 x, int32 y, int32 p = 0 ) const {
#if VW_DEBUG_LEVEL > 1
VW_OUT(VerboseDebugMessage, "image") << "ImageResourceView rasterizing pixel (" << x << "," << y << "," << p << ")" << std::endl;
#endif
if ( m_cache_ptr ) {
// Early-out optimization for single-block resources
if( m_block_table.size() == 1 ) {
return m_block_table[0]->operator()( x, y, p );
}
int32 ix = x/m_block_size.x(), iy = y/m_block_size.y();
return block(ix,iy)->operator()( x-ix*m_block_size.x(), y - iy*m_block_size.y(), p );
}
else return (*m_child)(x,y,p);
}
ImageT& child() { return *m_child; }
ImageT const& child() const { return *m_child; }
typedef CropView<ImageView<pixel_type> > prerasterize_type;
inline prerasterize_type prerasterize( BBox2i const& bbox ) const {
ImageView<pixel_type> buf( bbox.width(), bbox.height(), planes() );
rasterize( buf, bbox );
return CropView<ImageView<pixel_type> >( buf, BBox2i(-bbox.min().x(),-bbox.min().y(),cols(),rows()) );
}
template <class DestT> inline void rasterize( DestT const& dest, BBox2i const& bbox ) const {
RasterizeFunctor<DestT> rasterizer( *this, dest, bbox.min() );
BlockProcessor<RasterizeFunctor<DestT> > process( rasterizer, m_block_size, m_num_threads );
process(bbox);
}
private:
// These function objects are spawned to rasterize the child image.
// One functor is created per child thread, and they are called
// in succession with bounding boxes that are each contained
// within one block.
template <class DestT>
class RasterizeFunctor {
BlockRasterizeView const& m_view;
DestT const& m_dest;
Vector2i m_offset;
public:
RasterizeFunctor( BlockRasterizeView const& view, DestT const& dest, Vector2i const& offset )
: m_view(view), m_dest(dest), m_offset(offset) {}
void operator()( BBox2i const& bbox ) const {
#if VW_DEBUG_LEVEL > 1
VW_OUT(VerboseDebugMessage, "image") << "BlockRasterizeView::RasterizeFunctor( " << bbox << " )" << std::endl;
#endif
if( m_view.m_cache_ptr ) {
int32 ix=bbox.min().x()/m_view.m_block_size.x(), iy=bbox.min().y()/m_view.m_block_size.y();
#if VW_DEBUG_LEVEL > 1
int32 maxix=(bbox.max().x()-1)/m_view.m_block_size.x(), maxiy=(bbox.max().y()-1)/m_view.m_block_size.y();
if( maxix != ix || maxiy != iy ) {
vw_throw(LogicErr() << "BlockRasterizeView::RasterizeFunctor: bbox spans more than one cache block!");
}
#endif
m_view.block(ix,iy)->rasterize( crop( m_dest, bbox-m_offset ), bbox-Vector2i(ix*m_view.m_block_size.x(),iy*m_view.m_block_size.y()) );
}
else m_view.child().rasterize( crop( m_dest, bbox-m_offset ), bbox );
}
};
// Allows RasterizeFunctor to access cache-related members.
template <class DestT> friend class RasterizeFunctor;
// These objects rasterize a full block of image data to be
// stored in the cache.
class BlockGenerator {
boost::shared_ptr<ImageT> m_child;
BBox2i m_bbox;
public:
typedef ImageView<pixel_type> value_type;
BlockGenerator( boost::shared_ptr<ImageT> const& child, BBox2i const& bbox )
: m_child( child ), m_bbox( bbox ) {}
size_t size() const {
return m_bbox.width() * m_bbox.height() * m_child->planes() * sizeof(pixel_type);
}
boost::shared_ptr<ImageView<pixel_type> > generate() const {
boost::shared_ptr<ImageView<pixel_type> > ptr( new ImageView<pixel_type>( m_bbox.width(), m_bbox.height(), m_child->planes() ) );
m_child->rasterize( *ptr, m_bbox );
return ptr;
}
};
void initialize() {
if( m_block_size.x() <= 0 || m_block_size.y() <= 0 ) {
const int32 default_blocksize = 2*1024*1024; // 2 megabytes
// XXX Should the default block configuration be different for
// very wide images? Either way we will guess wrong some of
// the time, so advanced users will have to know what they're
// doing in any case.
int32 block_rows = default_blocksize / (planes()*cols()*int32(sizeof(pixel_type)));
if( block_rows < 1 ) block_rows = 1;
else if( block_rows > rows() ) block_rows = rows();
m_block_size = Vector2i( cols(), block_rows );
}
if( m_cache_ptr ) {
m_table_width = (cols()-1) / m_block_size.x() + 1;
m_table_height = (rows()-1) / m_block_size.y() + 1;
m_block_table.resize( m_table_width * m_table_height );
BBox2i view_bbox(0,0,cols(),rows());
for( int32 iy=0; iy<m_table_height; ++iy ) {
for( int32 ix=0; ix<m_table_width; ++ix ) {
BBox2i bbox( ix*m_block_size.x(), iy*m_block_size.y(), m_block_size.x(), m_block_size.y() );
bbox.crop( view_bbox );
block(ix,iy) = m_cache_ptr->insert( BlockGenerator( m_child, bbox ) );
}
}
}
}
const Cache::Handle<BlockGenerator>& block( int ix, int iy ) const {
if( ix<0 || ix>=m_table_width || iy<0 || iy>=m_table_height )
vw_throw( ArgumentErr() << "BlockRasterizeView: Block indices out of bounds, (" << ix
<< "," << iy << ") of (" << m_table_width << "," << m_table_height << ")" );
return m_block_table[ix+iy*m_table_width];
}
Cache::Handle<BlockGenerator>& block( int ix, int iy ) {
if( ix<0 || ix>=m_table_width || iy<0 || iy>=m_table_height )
vw_throw( ArgumentErr() << "BlockRasterizeView: Block indices out of bounds, (" << ix
<< "," << iy << ") of (" << m_table_width << "," << m_table_height << ")" );
return m_block_table[ix+iy*m_table_width];
}
// We store this by shared pointer so it doesn't move when we copy
// the BlockRasterizeView, since the BlockGenerators point to it.
boost::shared_ptr<ImageT> m_child;
Vector2i m_block_size;
int32 m_num_threads;
Cache *m_cache_ptr;
int m_table_width, m_table_height;
// Handles are lightweight and are just pointers underneath
std::vector<Cache::Handle<BlockGenerator> > m_block_table;
};
template <class ImageT>
inline BlockRasterizeView<ImageT> block_rasterize( ImageViewBase<ImageT> const& image, Vector2i const& block_size, int num_threads = 0 ) {
return BlockRasterizeView<ImageT>( image.impl(), block_size, num_threads );
}
template <class ImageT>
inline BlockRasterizeView<ImageT> block_cache( ImageViewBase<ImageT> const& image, Vector2i const& block_size, int num_threads = 0 ) {
return BlockRasterizeView<ImageT>( image.impl(), block_size, num_threads, &vw_system_cache() );
}
template <class ImageT>
inline BlockRasterizeView<ImageT> block_cache( ImageViewBase<ImageT> const& image, Vector2i const& block_size, int num_threads, Cache& cache ) {
return BlockRasterizeView<ImageT>( image.impl(), block_size, num_threads, &cache );
}
} // namespace vw
#endif // __VW_IMAGE_BLOCKRASTERIZE_H__
Jump to Line
Something went wrong with that request. Please try again.