15 constexpr int32_t dx8[] = { 1, 1, 0, -1, -1, -1, 0, 1 };
16 constexpr int32_t dy8[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
71 std::span<const float> mask, uint32_t w, uint32_t
h,
78 std::vector<Contour> result(cc.count);
79 std::vector<uint8_t> valid(cc.count, 0);
81 P::for_each(P::par_unseq,
82 std::views::iota(uint32_t { 0 }, cc.count).begin(),
83 std::views::iota(uint32_t { 0 }, cc.count).end(),
85 const uint32_t lbl = ci + 1;
86 const auto& box = cc.boxes[ci];
88 const auto x0 =
static_cast<uint32_t
>(box.x *
static_cast<float>(w));
89 const auto y0 =
static_cast<uint32_t
>(box.y *
static_cast<float>(
h));
90 const auto x1 = std::min(x0 +
static_cast<uint32_t
>(box.w *
static_cast<float>(w)) - 1U, w - 1);
91 const auto y1 = std::min(y0 +
static_cast<uint32_t
>(box.h *
static_cast<float>(
h)) - 1U,
h - 1);
93 uint32_t start_x = 0, start_y = 0;
95 for (uint32_t py = y0; py <= y1 && !found; ++py) {
96 for (uint32_t px = x0; px <= x1 && !found; ++px) {
97 if (cc.label_map[
static_cast<size_t>(py) * w + px] == lbl) {
108 const uint32_t bw = x1 - x0 + 1;
109 const uint32_t bh = y1 - y0 + 1;
111 if (bw < 2 || bh < 2)
114 std::vector<uint8_t> visited(
static_cast<size_t>(bw) * bh, 0);
116 auto is_component_fg = [&](int32_t px, int32_t py) ->
bool {
118 ||
static_cast<uint32_t
>(px) >= w
119 ||
static_cast<uint32_t
>(py) >=
h)
121 return cc.label_map[
static_cast<size_t>(py) * w + px] == lbl;
124 auto mark_visited = [&](int32_t px, int32_t py) {
125 if (
static_cast<uint32_t
>(px) < x0 ||
static_cast<uint32_t
>(py) < y0
126 ||
static_cast<uint32_t
>(px) > x1 ||
static_cast<uint32_t
>(py) > y1)
128 const uint32_t lx =
static_cast<uint32_t
>(px) - x0;
129 const uint32_t ly =
static_cast<uint32_t
>(py) - y0;
130 visited[
static_cast<size_t>(ly) * bw + lx] = 1;
133 auto cx =
static_cast<int32_t
>(start_x);
134 auto cy =
static_cast<int32_t
>(start_y);
136 int32_t start_dir = 0;
137 for (int32_t d = 0; d < 8; ++d) {
138 const int32_t nx = cx + dx8[d];
139 const int32_t ny = cy + dy8[d];
140 if (!is_component_fg(nx, ny)) {
146 const int32_t orig_x = cx;
147 const int32_t orig_y = cy;
148 int32_t dir = start_dir;
150 std::vector<glm::vec2>
points;
153 bool step_found =
false;
154 for (int32_t i = 0; i < 8; ++i) {
155 const int32_t d = (dir + 6 + i) % 8;
156 const int32_t nx = cx + dx8[d];
157 const int32_t ny = cy + dy8[d];
159 if (!is_component_fg(nx, ny))
163 static_cast<float>(cx) /
static_cast<float>(w),
164 static_cast<float>(cy) /
static_cast<float>(
h));
165 mark_visited(cx, cy);
175 if (!first && cx == orig_x && cy == orig_y)
178 if (
points.size() >
static_cast<size_t>(w) *
h)
185 const float area = polygon_area(
points);
189 result[ci] = { .points = std::move(
points), .area = area, .perimeter = polygon_perimeter(
points) };
193 std::vector<Contour> out;
194 out.reserve(cc.count);
195 for (uint32_t i = 0; i < cc.count; ++i) {
197 out.push_back(std::move(result[i]));
201 std::partial_sort(out.begin(),
std::vector< Contour > find_contours(std::span< const float > mask, uint32_t w, uint32_t h, float min_area, uint32_t max_contours)
Extract outer contours from a binary mask.
void apply_contour_mask(std::span< float > pixels, uint32_t w, uint32_t h, uint32_t channels, const Contour &contour, float origin_x, float origin_y, float scale_x, float scale_y)
Zero all pixels in pixels that fall outside contour.