Skip to content
Browse files

Core: Use a more exhaustive intersect

Instead of just intersecting the bounding bboxes, intersect the actual
shapes.
  • Loading branch information...
1 parent ac36bcd commit 0811ed7a279396332881bdc084415602a3f75b5b Zack Moratto committed
View
75 src/asp/Core/BlobIndexThreaded.cc
@@ -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 sum = 0;
for ( uint32 r = 0; r < m_row_end.size(); r++ )
@@ -76,6 +90,26 @@ BBox2i BlobCompressed::bounding_box() const {
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 {
int32 y_offset = m_min.y()-right.min().y()-1;
// Starting r_i on the index above
@@ -84,15 +118,15 @@ bool BlobCompressed::is_on_right( BlobCompressed const& right ) const {
i++, r_i++ ) {
if ( r_i >= 0 && r_i < int32(right.num_rows()) )
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;
if ( r_i+1 >= 0 && r_i+1 < int32(right.num_rows()) )
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;
if ( r_i+2 >= 0 && r_i+2 < int32(right.num_rows()) )
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 false;
@@ -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(),
top_end = m_row_end.back().begin(); top_start != m_row_start.back().end();
top_start++, top_end++ )
- for ( std::list<int32>::const_iterator bot_start = bottom.start(0).begin(),
- bot_end = bottom.end(0).begin(); bot_start != bottom.start(0).end();
+ for ( std::list<int32>::const_iterator bot_start = bottom.m_row_start[0].begin(),
+ bot_end = bottom.m_row_end[0].begin(); bot_start != bottom.m_row_start[0].end();
bot_start++, bot_end++ ) {
if ( (*top_end+m_min.x() >= *bot_start + bottom.min().x()) &&
(*top_start+m_min.x() <= *bot_end+bottom.min().x()) )
@@ -156,8 +190,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
if ( m_row_start.empty() ) {
m_min = victim.min();
for ( int i = 0; i < victim.num_rows(); i++ ) {
- m_row_start.push_back( victim.start(i) );
- m_row_end.push_back( victim.end(i) );
+ m_row_start.push_back( victim.m_row_start[i] );
+ m_row_end.push_back( victim.m_row_end[i] );
}
return;
}
@@ -174,8 +208,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
// Inserting victim's connected rows in singletons at a time
// become sometimes they connect like zippers.
- for ( std::list<int32>::const_iterator v_singleton_start = victim.start(i).begin(),
- v_singleton_end = victim.end(i).begin(); v_singleton_start != victim.start(i).end();
+ for ( std::list<int32>::const_iterator v_singleton_start = victim.m_row_start[i].begin(),
+ v_singleton_end = victim.m_row_end[i].begin(); v_singleton_start != victim.m_row_start[i].end();
v_singleton_start++, v_singleton_end++ ) {
std::list<int32>::iterator start_insertion_point = m_row_start[m_index].begin(),
@@ -249,8 +283,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
std::vector<std::list<int32> > temp_end;
for ( int v_i = 0; v_i < m_min.y()-victim.min().y(); v_i++ ) {
if ( v_i < victim.num_rows() ) {
- temp_start.push_back(victim.start(v_i));
- temp_end.push_back(victim.end(v_i));
+ temp_start.push_back(victim.m_row_start[v_i]);
+ temp_end.push_back(victim.m_row_end[v_i]);
for ( std::list<int32>::iterator i_start = temp_start.back().begin(),
i_stop = temp_end.back().begin();
i_start != temp_start.back().end(); i_start++, i_stop++ ) {
@@ -285,8 +319,8 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
temp_start.push_back(std::list<int32>());
temp_end.push_back(std::list<int32>());
} else {
- temp_start.push_back( victim.start(v_i) );
- temp_end.push_back( victim.end(v_i) );
+ temp_start.push_back( victim.m_row_start[v_i] );
+ temp_end.push_back( victim.m_row_end[v_i] );
for ( std::list<int32>::iterator i_start = temp_start.back().begin(),
i_stop = temp_end.back().begin();
i_start != temp_start.back().end(); i_start++, i_stop++ ) {
@@ -303,14 +337,14 @@ void BlobCompressed::absorb( BlobCompressed const& victim ) {
temp_end.end() );
}
// Recalculate min.x()
- int32 valid_first = 0;
+ size_t valid_first = 0;
while ( valid_first < m_row_start.size() ) {
if ( m_row_start[valid_first].size() )
break;
valid_first++;
}
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 )
lowest_value = m_row_start[i].front();
}
@@ -328,6 +362,17 @@ void BlobCompressed::decompress( std::list<Vector2i>& output ) const {
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 {
std::deque<BlobCompressed> &m_src_c_blob, &m_dest_c_blob;
View
48 src/asp/Core/BlobIndexThreaded.h
@@ -60,16 +60,8 @@ namespace blob {
public:
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() { m_min = vw::Vector2i(-1,-1); }
+ std::vector<std::list<vw::int32> > const& row_end );
+ BlobCompressed();
// Standard Access point
vw::Vector2i const& min() const { return m_min; }
@@ -79,8 +71,9 @@ namespace blob {
std::list<vw::int32> const& end( vw::uint32 const& index ) const { return m_row_end[index]; }
vw::int32 size() const; // Please use sparingly
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_bottom( BlobCompressed const& bottom ) const;
@@ -88,20 +81,10 @@ namespace blob {
void add_row( vw::Vector2i const& start, int const& width );
// Use to expand this blob into a non overlapped area
void absorb( BlobCompressed const& victim );
- // Dump into stupid format
+ // Dump listing of every pixel used
void decompress( std::list<vw::Vector2i>& output ) 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";
- }
- }
+ // Print internal data
+ void print() const;
};
// Blob Index Custom
@@ -295,11 +278,7 @@ namespace blob {
/////////////////////////////////////
// A task wrapper to allow threading
template <class SourceT>
- class BlobIndexTask : public vw::Task {
- // Disable copy !!
- BlobIndexTask(BlobIndexTask& copy){}
- void operator=(BlobIndexTask& copy) {}
-
+ class BlobIndexTask : public vw::Task, private boost::noncopyable {
vw::ImageViewBase<SourceT> const& m_view;
vw::BBox2i const& m_bbox;
vw::Mutex& m_append_mutex;
@@ -380,9 +359,8 @@ class BlobIndexThreaded {
vw::FifoWorkQueue queue(vw::vw_settings().default_num_threads());
typedef blob::BlobIndexTask<SourceT> task_type;
- std::vector<vw::BBox2i> bboxes = image_blocks( src.impl(),
- m_tile_size,
- m_tile_size );
+ std::vector<vw::BBox2i> bboxes =
+ image_blocks( src.impl(), m_tile_size, m_tile_size );
for ( size_t i = 0; i < bboxes.size(); ++i ) {
boost::shared_ptr<task_type> task(new task_type(src, bboxes[i], m_insert_mutex,
m_c_blob, m_blob_bbox,
@@ -399,13 +377,15 @@ class BlobIndexThreaded {
vw::Vector2i( m_tile_size, m_tile_size ) );
// 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();
- iter != m_c_blob.end(); iter++ )
+ iter != m_c_blob.end(); iter++ ) {
if ( iter->size() > m_max_area ) {
iter = m_c_blob.erase( iter );
iter--;
}
+ }
+ }
}
// Access for the users
View
10 src/asp/Core/InpaintView.h
@@ -190,11 +190,11 @@ namespace asp {
std::vector<size_t> intersections;
intersections.reserve(20);
BBox2i bbox_expanded = bbox;
- for ( BlobIndexThreaded::const_bbox_iterator bbox_it = m_bindex.bbox_begin();
- bbox_it != m_bindex.bbox_end(); bbox_it++ ) {
- if ( bbox_it->intersects( bbox ) ) {
- bbox_expanded.grow( *bbox_it );
- intersections.push_back( bbox_it - m_bindex.bbox_begin() );
+ for ( size_t i = 0; i < m_bindex.num_blobs(); i++ ) {
+ if ( m_bindex.blob_bbox(i).intersects( bbox ) && // Early exit option
+ m_bindex.compressed_blob(i).intersects( bbox ) ) {
+ bbox_expanded.grow( m_bindex.blob_bbox(i) );
+ intersections.push_back(i);
}
}
bbox_expanded.expand(1);
View
20 src/asp/Core/tests/TestBlobIndexThreaded.cxx
@@ -21,8 +21,11 @@
#include <vw/FileIO.h>
#include <vw/Image.h>
#include <asp/Core/BlobIndexThreaded.h>
+#include <boost/assign/std/vector.hpp>
+#include <boost/assign/list_of.hpp>
using namespace vw;
+using namespace boost::assign;
TEST(BlobIndexThreaded, TestImage1) {
DiskImageView<PixelGray<uint8> > input("ThreadTest1.tif");
@@ -44,3 +47,20 @@ TEST(BlobIndexThreaded, TestImage3) {
BlobIndexThreaded bindex( create_mask(input,255), 1000, 5 );
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.
Something went wrong with that request. Please try again.