blob: 441a058169ce883370e268f836a4c7261cfb2470 [file] [log] [blame]
Brian Silverman37b15b32019-03-10 13:30:18 -07001#ifndef AOS_VISION_BLOB_THRESHOLD_H_
2#define AOS_VISION_BLOB_THRESHOLD_H_
Parker Schuh6691f192017-01-14 17:01:02 -08003
4#include "aos/vision/blob/range_image.h"
5#include "aos/vision/image/image_types.h"
6
7namespace aos {
8namespace vision {
Brian Silverman37b15b32019-03-10 13:30:18 -07009namespace threshold_internal {
Parker Schuh6691f192017-01-14 17:01:02 -080010
Brian Silverman37b15b32019-03-10 13:30:18 -070011// Performs thresholding in a given region using a function which determines
12// whether a given point is in or out of the region.
13//
14// fn must return a bool when called with two integers (x, y).
15template <typename PointTestFn>
16RangeImage ThresholdPointsWithFunction(ImageFormat fmt, PointTestFn &&fn) {
17 static_assert(
18 std::is_convertible<PointTestFn, std::function<bool(int, int)>>::value,
19 "Invalid threshold function");
Parker Schuh6691f192017-01-14 17:01:02 -080020 std::vector<std::vector<ImageRange>> ranges;
Parker Schuh02f13f62019-02-16 16:42:41 -080021 ranges.reserve(fmt.h);
22 for (int y = 0; y < fmt.h; ++y) {
Parker Schuh6691f192017-01-14 17:01:02 -080023 bool p_score = false;
24 int pstart = -1;
25 std::vector<ImageRange> rngs;
Parker Schuh02f13f62019-02-16 16:42:41 -080026 for (int x = 0; x < fmt.w; ++x) {
27 if (fn(x, y) != p_score) {
Parker Schuh6691f192017-01-14 17:01:02 -080028 if (p_score) {
29 rngs.emplace_back(ImageRange(pstart, x));
30 } else {
31 pstart = x;
32 }
33 p_score = !p_score;
34 }
35 }
36 if (p_score) {
Parker Schuh02f13f62019-02-16 16:42:41 -080037 rngs.emplace_back(ImageRange(pstart, fmt.w));
Parker Schuh6691f192017-01-14 17:01:02 -080038 }
39 ranges.push_back(rngs);
40 }
41 return RangeImage(0, std::move(ranges));
42}
43
Brian Silverman37b15b32019-03-10 13:30:18 -070044} // namespace threshold_internal
45
46// Thresholds an image using a function which determines whether a given pixel
47// value is in or out of the region.
48//
49// fn must return a bool when called with a PixelRef.
Parker Schuh02f13f62019-02-16 16:42:41 -080050template <typename ThresholdFn>
Brian Silverman37b15b32019-03-10 13:30:18 -070051RangeImage ThresholdImageWithFunction(const ImagePtr &img, ThresholdFn &&fn) {
52 static_assert(
53 std::is_convertible<ThresholdFn, std::function<bool(PixelRef)>>::value,
54 "Invalid threshold function");
55 return threshold_internal::ThresholdPointsWithFunction(
56 img.fmt(), [&](int x, int y) { return fn(img.get_px(x, y)); });
Parker Schuh02f13f62019-02-16 16:42:41 -080057}
58
Brian Silverman37b15b32019-03-10 13:30:18 -070059// Thresholds an image in YUYV format, selecting pixels with a Y (luma) greater
60// than value.
61//
62// This is implemented via a simple function that pulls out the Y values and
63// compares them each. It mostly exists for tests to compare against
64// FastYuyvYThreshold, because it's obviously correct.
65inline RangeImage SlowYuyvYThreshold(ImageFormat fmt, const char *data,
66 uint8_t value) {
67 return threshold_internal::ThresholdPointsWithFunction(
68 fmt, [&](int x, int y) {
69 uint8_t v = data[x * 2 + y * fmt.w * 2];
70 return v > value;
71 });
Parker Schuh02f13f62019-02-16 16:42:41 -080072}
73
Brian Silverman37b15b32019-03-10 13:30:18 -070074// Thresholds an image in YUYV format, selecting pixels with a Y (luma) greater
75// than value.
76//
77// This is implemented via some tricky bit shuffling that goes fast.
78RangeImage FastYuyvYThreshold(ImageFormat fmt, const char *data, uint8_t value);
79
Parker Schuh6691f192017-01-14 17:01:02 -080080} // namespace vision
81} // namespace aos
82
Brian Silverman37b15b32019-03-10 13:30:18 -070083#endif // AOS_VISION_BLOB_THRESHOLD_H_