Skip to content

Commit

Permalink
Core: Use a more exhaustive intersect
Browse files Browse the repository at this point in the history
Instead of just intersecting the bounding bboxes, intersect the actual
shapes.
  • Loading branch information
Zack Moratto committed Mar 25, 2013
1 parent ac36bcd commit 0811ed7
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 54 deletions.
75 changes: 60 additions & 15 deletions src/asp/Core/BlobIndexThreaded.cc
Expand Up @@ -53,6 +53,20 @@ void BlobCompressed::refactor() {
} }
} }


BlobCompressed::BlobCompressed( vw::Vector2i const& top_left,
std::vector<std::list<vw::int32> > const& row_start,
std::vector<std::list<vw::int32> > const& row_end ) :
m_min(top_left), m_row_start(row_start), m_row_end(row_end) {
VW_DEBUG_ASSERT( row_start.size() == row_end.size(),
vw::InputErr() << "Input vectors do not have the same length." );
for ( size_t i = 0; i < row_start.size(); i++ ) {
VW_DEBUG_ASSERT( row_start[i].size() == row_end[i].size(),
vw::InputErr() << "List at row " << i << " doesn't have matched starts and ends." );
}
}

BlobCompressed::BlobCompressed() : m_min(-1,-1) {}

int32 BlobCompressed::size() const { int32 BlobCompressed::size() const {
int32 sum = 0; int32 sum = 0;
for ( uint32 r = 0; r < m_row_end.size(); r++ ) for ( uint32 r = 0; r < m_row_end.size(); r++ )
Expand All @@ -76,6 +90,26 @@ BBox2i BlobCompressed::bounding_box() const {
return bbox; return bbox;
} }


bool BlobCompressed::intersects( vw::BBox2i const& input ) const {
// Check if Y's overlap.
if ( input.max().y() <= m_min.y() ||
input.min().y() >= m_min.y() + int32(m_row_start.size()) )
return false;

// Check X for each row.
for ( size_t i = 0; i < m_row_start.size(); i++ ) {
if ( !m_row_start[i].size() ||
m_min.y() + int32(i) < input.min().y() ||
m_min.y() + int32(i) >= input.max().y() )
continue;
if ( m_row_end[i].back() + m_min.x() > input.min().x() &&
m_row_start[i].front() + m_min.x() < input.max().x() ) {
return true;
}
}
return false;
}

bool BlobCompressed::is_on_right( BlobCompressed const& right ) const { bool BlobCompressed::is_on_right( BlobCompressed const& right ) const {
int32 y_offset = m_min.y()-right.min().y()-1; int32 y_offset = m_min.y()-right.min().y()-1;
// Starting r_i on the index above // Starting r_i on the index above
Expand All @@ -84,15 +118,15 @@ bool BlobCompressed::is_on_right( BlobCompressed const& right ) const {
i++, r_i++ ) { i++, r_i++ ) {
if ( r_i >= 0 && r_i < int32(right.num_rows()) ) if ( r_i >= 0 && r_i < int32(right.num_rows()) )
if ( m_row_end[i].back() + m_min.x() == if ( m_row_end[i].back() + m_min.x() ==
right.start(r_i).front()+right.min().x() ) right.m_row_start[r_i].front()+right.min().x() )
return true; return true;
if ( r_i+1 >= 0 && r_i+1 < int32(right.num_rows()) ) if ( r_i+1 >= 0 && r_i+1 < int32(right.num_rows()) )
if ( m_row_end[i].back() + m_min.x() == if ( m_row_end[i].back() + m_min.x() ==
right.start(r_i+1).front()+right.min().x() ) right.m_row_start[r_i+1].front()+right.min().x() )
return true; return true;
if ( r_i+2 >= 0 && r_i+2 < int32(right.num_rows()) ) if ( r_i+2 >= 0 && r_i+2 < int32(right.num_rows()) )
if ( m_row_end[i].back() + m_min.x() == if ( m_row_end[i].back() + m_min.x() ==
right.start(r_i+2).front()+right.min().x() ) right.m_row_start[r_i+2].front()+right.min().x() )
return true; return true;
} }
return false; return false;
Expand All @@ -105,8 +139,8 @@ bool BlobCompressed::is_on_bottom( BlobCompressed const& bottom ) const {
for ( std::list<int32>::const_iterator top_start = m_row_start.back().begin(), for ( std::list<int32>::const_iterator top_start = m_row_start.back().begin(),
top_end = m_row_end.back().begin(); top_start != m_row_start.back().end(); top_end = m_row_end.back().begin(); top_start != m_row_start.back().end();
top_start++, top_end++ ) top_start++, top_end++ )
for ( std::list<int32>::const_iterator bot_start = bottom.start(0).begin(), for ( std::list<int32>::const_iterator bot_start = bottom.m_row_start[0].begin(),
bot_end = bottom.end(0).begin(); bot_start != bottom.start(0).end(); bot_end = bottom.m_row_end[0].begin(); bot_start != bottom.m_row_start[0].end();
bot_start++, bot_end++ ) { bot_start++, bot_end++ ) {
if ( (*top_end+m_min.x() >= *bot_start + bottom.min().x()) && if ( (*top_end+m_min.x() >= *bot_start + bottom.min().x()) &&
(*top_start+m_min.x() <= *bot_end+bottom.min().x()) ) (*top_start+m_min.x() <= *bot_end+bottom.min().x()) )
Expand Down Expand Up @@ -156,8 +190,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
if ( m_row_start.empty() ) { if ( m_row_start.empty() ) {
m_min = victim.min(); m_min = victim.min();
for ( int i = 0; i < victim.num_rows(); i++ ) { for ( int i = 0; i < victim.num_rows(); i++ ) {
m_row_start.push_back( victim.start(i) ); m_row_start.push_back( victim.m_row_start[i] );
m_row_end.push_back( victim.end(i) ); m_row_end.push_back( victim.m_row_end[i] );
} }
return; return;
} }
Expand All @@ -174,8 +208,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {


// Inserting victim's connected rows in singletons at a time // Inserting victim's connected rows in singletons at a time
// become sometimes they connect like zippers. // become sometimes they connect like zippers.
for ( std::list<int32>::const_iterator v_singleton_start = victim.start(i).begin(), for ( std::list<int32>::const_iterator v_singleton_start = victim.m_row_start[i].begin(),
v_singleton_end = victim.end(i).begin(); v_singleton_start != victim.start(i).end(); v_singleton_end = victim.m_row_end[i].begin(); v_singleton_start != victim.m_row_start[i].end();
v_singleton_start++, v_singleton_end++ ) { v_singleton_start++, v_singleton_end++ ) {


std::list<int32>::iterator start_insertion_point = m_row_start[m_index].begin(), std::list<int32>::iterator start_insertion_point = m_row_start[m_index].begin(),
Expand Down Expand Up @@ -249,8 +283,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
std::vector<std::list<int32> > temp_end; std::vector<std::list<int32> > temp_end;
for ( int v_i = 0; v_i < m_min.y()-victim.min().y(); v_i++ ) { for ( int v_i = 0; v_i < m_min.y()-victim.min().y(); v_i++ ) {
if ( v_i < victim.num_rows() ) { if ( v_i < victim.num_rows() ) {
temp_start.push_back(victim.start(v_i)); temp_start.push_back(victim.m_row_start[v_i]);
temp_end.push_back(victim.end(v_i)); temp_end.push_back(victim.m_row_end[v_i]);
for ( std::list<int32>::iterator i_start = temp_start.back().begin(), for ( std::list<int32>::iterator i_start = temp_start.back().begin(),
i_stop = temp_end.back().begin(); i_stop = temp_end.back().begin();
i_start != temp_start.back().end(); i_start++, i_stop++ ) { i_start != temp_start.back().end(); i_start++, i_stop++ ) {
Expand Down Expand Up @@ -285,8 +319,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
temp_start.push_back(std::list<int32>()); temp_start.push_back(std::list<int32>());
temp_end.push_back(std::list<int32>()); temp_end.push_back(std::list<int32>());
} else { } else {
temp_start.push_back( victim.start(v_i) ); temp_start.push_back( victim.m_row_start[v_i] );
temp_end.push_back( victim.end(v_i) ); temp_end.push_back( victim.m_row_end[v_i] );
for ( std::list<int32>::iterator i_start = temp_start.back().begin(), for ( std::list<int32>::iterator i_start = temp_start.back().begin(),
i_stop = temp_end.back().begin(); i_stop = temp_end.back().begin();
i_start != temp_start.back().end(); i_start++, i_stop++ ) { i_start != temp_start.back().end(); i_start++, i_stop++ ) {
Expand All @@ -303,14 +337,14 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
temp_end.end() ); temp_end.end() );
} }
// Recalculate min.x() // Recalculate min.x()
int32 valid_first = 0; size_t valid_first = 0;
while ( valid_first < m_row_start.size() ) { while ( valid_first < m_row_start.size() ) {
if ( m_row_start[valid_first].size() ) if ( m_row_start[valid_first].size() )
break; break;
valid_first++; valid_first++;
} }
int32 lowest_value = m_row_start[valid_first].front(); int32 lowest_value = m_row_start[valid_first].front();
for ( uint32 i = ++valid_first; i < m_row_start.size(); i++ ) { for (size_t i = ++valid_first; i < m_row_start.size(); i++ ) {
if ( m_row_start[i].front() < lowest_value ) if ( m_row_start[i].front() < lowest_value )
lowest_value = m_row_start[i].front(); lowest_value = m_row_start[i].front();
} }
Expand All @@ -328,6 +362,17 @@ void BlobCompressed::decompress( std::list<Vector2i>& output ) const {
output.push_back( Vector2i(c,r)+m_min ); output.push_back( Vector2i(c,r)+m_min );
} }


void BlobCompressed::print() const {
vw::vw_out() << "BlobCompressed | min: " << m_min << "\n";
for ( vw::uint32 i = 0; i < m_row_start.size(); i++ ) {
vw::vw_out() << " " << i << "|";
for ( std::list<vw::int32>::const_iterator s_iter = m_row_start[i].begin(),
e_iter = m_row_end[i].begin(); s_iter != m_row_start[i].end();
s_iter++, e_iter++ )
vw::vw_out() << "(" << *s_iter << "<>" << *e_iter << ")";
vw::vw_out() <<"\n";
}
}


class ConsolidateAbsorbTask : public Task, private boost::noncopyable { class ConsolidateAbsorbTask : public Task, private boost::noncopyable {
std::deque<BlobCompressed> &m_src_c_blob, &m_dest_c_blob; std::deque<BlobCompressed> &m_src_c_blob, &m_dest_c_blob;
Expand Down
48 changes: 14 additions & 34 deletions src/asp/Core/BlobIndexThreaded.h
Expand Up @@ -60,16 +60,8 @@ namespace blob {
public: public:
BlobCompressed( vw::Vector2i const& top_left, BlobCompressed( vw::Vector2i const& top_left,
std::vector<std::list<vw::int32> > const& row_start, std::vector<std::list<vw::int32> > const& row_start,
std::vector<std::list<vw::int32> > const& row_end ) : std::vector<std::list<vw::int32> > const& row_end );
m_min(top_left), m_row_start(row_start), m_row_end(row_end) { BlobCompressed();
VW_DEBUG_ASSERT( row_start.size() == row_end.size(),
vw::InputErr() << "Input vectors do not have the same length." );
for ( size_t i = 0; i < row_start.size(); i++ ) {
VW_DEBUG_ASSERT( row_start[i].size() == row_end[i].size(),
vw::InputErr() << "List at row " << i << " doesn't have matched starts and ends." );
}
}
BlobCompressed() { m_min = vw::Vector2i(-1,-1); }


// Standard Access point // Standard Access point
vw::Vector2i const& min() const { return m_min; } vw::Vector2i const& min() const { return m_min; }
Expand All @@ -79,29 +71,20 @@ namespace blob {
std::list<vw::int32> const& end( vw::uint32 const& index ) const { return m_row_end[index]; } std::list<vw::int32> const& end( vw::uint32 const& index ) const { return m_row_end[index]; }
vw::int32 size() const; // Please use sparingly vw::int32 size() const; // Please use sparingly
vw::BBox2i bounding_box() const; vw::BBox2i bounding_box() const;
bool intersects( vw::BBox2i const& input ) const;


// Rather specific conditionals used by BlobIndexThreaded // Specific conditionals used by BlobIndexThreaded
bool is_on_right( BlobCompressed const& right ) const; bool is_on_right( BlobCompressed const& right ) const;
bool is_on_bottom( BlobCompressed const& bottom ) const; bool is_on_bottom( BlobCompressed const& bottom ) const;


// Append a row (since these guys are built a row at a time ) // Append a row (since these guys are built a row at a time )
void add_row( vw::Vector2i const& start, int const& width ); void add_row( vw::Vector2i const& start, int const& width );
// Use to expand this blob into a non overlapped area // Use to expand this blob into a non overlapped area
void absorb( BlobCompressed const& victim ); void absorb( BlobCompressed const& victim );
// Dump into stupid format // Dump listing of every pixel used
void decompress( std::list<vw::Vector2i>& output ) const; void decompress( std::list<vw::Vector2i>& output ) const;

// Print internal data
void print() const { void print() const;
vw::vw_out() << "BlobCompressed | min: " << m_min << "\n";
for ( vw::uint32 i = 0; i < m_row_start.size(); i++ ) {
vw::vw_out() << " " << i << "|";
for ( std::list<vw::int32>::const_iterator s_iter = m_row_start[i].begin(),
e_iter = m_row_end[i].begin(); s_iter != m_row_start[i].end();
s_iter++, e_iter++ )
vw::vw_out() << "(" << *s_iter << "<>" << *e_iter << ")";
vw::vw_out() <<"\n";
}
}
}; };


// Blob Index Custom // Blob Index Custom
Expand Down Expand Up @@ -295,11 +278,7 @@ namespace blob {
///////////////////////////////////// /////////////////////////////////////
// A task wrapper to allow threading // A task wrapper to allow threading
template <class SourceT> template <class SourceT>
class BlobIndexTask : public vw::Task { class BlobIndexTask : public vw::Task, private boost::noncopyable {
// Disable copy !!
BlobIndexTask(BlobIndexTask& copy){}
void operator=(BlobIndexTask& copy) {}

vw::ImageViewBase<SourceT> const& m_view; vw::ImageViewBase<SourceT> const& m_view;
vw::BBox2i const& m_bbox; vw::BBox2i const& m_bbox;
vw::Mutex& m_append_mutex; vw::Mutex& m_append_mutex;
Expand Down Expand Up @@ -380,9 +359,8 @@ class BlobIndexThreaded {
vw::FifoWorkQueue queue(vw::vw_settings().default_num_threads()); vw::FifoWorkQueue queue(vw::vw_settings().default_num_threads());
typedef blob::BlobIndexTask<SourceT> task_type; typedef blob::BlobIndexTask<SourceT> task_type;


std::vector<vw::BBox2i> bboxes = image_blocks( src.impl(), std::vector<vw::BBox2i> bboxes =
m_tile_size, image_blocks( src.impl(), m_tile_size, m_tile_size );
m_tile_size );
for ( size_t i = 0; i < bboxes.size(); ++i ) { for ( size_t i = 0; i < bboxes.size(); ++i ) {
boost::shared_ptr<task_type> task(new task_type(src, bboxes[i], m_insert_mutex, boost::shared_ptr<task_type> task(new task_type(src, bboxes[i], m_insert_mutex,
m_c_blob, m_blob_bbox, m_c_blob, m_blob_bbox,
Expand All @@ -399,13 +377,15 @@ class BlobIndexThreaded {
vw::Vector2i( m_tile_size, m_tile_size ) ); vw::Vector2i( m_tile_size, m_tile_size ) );


// Cull blobs that are too big. // Cull blobs that are too big.
if ( m_max_area > 0 ) if ( m_max_area > 0 ) {
for ( std::deque<blob::BlobCompressed>::iterator iter = m_c_blob.begin(); for ( std::deque<blob::BlobCompressed>::iterator iter = m_c_blob.begin();
iter != m_c_blob.end(); iter++ ) iter != m_c_blob.end(); iter++ ) {
if ( iter->size() > m_max_area ) { if ( iter->size() > m_max_area ) {
iter = m_c_blob.erase( iter ); iter = m_c_blob.erase( iter );
iter--; iter--;
} }
}
}
} }


// Access for the users // Access for the users
Expand Down
10 changes: 5 additions & 5 deletions src/asp/Core/InpaintView.h
Expand Up @@ -190,11 +190,11 @@ namespace asp {
std::vector<size_t> intersections; std::vector<size_t> intersections;
intersections.reserve(20); intersections.reserve(20);
BBox2i bbox_expanded = bbox; BBox2i bbox_expanded = bbox;
for ( BlobIndexThreaded::const_bbox_iterator bbox_it = m_bindex.bbox_begin(); for ( size_t i = 0; i < m_bindex.num_blobs(); i++ ) {
bbox_it != m_bindex.bbox_end(); bbox_it++ ) { if ( m_bindex.blob_bbox(i).intersects( bbox ) && // Early exit option
if ( bbox_it->intersects( bbox ) ) { m_bindex.compressed_blob(i).intersects( bbox ) ) {
bbox_expanded.grow( *bbox_it ); bbox_expanded.grow( m_bindex.blob_bbox(i) );
intersections.push_back( bbox_it - m_bindex.bbox_begin() ); intersections.push_back(i);
} }
} }
bbox_expanded.expand(1); bbox_expanded.expand(1);
Expand Down
20 changes: 20 additions & 0 deletions src/asp/Core/tests/TestBlobIndexThreaded.cxx
Expand Up @@ -21,8 +21,11 @@
#include <vw/FileIO.h> #include <vw/FileIO.h>
#include <vw/Image.h> #include <vw/Image.h>
#include <asp/Core/BlobIndexThreaded.h> #include <asp/Core/BlobIndexThreaded.h>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp>


using namespace vw; using namespace vw;
using namespace boost::assign;


TEST(BlobIndexThreaded, TestImage1) { TEST(BlobIndexThreaded, TestImage1) {
DiskImageView<PixelGray<uint8> > input("ThreadTest1.tif"); DiskImageView<PixelGray<uint8> > input("ThreadTest1.tif");
Expand All @@ -44,3 +47,20 @@ TEST(BlobIndexThreaded, TestImage3) {
BlobIndexThreaded bindex( create_mask(input,255), 1000, 5 ); BlobIndexThreaded bindex( create_mask(input,255), 1000, 5 );
EXPECT_EQ( 2u, bindex.num_blobs() ); EXPECT_EQ( 2u, bindex.num_blobs() );
} }

TEST(BlobIndexThreaded, BlobCompressedIntersect) {
std::vector<std::list<int32> > starts, ends;
starts += list_of(0), list_of(0), list_of(0), list_of(0), list_of(0);
ends += list_of(5), list_of(1), list_of(1), list_of(1), list_of(1);
blob::BlobCompressed test_blob( Vector2i(5,5), starts, ends );

test_blob.print();

EXPECT_FALSE( test_blob.intersects( BBox2i(6,6,2,2) ) );
EXPECT_FALSE( test_blob.intersects( BBox2i(4,4,1,1) ) );
EXPECT_FALSE( test_blob.intersects( BBox2i(6,4,3,1) ) );
EXPECT_FALSE( test_blob.intersects( BBox2i(3,5,2,8) ) );
EXPECT_TRUE( test_blob.intersects( BBox2i(6,2,4,10) ) );
EXPECT_TRUE( test_blob.intersects( BBox2i(3,4,6,2) ) );
EXPECT_TRUE( test_blob.intersects( BBox2i(4,7,2,2) ) );
}

0 comments on commit 0811ed7

Please sign in to comment.