Commit 2f73167c authored by LEFEBVREJP email's avatar LEFEBVREJP email
Browse files

Merge branch '19-iterative-ccl' into 'master'

Resolve "iterative ccl"

Closes #19

See merge request !39
parents 8b4804f4 3d1a88c5
Pipeline #13802 passed with stages
in 25 minutes and 21 seconds
...@@ -21,8 +21,7 @@ class MarchingSquares ...@@ -21,8 +21,7 @@ class MarchingSquares
protected: protected:
std::vector<data_type> mData; std::vector<data_type> mData;
std::vector<int> mBit; std::vector<short> mBit;
std::vector<int> mComponent;
size_t mRows; size_t mRows;
size_t mColumns; size_t mColumns;
...@@ -51,8 +50,8 @@ class MarchingSquares ...@@ -51,8 +50,8 @@ class MarchingSquares
*/ */
void step(size_t r, size_t c); void step(size_t r, size_t c);
bool accepts(size_t r, size_t c) const; bool accepts(size_t r, size_t c) const;
void find_components(); void clear_connected_component(int row, int col, size_t label,
void dfs(int x, int y, size_t current_label); data_type wash_bit);
public: public:
/** /**
......
#include <array> #include <set>
#include <unordered_set>
#include <vector> #include <vector>
#include "radixalgorithm/marchingsquares.hh" #include "radixalgorithm/marchingsquares.hh"
...@@ -9,36 +8,45 @@ ...@@ -9,36 +8,45 @@
namespace radix namespace radix
{ {
template <typename data_type> template <typename data_type>
void MarchingSquares<data_type>::dfs(int x, int y, size_t current_label) void MarchingSquares<data_type>::clear_connected_component(int row, int col,
size_t label,
data_type wash_bit)
{ {
if (x < 0 || x == mColumns) return; // out of bounds if (row < 0 || row == mColumns) return; // out of bounds
if (y < 0 || y == mRows) return; // out of bounds if (col < 0 || col == mRows) return; // out of bounds
size_t c_i = mColumns * y + x; std::set<size_t> list;
list.insert(mColumns * row + col);
if (mComponent[c_i] || !mBit[c_i]) while (!list.empty())
return; // already labeled or not marked with 1 in m {
const auto& it = list.begin();
// mark the current cell size_t c_i = *it;
mComponent[c_i] = current_label;
// recursively mark the neighbors // update the row
row = c_i / mColumns;
// upate the column
col = c_i % mColumns;
// clear data
mBit[c_i] = 0;
mData[c_i] = wash_bit;
// search neighbors
for (int direction = 0; direction < 4; ++direction) for (int direction = 0; direction < 4; ++direction)
dfs(x + dx[direction], y + dy[direction], current_label);
}
template <typename data_type>
void MarchingSquares<data_type>::find_components()
{
mComponent.resize(mBit.size(), 0);
size_t component = 0;
for (size_t c_i = 0; c_i < mComponent.size(); ++c_i)
{ {
// save the row size_t nc = col + dx[direction];
size_t y = c_i / mColumns; size_t nr = row + dy[direction];
// save the column if (nc < 0 || nc == mColumns) continue; // out of bounds
size_t x = c_i % mColumns; if (nr < 0 || nr == mRows) continue; // out of bounds
// check if it is already labeled size_t nc_i = mColumns * nr + nc;
if (!mComponent[c_i] && mBit[c_i]) dfs(x, y, ++component); if (mBit[nc_i] == label)
{
// if we already have this cell in the list to look at
// don't add it again
if (list.find(nc_i) == list.end())
{
list.insert(nc_i);
}
}
}
list.erase(it);
} }
} }
...@@ -74,33 +82,25 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march( ...@@ -74,33 +82,25 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
{ {
mBit[p_i] = 2; mBit[p_i] = 2;
} }
else
{
mBit[p_i] = 0;
}
} }
//
// connected component labeling is required for multiple groups
if (mComponent.empty()) find_components();
size_t group_i = mColumns * start.first + start.second;
radix_line("Starting point is a member of component(" << mComponent[group_i]
<< ")");
std::cerr << std::endl;
radix_block(
std::unordered_set<int> groups(mComponent.begin(), mComponent.end()));
radix_tagged_line("Number of groups(" << groups.size() << ")");
// //
// Walk the perimeter // Walk the perimeter
size_t row = start.first, column = start.second; size_t row = start.first, column = start.second;
radix_tagged_line("Starting (" << row << ", " << column << ")");
do do
{ {
step(row, column); step(row, column);
// If our current point is within our image // If our current point is within our image
// add it to the list of points // add it to the list of points
if (column >= 0 && column < mColumns && row >= 0 && row < mRows) // We have to allow for row and column being equal to the number
// of rows and columns to allow for traveling the boundaries
if (column >= 0 && column <= mColumns && row >= 0 && row <= mRows)
{
radix_tagged_line("(" << row << ", " << column
<< ") =" << int(next_step));
out.push_back({row, column}); out.push_back({row, column});
}
switch (next_step) switch (next_step)
{ {
...@@ -121,19 +121,10 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march( ...@@ -121,19 +121,10 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
} }
} while (row != start.first || column != start.second); } while (row != start.first || column != start.second);
// clear_connected_component(start.first, start.second,
// Now we need to wash out selected group within contour, leaving those at or mBit[mColumns * start.first + start.second],
// above threhold wash_bit);
// Get the group the starting point is a member of
for (size_t i = 0; i < mData.size(); ++i)
{
if (mComponent[i] == mComponent[group_i])
{
mData[i] = wash_bit;
}
}
//
// TODO: Simply polygon being returned with Ramer-Douglas-Peuker algorithm
return out; return out;
} // march } // march
...@@ -186,8 +177,8 @@ void MarchingSquares<data_type>::step(size_t r, size_t c) ...@@ -186,8 +177,8 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
if (u_left) state |= 1; if (u_left) state |= 1;
if (u_right) state |= 2; if (u_right) state |= 2;
if (l_left) state |= 4; if (l_right) state |= 4;
if (l_right) state |= 8; if (l_left) state |= 8;
// State now contains a number between 0 and 15 // State now contains a number between 0 and 15
// representing our state. // representing our state.
// In binary, it looks like 0000-1111 (in binary) // In binary, it looks like 0000-1111 (in binary)
...@@ -212,60 +203,67 @@ void MarchingSquares<data_type>::step(size_t r, size_t c) ...@@ -212,60 +203,67 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
switch (state) switch (state)
{ {
case 1: case 1:
next_step = StepDirection::Up; next_step = StepDirection::Left;
break; break;
case 2: case 2:
if (prev_step == StepDirection::Left)
next_step = StepDirection::Up;
else
next_step = StepDirection::Right; next_step = StepDirection::Right;
break; break;
case 3: case 3:
next_step = StepDirection::Right; next_step = StepDirection::Left;
break; break;
case 4: case 4:
next_step = StepDirection::Left; next_step = StepDirection::Right;
break; break;
case 5: case 5:
next_step = StepDirection::Up; next_step = StepDirection::Up;
break; break;
case 6: case 6:
if (prev_step == StepDirection::Up) if (prev_step == StepDirection::Down)
{ next_step = StepDirection::Down;
next_step = StepDirection::Left;
}
else else
{ next_step = StepDirection::Up;
next_step = StepDirection::Right;
}
break; break;
case 7: case 7:
next_step = StepDirection::Right; if (prev_step == StepDirection::Up)
next_step = StepDirection::Left;
else
next_step = StepDirection::Down;
break; break;
case 8: case 8:
next_step = StepDirection::Down; next_step = StepDirection::Down;
break; break;
case 9: case 9:
if (prev_step == StepDirection::Right) if (prev_step == StepDirection::Down)
{
next_step = StepDirection::Up;
}
else
{
next_step = StepDirection::Down; next_step = StepDirection::Down;
} else
next_step = StepDirection::Up;
break; break;
case 10: case 10:
next_step = StepDirection::Down; next_step = StepDirection::Down;
break; break;
case 11: case 11:
if (prev_step == StepDirection::Left)
next_step = StepDirection::Down; next_step = StepDirection::Down;
else
next_step = StepDirection::Right;
break; break;
case 12: case 12:
next_step = StepDirection::Left; next_step = StepDirection::Right;
break; break;
case 13: case 13:
next_step = StepDirection::Up; if (prev_step == StepDirection::Down)
next_step = StepDirection::Right;
else
next_step == StepDirection::Up;
break; break;
case 14: case 14:
if (prev_step == StepDirection::Down)
next_step = StepDirection::Left; next_step = StepDirection::Left;
else
next_step = StepDirection::Up;
break; break;
default: default:
next_step = StepDirection::None; next_step = StepDirection::None;
...@@ -273,14 +271,4 @@ void MarchingSquares<data_type>::step(size_t r, size_t c) ...@@ -273,14 +271,4 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
} }
} }
template <typename data_type>
void MarchingSquares<data_type>::dump_component_map(std::ostream& os) const
{
for (size_t i = 0; i < mComponent.size(); ++i)
{
os << std::setw(4) << mComponent[i] << ", ";
if (((i + 1) % mColumns) == 0) os << std::endl;
}
os << std::endl;
}
} // namespace radix } // namespace radix
...@@ -39,14 +39,14 @@ TEST(MarchingSquares, Simple) ...@@ -39,14 +39,14 @@ TEST(MarchingSquares, Simple)
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{ std::vector<std::pair<int, int>> blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2}, {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10}, {6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11}, {7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6}, {4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9}, {3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7}, {6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4}, {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{3, 4}, {2, 4}, {1, 4}, {1, 3}}; {5, 2}, {4, 2}, {3, 2}, {2, 2}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -77,15 +77,26 @@ TEST(MarchingSquares, TwoGroups) ...@@ -77,15 +77,26 @@ TEST(MarchingSquares, TwoGroups)
std::vector<std::pair<int, int>> first_contour = ms.march(2.); std::vector<std::pair<int, int>> first_contour = ms.march(2.);
std::vector<std::pair<int, int>> first_blessed{ std::vector<std::pair<int, int>> first_blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2}, {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10}, {6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11}, {7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6}, {4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9}, {3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7}, {6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4}, {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{3, 4}, {2, 4}, {1, 4}, {1, 3}}; {5, 2}, {4, 2}, {3, 2}, {2, 2}};
// std::cout << "{" << std::endl;
// for (size_t i = 0; i < first_contour.size(); ++i)
// {
// const auto& pixel = first_contour[i];
// std::cout << "{" << pixel.first << "," << pixel.second << "}";
// if (i != first_contour.size() - 1)
// {
// std::cout << ",";
// }
// std::cout << std::endl;
// }
// std::cout << "}" << std::endl;
ASSERT_EQ(first_blessed.size(), first_contour.size()); ASSERT_EQ(first_blessed.size(), first_contour.size());
for (size_t i = 0; i < first_blessed.size(); ++i) for (size_t i = 0; i < first_blessed.size(); ++i)
{ {
...@@ -95,7 +106,7 @@ TEST(MarchingSquares, TwoGroups) ...@@ -95,7 +106,7 @@ TEST(MarchingSquares, TwoGroups)
{ // get the second grouping { // get the second grouping
std::vector<std::pair<int, int>> second_contour = ms.march(2.); std::vector<std::pair<int, int>> second_contour = ms.march(2.);
// std::cout << "[ row , col ]" << std::endl; std::cout << "[ row , col ]" << std::endl;
// std::cout << "{" << std::endl; // std::cout << "{" << std::endl;
// for (size_t i = 0; i < second_contour.size(); ++i) // for (size_t i = 0; i < second_contour.size(); ++i)
// { // {
...@@ -109,7 +120,7 @@ TEST(MarchingSquares, TwoGroups) ...@@ -109,7 +120,7 @@ TEST(MarchingSquares, TwoGroups)
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> second_blessed{ std::vector<std::pair<int, int>> second_blessed{
{7, 16}, {8, 16}, {9, 16}, {9, 17}, {9, 18}, {8, 18}, {7, 18}, {7, 17}}; {7, 16}, {7, 17}, {7, 18}, {8, 18}, {9, 18}, {9, 17}, {9, 16}, {8, 16}};
ASSERT_EQ(second_blessed.size(), second_contour.size()); ASSERT_EQ(second_blessed.size(), second_contour.size());
for (size_t i = 0; i < second_blessed.size(); ++i) for (size_t i = 0; i < second_blessed.size(); ++i)
{ {
...@@ -141,7 +152,6 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -141,7 +152,6 @@ TEST(MarchingSquares, 4EdgeGroups)
{ {
std::vector<std::pair<int, int>> contour = ms.march(2., 0., 3.); std::vector<std::pair<int, int>> contour = ms.march(2., 0., 3.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl; // std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i) // for (size_t i = 0; i < contour.size(); ++i)
// { // {
...@@ -155,8 +165,8 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -155,8 +165,8 @@ TEST(MarchingSquares, 4EdgeGroups)
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{ std::vector<std::pair<int, int>> blessed{
{2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {8, 1}, {2, 0}, {2, 1}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2},
{8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {2, 1}}; {8, 2}, {8, 1}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -168,7 +178,6 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -168,7 +178,6 @@ TEST(MarchingSquares, 4EdgeGroups)
} }
{ {
std::vector<std::pair<int, int>> contour = ms.march(3., 0., 4.); std::vector<std::pair<int, int>> contour = ms.march(3., 0., 4.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl; // std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i) // for (size_t i = 0; i < contour.size(); ++i)
// { // {
...@@ -181,9 +190,10 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -181,9 +190,10 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl; // std::cout << std::endl;
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{6, 6}, {7, 6}, {8, 6}, {9, 6}, std::vector<std::pair<int, int>> blessed{
{9, 5}, {9, 4}, {9, 3}, {9, 8}, {6, 6}, {6, 7}, {6, 8}, {7, 8}, {8, 8}, {9, 8},
{8, 8}, {7, 8}, {6, 8}, {6, 7}}; {10, 8}, {10, 7}, {10, 6}, {10, 5}, {10, 4}, {10, 3},
{9, 3}, {9, 4}, {9, 5}, {9, 6}, {8, 6}, {7, 6}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -195,7 +205,6 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -195,7 +205,6 @@ TEST(MarchingSquares, 4EdgeGroups)
} }
{ {
std::vector<std::pair<int, int>> contour = ms.march(4., 0., 5.); std::vector<std::pair<int, int>> contour = ms.march(4., 0., 5.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl; // std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i) // for (size_t i = 0; i < contour.size(); ++i)
// { // {
...@@ -209,8 +218,9 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -209,8 +218,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{ std::vector<std::pair<int, int>> blessed{
{4, 18}, {5, 18}, {5, 17}, {6, 17}, {7, 17}, {8, 17}, {8, 18}, {4, 18}, {4, 19}, {4, 20}, {5, 20}, {6, 20}, {6, 19},
{9, 18}, {9, 19}, {8, 19}, {7, 19}, {6, 19}, {4, 19}}; {7, 19}, {8, 19}, {8, 20}, {9, 20}, {9, 19}, {9, 18},
{8, 18}, {8, 17}, {7, 17}, {6, 17}, {5, 17}, {5, 18}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
...@@ -222,7 +232,6 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -222,7 +232,6 @@ TEST(MarchingSquares, 4EdgeGroups)
} }
{ {
std::vector<std::pair<int, int>> contour = ms.march(5.); std::vector<std::pair<int, int>> contour = ms.march(5.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl; // std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i) // for (size_t i = 0; i < contour.size(); ++i)
// { // {
...@@ -235,9 +244,9 @@ TEST(MarchingSquares, 4EdgeGroups) ...@@ -235,9 +244,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl; // std::cout << std::endl;
// } // }
// std::cout << "}" << std::endl; // std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{0, 14}, {1, 14}, {2, 14}, {2, 15}, std::vector<std::pair<int, int>> blessed{{0, 14}, {0, 15}, {0, 16}, {0, 17},
{2, 16}, {2, 17}, {1, 17}, {0, 17}, {1, 17}, {2, 17}, {2, 16}, {2, 15},
{0, 16}, {0, 15}}; {2, 14}, {1, 14}};
ASSERT_EQ(blessed.size(), contour.size()); ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i) for (size_t i = 0; i < blessed.size(); ++i)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment