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
protected:
std::vector<data_type> mData;
std::vector<int> mBit;
std::vector<int> mComponent;
std::vector<short> mBit;
size_t mRows;
size_t mColumns;
......@@ -51,8 +50,8 @@ class MarchingSquares
*/
void step(size_t r, size_t c);
bool accepts(size_t r, size_t c) const;
void find_components();
void dfs(int x, int y, size_t current_label);
void clear_connected_component(int row, int col, size_t label,
data_type wash_bit);
public:
/**
......
#include <array>
#include <unordered_set>
#include <set>
#include <vector>
#include "radixalgorithm/marchingsquares.hh"
......@@ -9,36 +8,45 @@
namespace radix
{
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 (y < 0 || y == mRows) return; // out of bounds
size_t c_i = mColumns * y + x;
if (mComponent[c_i] || !mBit[c_i])
return; // already labeled or not marked with 1 in m
// mark the current cell
mComponent[c_i] = current_label;
// recursively mark the neighbors
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)
if (row < 0 || row == mColumns) return; // out of bounds
if (col < 0 || col == mRows) return; // out of bounds
std::set<size_t> list;
list.insert(mColumns * row + col);
while (!list.empty())
{
// save the row
size_t y = c_i / mColumns;
// save the column
size_t x = c_i % mColumns;
// check if it is already labeled
if (!mComponent[c_i] && mBit[c_i]) dfs(x, y, ++component);
const auto& it = list.begin();
size_t c_i = *it;
// 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)
{
size_t nc = col + dx[direction];
size_t nr = row + dy[direction];
if (nc < 0 || nc == mColumns) continue; // out of bounds
if (nr < 0 || nr == mRows) continue; // out of bounds
size_t nc_i = mColumns * nr + nc;
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(
{
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
size_t row = start.first, column = start.second;
radix_tagged_line("Starting (" << row << ", " << column << ")");
do
{
step(row, column);
// If our current point is within our image
// 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});
}
switch (next_step)
{
......@@ -121,19 +121,10 @@ std::vector<std::pair<int, int>> MarchingSquares<data_type>::march(
}
} while (row != start.first || column != start.second);
//
// Now we need to wash out selected group within contour, leaving those at or
// above threhold
// 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
clear_connected_component(start.first, start.second,
mBit[mColumns * start.first + start.second],
wash_bit);
return out;
} // march
......@@ -186,8 +177,8 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
if (u_left) state |= 1;
if (u_right) state |= 2;
if (l_left) state |= 4;
if (l_right) state |= 8;
if (l_right) state |= 4;
if (l_left) state |= 8;
// State now contains a number between 0 and 15
// representing our state.
// In binary, it looks like 0000-1111 (in binary)
......@@ -212,60 +203,67 @@ void MarchingSquares<data_type>::step(size_t r, size_t c)
switch (state)
{
case 1:
next_step = StepDirection::Up;
next_step = StepDirection::Left;
break;
case 2:
next_step = StepDirection::Right;
if (prev_step == StepDirection::Left)
next_step = StepDirection::Up;
else
next_step = StepDirection::Right;
break;
case 3:
next_step = StepDirection::Right;
next_step = StepDirection::Left;
break;
case 4:
next_step = StepDirection::Left;
next_step = StepDirection::Right;
break;
case 5:
next_step = StepDirection::Up;
break;
case 6:
if (prev_step == StepDirection::Up)
{
next_step = StepDirection::Left;
}
if (prev_step == StepDirection::Down)
next_step = StepDirection::Down;
else
{
next_step = StepDirection::Right;
}
next_step = StepDirection::Up;
break;
case 7:
next_step = StepDirection::Right;
if (prev_step == StepDirection::Up)
next_step = StepDirection::Left;
else
next_step = StepDirection::Down;
break;
case 8:
next_step = StepDirection::Down;
break;
case 9:
if (prev_step == StepDirection::Right)
{
next_step = StepDirection::Up;
}
else
{
if (prev_step == StepDirection::Down)
next_step = StepDirection::Down;
}
else
next_step = StepDirection::Up;
break;
case 10:
next_step = StepDirection::Down;
break;
case 11:
next_step = StepDirection::Down;
if (prev_step == StepDirection::Left)
next_step = StepDirection::Down;
else
next_step = StepDirection::Right;
break;
case 12:
next_step = StepDirection::Left;
next_step = StepDirection::Right;
break;
case 13:
next_step = StepDirection::Up;
if (prev_step == StepDirection::Down)
next_step = StepDirection::Right;
else
next_step == StepDirection::Up;
break;
case 14:
next_step = StepDirection::Left;
if (prev_step == StepDirection::Down)
next_step = StepDirection::Left;
else
next_step = StepDirection::Up;
break;
default:
next_step = StepDirection::None;
......@@ -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
......@@ -39,14 +39,14 @@ TEST(MarchingSquares, Simple)
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4},
{3, 4}, {2, 4}, {1, 4}, {1, 3}};
{1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{5, 2}, {4, 2}, {3, 2}, {2, 2}};
ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -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_blessed{
{1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2}, {8, 2},
{8, 3}, {8, 4}, {8, 5}, {8, 6}, {8, 7}, {8, 8}, {8, 9}, {8, 10},
{8, 11}, {8, 12}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {5, 12}, {5, 11},
{4, 11}, {4, 10}, {4, 9}, {3, 9}, {3, 8}, {3, 7}, {2, 7}, {2, 6},
{2, 5}, {3, 5}, {3, 6}, {4, 6}, {4, 7}, {4, 8}, {5, 8}, {5, 9},
{5, 10}, {6, 10}, {6, 11}, {7, 11}, {7, 10}, {7, 9}, {7, 8}, {7, 7},
{7, 6}, {7, 5}, {7, 4}, {7, 3}, {6, 3}, {5, 3}, {4, 3}, {4, 4},
{3, 4}, {2, 4}, {1, 4}, {1, 3}};
{1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4}, {4, 4}, {4, 3}, {5, 3},
{6, 3}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9},
{7, 10}, {7, 11}, {6, 11}, {6, 10}, {5, 10}, {5, 9}, {5, 8}, {4, 8},
{4, 7}, {4, 6}, {3, 6}, {3, 5}, {2, 5}, {2, 6}, {2, 7}, {3, 7},
{3, 8}, {3, 9}, {4, 9}, {4, 10}, {4, 11}, {5, 11}, {5, 12}, {5, 13},
{6, 13}, {7, 13}, {8, 13}, {8, 12}, {8, 11}, {8, 10}, {8, 9}, {8, 8},
{8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {7, 2}, {6, 2},
{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());
for (size_t i = 0; i < first_blessed.size(); ++i)
{
......@@ -95,7 +106,7 @@ TEST(MarchingSquares, TwoGroups)
{ // get the second grouping
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;
// for (size_t i = 0; i < second_contour.size(); ++i)
// {
......@@ -109,7 +120,7 @@ TEST(MarchingSquares, TwoGroups)
// }
// std::cout << "}" << std::endl;
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());
for (size_t i = 0; i < second_blessed.size(); ++i)
{
......@@ -141,7 +152,6 @@ TEST(MarchingSquares, 4EdgeGroups)
{
std::vector<std::pair<int, int>> contour = ms.march(2., 0., 3.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i)
// {
......@@ -155,8 +165,8 @@ TEST(MarchingSquares, 4EdgeGroups)
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{
{2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {8, 1},
{8, 2}, {7, 2}, {6, 2}, {5, 2}, {4, 2}, {3, 2}, {2, 2}, {2, 1}};
{2, 0}, {2, 1}, {2, 2}, {3, 2}, {4, 2}, {5, 2}, {6, 2}, {7, 2},
{8, 2}, {8, 1}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}};
ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -168,7 +178,6 @@ TEST(MarchingSquares, 4EdgeGroups)
}
{
std::vector<std::pair<int, int>> contour = ms.march(3., 0., 4.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i)
// {
......@@ -181,9 +190,10 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl;
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{6, 6}, {7, 6}, {8, 6}, {9, 6},
{9, 5}, {9, 4}, {9, 3}, {9, 8},
{8, 8}, {7, 8}, {6, 8}, {6, 7}};
std::vector<std::pair<int, int>> blessed{
{6, 6}, {6, 7}, {6, 8}, {7, 8}, {8, 8}, {9, 8},
{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());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -195,7 +205,6 @@ TEST(MarchingSquares, 4EdgeGroups)
}
{
std::vector<std::pair<int, int>> contour = ms.march(4., 0., 5.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i)
// {
......@@ -209,8 +218,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{
{4, 18}, {5, 18}, {5, 17}, {6, 17}, {7, 17}, {8, 17}, {8, 18},
{9, 18}, {9, 19}, {8, 19}, {7, 19}, {6, 19}, {4, 19}};
{4, 18}, {4, 19}, {4, 20}, {5, 20}, {6, 20}, {6, 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());
for (size_t i = 0; i < blessed.size(); ++i)
......@@ -222,7 +232,6 @@ TEST(MarchingSquares, 4EdgeGroups)
}
{
std::vector<std::pair<int, int>> contour = ms.march(5.);
// ms.dump_component_map(std::cout);
// std::cout << "{" << std::endl;
// for (size_t i = 0; i < contour.size(); ++i)
// {
......@@ -235,9 +244,9 @@ TEST(MarchingSquares, 4EdgeGroups)
// std::cout << std::endl;
// }
// std::cout << "}" << std::endl;
std::vector<std::pair<int, int>> blessed{{0, 14}, {1, 14}, {2, 14}, {2, 15},
{2, 16}, {2, 17}, {1, 17}, {0, 17},
{0, 16}, {0, 15}};
std::vector<std::pair<int, int>> blessed{{0, 14}, {0, 15}, {0, 16}, {0, 17},
{1, 17}, {2, 17}, {2, 16}, {2, 15},
{2, 14}, {1, 14}};
ASSERT_EQ(blessed.size(), contour.size());
for (size_t i = 0; i < blessed.size(); ++i)
......
Supports Markdown
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