blob: ef9cc198a3bcd03f81325f097776e607951b94a1 [file] [log] [blame]
Parker Schuh6691f192017-01-14 17:01:02 -08001#include "aos/vision/blob/range_image.h"
2
Stephan Pleinescc500b92024-05-30 10:58:40 -07003#include <stdio.h>
4
Parker Schuh6691f192017-01-14 17:01:02 -08005#include <algorithm>
Stephan Pleinescc500b92024-05-30 10:58:40 -07006#include <ostream>
Parker Schuh6691f192017-01-14 17:01:02 -08007
Stephan Pleinesf63bde82024-01-13 15:59:33 -08008namespace aos::vision {
Brian Silverman93897f32019-03-10 16:19:19 -07009namespace {
Parker Schuh6691f192017-01-14 17:01:02 -080010
Brian Silverman93897f32019-03-10 16:19:19 -070011// Merge sort of multiple range images into a single range image.
12// They must not overlap.
Parker Schuh6691f192017-01-14 17:01:02 -080013RangeImage MergeRangeImage(const BlobList &blobl) {
14 if (blobl.size() == 1) return blobl[0];
15
16 int min_y = blobl[0].min_y();
17 for (const RangeImage &subrimg : blobl) {
18 if (min_y > subrimg.min_y()) min_y = subrimg.min_y();
19 }
20 std::vector<std::vector<ImageRange>> ranges;
21 int i = min_y;
22 while (true) {
23 std::vector<ImageRange> range_lst;
24 int n_missing = 0;
25 for (const RangeImage &subrimg : blobl) {
26 if (subrimg.min_y() > i) continue;
27 int ri = i - subrimg.min_y();
28 if (ri < (int)subrimg.ranges().size()) {
29 for (const auto &span : subrimg.ranges()[ri]) {
30 range_lst.emplace_back(span);
31 }
32 } else {
33 ++n_missing;
34 }
35 }
36 std::sort(range_lst.begin(), range_lst.end());
37 ranges.emplace_back(std::move(range_lst));
38 if (n_missing == static_cast<int>(blobl.size()))
39 return RangeImage(min_y, std::move(ranges));
40 ++i;
41 }
42}
43
Brian Silverman93897f32019-03-10 16:19:19 -070044} // namespace
45
Parker Schuh6691f192017-01-14 17:01:02 -080046std::string ShortDebugPrint(const BlobList &blobl) {
47 RangeImage rimg = MergeRangeImage(blobl);
48 std::string out;
49 out += "{";
50 out += "min_y: " + std::to_string(rimg.min_y());
51 for (const auto &line : rimg) {
52 out += "{";
53 for (const auto &span : line) {
54 out +=
55 "{" + std::to_string(span.st) + ", " + std::to_string(span.ed) + "},";
56 }
57 out += "},";
58 }
59 out += "}";
60 return out;
61}
62
63void DebugPrint(const BlobList &blobl) {
64 RangeImage rimg = MergeRangeImage(blobl);
65 int minx = rimg.ranges()[0][0].st;
66 int maxx = 0;
Austin Schuh335eef12019-03-02 17:04:17 -080067 for (const std::vector<ImageRange> &range : rimg.ranges()) {
68 for (const ImageRange &span : range) {
Parker Schuh6691f192017-01-14 17:01:02 -080069 if (span.st < minx) minx = span.st;
70 if (span.ed > maxx) maxx = span.ed;
71 }
72 }
Parker Schuh309dd722017-02-25 11:31:18 -080073 printf("maxx: %d minx: %d\n", maxx, minx);
Parker Schuh6691f192017-01-14 17:01:02 -080074 char buf[maxx - minx];
Austin Schuh335eef12019-03-02 17:04:17 -080075 for (const std::vector<ImageRange> &range : rimg.ranges()) {
Parker Schuh6691f192017-01-14 17:01:02 -080076 int i = minx;
Austin Schuh335eef12019-03-02 17:04:17 -080077 for (const ImageRange &span : range) {
Parker Schuh6691f192017-01-14 17:01:02 -080078 for (; i < span.st; ++i) buf[i - minx] = ' ';
79 for (; i < span.ed; ++i) buf[i - minx] = '#';
80 }
81 for (; i < maxx; ++i) buf[i - minx] = ' ';
Parker Schuh309dd722017-02-25 11:31:18 -080082 printf("%.*s\n", maxx - minx, buf);
Parker Schuh6691f192017-01-14 17:01:02 -080083 }
84}
85
Brian Silverman5eec8b92019-03-10 15:14:31 -070086void PrintTo(const ImageRange &range, std::ostream *os) {
87 *os << "{" << range.st << ", " << range.ed << "}";
88}
89
Parker Schuh6691f192017-01-14 17:01:02 -080090void RangeImage::Flip(int image_width, int image_height) {
91 std::reverse(ranges_.begin(), ranges_.end());
92 for (std::vector<ImageRange> &range : ranges_) {
93 std::reverse(range.begin(), range.end());
94 for (ImageRange &interval : range) {
95 int tmp = image_width - interval.ed;
96 interval.ed = image_width - interval.st;
97 interval.st = tmp;
98 }
99 }
100
101 min_y_ = image_height - static_cast<int>(ranges_.size()) - min_y_;
102}
103
Brian Silverman5eec8b92019-03-10 15:14:31 -0700104void PrintTo(const RangeImage &range, std::ostream *os) {
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700105 *os << "{min_y=" << range.min_y() << ", ranges={";
Brian Silverman5eec8b92019-03-10 15:14:31 -0700106 bool first_row = true;
107 for (const auto &row : range) {
108 if (first_row) {
109 first_row = false;
110 } else {
111 *os << ", ";
112 }
113 *os << "{";
114 bool first_value = true;
115 for (const auto &value : row) {
116 if (first_value) {
117 first_value = false;
118 } else {
119 *os << ", ";
120 }
121 *os << "{" << value.st << ", " << value.ed << "}";
122 }
123 *os << "}";
124 }
125 *os << "}}";
126}
127
Parker Schuh6691f192017-01-14 17:01:02 -0800128int RangeImage::npixels() {
129 if (npixelsc_ > 0) {
130 return npixelsc_;
131 }
132 npixelsc_ = calc_area();
133 return npixelsc_;
134}
135
136int RangeImage::calc_area() const {
137 int area = 0;
138 for (auto &range : ranges_) {
139 for (auto &interval : range) {
140 area += interval.calc_width();
141 }
142 }
143 return area;
144}
145
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800146} // namespace aos::vision