blob: 989172295caceda2b6973fc55d29b544c410391a [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");
Brian Silverman4482db52019-03-10 16:14:48 -070020 std::vector<std::vector<ImageRange>> result;
21 result.reserve(fmt.h);
22 // Iterate through each row.
Parker Schuh02f13f62019-02-16 16:42:41 -080023 for (int y = 0; y < fmt.h; ++y) {
Brian Silverman4482db52019-03-10 16:14:48 -070024 // Whether we're currently in a range.
25 bool in_range = false;
26 int current_range_start = -1;
27 std::vector<ImageRange> current_row_ranges;
28 // Iterate through each pixel.
Parker Schuh02f13f62019-02-16 16:42:41 -080029 for (int x = 0; x < fmt.w; ++x) {
Brian Silverman4482db52019-03-10 16:14:48 -070030 if (fn(x, y) != in_range) {
31 if (in_range) {
32 current_row_ranges.emplace_back(ImageRange(current_range_start, x));
Parker Schuh6691f192017-01-14 17:01:02 -080033 } else {
Brian Silverman4482db52019-03-10 16:14:48 -070034 current_range_start = x;
Parker Schuh6691f192017-01-14 17:01:02 -080035 }
Brian Silverman4482db52019-03-10 16:14:48 -070036 in_range = !in_range;
Parker Schuh6691f192017-01-14 17:01:02 -080037 }
38 }
Brian Silverman4482db52019-03-10 16:14:48 -070039 if (in_range) {
40 current_row_ranges.emplace_back(ImageRange(current_range_start, fmt.w));
Parker Schuh6691f192017-01-14 17:01:02 -080041 }
Brian Silverman4482db52019-03-10 16:14:48 -070042 result.push_back(current_row_ranges);
Parker Schuh6691f192017-01-14 17:01:02 -080043 }
Brian Silverman4482db52019-03-10 16:14:48 -070044 return RangeImage(0, std::move(result));
Parker Schuh6691f192017-01-14 17:01:02 -080045}
46
Brian Silverman37b15b32019-03-10 13:30:18 -070047} // namespace threshold_internal
48
49// Thresholds an image using a function which determines whether a given pixel
50// value is in or out of the region.
51//
52// fn must return a bool when called with a PixelRef.
Parker Schuh02f13f62019-02-16 16:42:41 -080053template <typename ThresholdFn>
Brian Silverman37b15b32019-03-10 13:30:18 -070054RangeImage ThresholdImageWithFunction(const ImagePtr &img, ThresholdFn &&fn) {
55 static_assert(
56 std::is_convertible<ThresholdFn, std::function<bool(PixelRef)>>::value,
57 "Invalid threshold function");
58 return threshold_internal::ThresholdPointsWithFunction(
59 img.fmt(), [&](int x, int y) { return fn(img.get_px(x, y)); });
Parker Schuh02f13f62019-02-16 16:42:41 -080060}
61
Brian Silverman37b15b32019-03-10 13:30:18 -070062// Thresholds an image in YUYV format, selecting pixels with a Y (luma) greater
63// than value.
64//
65// This is implemented via a simple function that pulls out the Y values and
66// compares them each. It mostly exists for tests to compare against
67// FastYuyvYThreshold, because it's obviously correct.
68inline RangeImage SlowYuyvYThreshold(ImageFormat fmt, const char *data,
69 uint8_t value) {
70 return threshold_internal::ThresholdPointsWithFunction(
71 fmt, [&](int x, int y) {
72 uint8_t v = data[x * 2 + y * fmt.w * 2];
73 return v > value;
74 });
Parker Schuh02f13f62019-02-16 16:42:41 -080075}
76
Brian Silverman37b15b32019-03-10 13:30:18 -070077// Thresholds an image in YUYV format, selecting pixels with a Y (luma) greater
Brian Silverman4482db52019-03-10 16:14:48 -070078// than value. The width must be a multiple of 4.
Brian Silverman37b15b32019-03-10 13:30:18 -070079//
80// This is implemented via some tricky bit shuffling that goes fast.
81RangeImage FastYuyvYThreshold(ImageFormat fmt, const char *data, uint8_t value);
82
Parker Schuh6691f192017-01-14 17:01:02 -080083} // namespace vision
84} // namespace aos
85
Brian Silverman37b15b32019-03-10 13:30:18 -070086#endif // AOS_VISION_BLOB_THRESHOLD_H_