Img2Num C++ (Internal Developer Docs) dev
API Documentation
Loading...
Searching...
No Matches
node.cpp
1#include "internal/node.h"
2
3#include <climits>
4
5/*
6 Node class
7 */
8
9XY Node::centroid() const {
10 XY centroid{0, 0};
11 const int32_t m_pixels_size{static_cast<int32_t>(m_pixels->size())};
12
13 // Guard against division by zero after loop
14 if (m_pixels_size == 0) {
15 return centroid;
16 }
17
18 for (auto &[_, pos] : *m_pixels) {
19 centroid.x += pos.x;
20 centroid.y += pos.y;
21 }
22
23 centroid.x /= m_pixels_size;
24 centroid.y /= m_pixels_size;
25
26 return centroid;
27}
28
29ImageLib::RGBPixel<uint8_t> Node::color() const {
30 const int32_t m_pixels_size{static_cast<int32_t>(m_pixels->size())};
31
32 // Guard against division by zero after loop
33 if (m_pixels_size == 0) {
34 return {0, 0, 0};
35 }
36
37 float r{0};
38 float g{0};
39 float b{0};
40 for (auto &[color, _] : *m_pixels) {
41 r += color.red;
42 g += color.green;
43 b += color.blue;
44 }
45
46 r /= m_pixels_size;
47 g /= m_pixels_size;
48 b /= m_pixels_size;
49
50 // Accept lossy conversion - the difference is very minimal
51 return {static_cast<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(b)};
52}
53
54std::array<int32_t, 4> Node::bounding_box_xywh() const {
55 if (m_pixels->empty()) {
56 return {0, 0, 0, 0};
57 }
58
59 int32_t x_min{INT_MAX};
60 int32_t y_min{INT_MAX};
61 int32_t x_max{0};
62 int32_t y_max{0};
63 for (auto &[_, p] : *m_pixels) {
64 if (p.x < x_min) {
65 x_min = p.x;
66 }
67 if (p.x > x_max) {
68 x_max = p.x;
69 }
70 if (p.y < y_min) {
71 y_min = p.y;
72 }
73 if (p.y > y_max) {
74 y_max = p.y;
75 }
76 }
77
78 for (auto &p : m_edge_pixels) {
79 if (p.x < x_min) {
80 x_min = p.x;
81 }
82 if (p.x > x_max) {
83 x_max = p.x;
84 }
85 if (p.y < y_min) {
86 y_min = p.y;
87 }
88 if (p.y > y_max) {
89 y_max = p.y;
90 }
91 }
92
93 const int32_t w{x_max - x_min + 1};
94 const int32_t h{y_max - y_min + 1};
95
96 return std::array<int32_t, 4>{x_min, y_min, w, h};
97}
98
99std::array<int, 4> Node::create_binary_image(std::vector<uint8_t> &binary) const {
100 std::array<int, 4> xywh{bounding_box_xywh()};
101
102 binary.resize(static_cast<size_t>(xywh[2]) * static_cast<size_t>(xywh[3]), 0);
103
104 for (auto &[_, p] : *m_pixels) {
105 int32_t _x = p.x - xywh[0];
106 int32_t _y = p.y - xywh[1];
107 binary[_y * xywh[2] + _x] = 1;
108 }
109
110 // include the edge pixels to ensure contour overlap with neighbor
111 for (auto &p : m_edge_pixels) {
112 int32_t _x = p.x - xywh[0];
113 int32_t _y = p.y - xywh[1];
114 binary[_y * xywh[2] + _x] = 1;
115 }
116
117 return xywh;
118}
119
120void Node::clear_contour(void) {
121 m_contours.contours.clear();
122 m_contours.hierarchy.clear();
123 m_contours.is_hole.clear();
124 m_contours.colors.clear();
125 m_contours.curves.clear();
126}
127
128void Node::compute_contour(void) {
129 // return list of all contours present in Node.
130 // usually 1 sometimes more if holes are present
131
132 clear_contour();
133
134 std::vector<uint8_t> binary;
135 std::array<int, 4> xywh{create_binary_image(binary)};
136
137 int xmin = xywh[0];
138 int ymin = xywh[1];
139 int bw = xywh[2];
140 int bh = xywh[3];
141
142 ContoursResult contour_res = contours::find_contours(binary, bw, bh);
143
144 for (size_t cidx = 0; cidx < contour_res.contours.size(); ++cidx) {
145 auto &contour = contour_res.contours[cidx];
146 for (auto &p : contour) {
147 p.x += xmin;
148 p.y += ymin;
149 }
150
151 // if (contour_res.is_hole[cidx]) { continue; }
152
153 ImageLib::RGBPixel<uint8_t> _col = color();
154 ImageLib::RGBAPixel<uint8_t> col{_col.red, _col.green, _col.blue, 255};
155 m_contours.contours.push_back(contour);
156 m_contours.hierarchy.push_back(contour_res.hierarchy[cidx]);
157 m_contours.is_hole.push_back(contour_res.is_hole[cidx]);
158 m_contours.colors.push_back(col);
159 }
160
161 m_contours.curves.resize(m_contours.contours.size());
162}
163
164void Node::add_pixels(const std::vector<RGBXY> &new_pixels) {
165 for (auto &c : new_pixels) {
166 m_pixels->push_back(c);
167 }
168}
169
170void Node::add_edge_pixel(const XY edge_pixel) {
171 m_edge_pixels.insert(edge_pixel);
172}
173
174void Node::clear_edge_pixels() {
175 m_edge_pixels.clear();
176}
177
178void Node::clear_all() {
179 m_edges.clear();
180 m_pixels->clear();
181 m_edge_pixels.clear();
182}
Definition node.h:38