TinyRobotics
Loading...
Searching...
No Matches
CameraImageDiff.h
1
2
3#pragma once
4#include <cmath>
5#include <cstdint>
6#include <vector>
7
8#include "TinyRobotics/utils/AllocatorPSRAM.h"
9
10namespace tinyrobotics {
11
12/**
13 * @class CameraImageDiff
14 * @ingroup sensors
15 * @brief Computes pixel-wise differences between consecutive grayscale camera
16 * images.
17 *
18 * This class is designed for simple motion or change detection in a sequence of
19 * grayscale images. It calculates the absolute difference between the current
20 * and previous image, applies a threshold, and provides methods to count the
21 * number of changed pixels globally or in image regions.
22 *
23 * Features:
24 * - Computes per-pixel absolute difference between frames
25 * - Thresholds the difference to create a binary mask of changed pixels
26 * - Counts changed pixels globally, by vertical thirds (left/center/right),
27 * or by horizontal thirds (top/center/bottom)
28 * - Lightweight and suitable for embedded/Arduino use
29 *
30 * Usage Example:
31 * @code
32 * CameraImageDiff diff;
33 * diff.process(image, width, height);
34 * diff.threshold(30);
35 * uint32_t changed = diff.countChanges();
36 * auto [left, center, right] = diff.countChangesSplitVertical();
37 * auto [top, center, bottom] = diff.countChangesSplitHorizontal();
38 * @endcode
39 */
40
41class CameraImageDiff {
42 public:
43 CameraImageDiff() = default;
44
45 void process(const uint8_t* image, size_t width, size_t height) {
46 this->width_ = width;
47 this->height_ = height;
48 diff_.resize(width * height);
49 prevImage_.resize(width * height);
50 for (uint32_t i = 0; i < width_ * height_; ++i) {
51 diff_[i] = (uint8_t)abs(int16_t(image[i]) - int16_t(prevImage_[i]));
52 }
53 memcpy(prevImage_.data(), image, width * height);
54 }
55
56 /// Simple thresholding: convert difference to binary mask
57 void threshold(uint8_t thresh) {
58 mask_.resize(width_ * height_);
59 for (uint32_t i = 0; i < width_ * height_; ++i) {
60 mask_[i] = (diff_[i] > thresh) ? 255 : 0;
61 }
62 }
63
64 /// Count number of pixels above threshold
65 uint32_t countChanges() {
66 uint32_t cnt = 0;
67 for (uint32_t i = 0; i < width_ * height_; ++i)
68 if (mask_[i] != 0) ++cnt;
69 return cnt;
70 }
71
72 /**
73 * Count number of changed pixels in left, center, and right thirds of the
74 * image.
75 * @return std::tuple<uint32_t, uint32_t, uint32_t> (left, center, right)
76 */
77 std::tuple<uint32_t, uint32_t, uint32_t> countChangesSplitVertical() {
78 uint32_t left = 0, center = 0, right = 0;
79 int leftEnd = width_ / 3;
80 int centerEnd = 2 * width_ / 3;
81 for (int y = 0; y < height_; ++y) {
82 for (int x = 0; x < width_; ++x) {
83 int idx = y * width_ + x;
84 if (mask_[idx] != 0) {
85 if (x < leftEnd)
86 ++left;
87 else if (x < centerEnd)
88 ++center;
89 else
90 ++right;
91 }
92 }
93 }
94 return std::make_tuple(left, center, right);
95 }
96
97 /**
98 * Count number of changed pixels in top, center, and bottom thirds of the
99 * image.
100 * @return std::tuple<uint32_t, uint32_t, uint32_t> (top, center, bottom)
101 */
102 std::tuple<uint32_t, uint32_t, uint32_t> countChangesSplitHorizontal() {
103 uint32_t top = 0, center = 0, bottom = 0;
104 int topEnd = height_ / 3;
105 int centerEnd = 2 * height_ / 3;
106 for (int y = 0; y < height_; ++y) {
107 for (int x = 0; x < width_; ++x) {
108 int idx = y * width_ + x;
109 if (mask_[idx] != 0) {
110 if (y < topEnd)
111 ++top;
112 else if (y < centerEnd)
113 ++center;
114 else
115 ++bottom;
116 }
117 }
118 }
119 return std::make_tuple(top, center, bottom);
120 }
121
122 void end() {
123 prevImage_.resize(0);
124 diff_.resize(0);
125 mask_.resize(0);
126 }
127 int getWidth() const { return width_; }
128 int getHeight() const { return height_; }
129 int getPixelCount() const { return width_ * height_; }
130 /// Provides the raw difference buffer (grayscale values 0–255) for external
131 /// use or debugging.
132 uint8_t* getDiff() { return diff_.data(); }
133
134 protected:
135 int width_ = 0;
136 int height_ = 0;
137 std::vector<uint8_t, AllocatorPSRAM<uint8_t>> prevImage_;
138 std::vector<uint8_t, AllocatorPSRAM<uint8_t>> diff_;
139 std::vector<uint8_t, AllocatorPSRAM<uint8_t>> mask_;
140};
141
142} // namespace tinyrobotics
Custom allocator that uses ESP32's PSRAM for memory allocation.
Definition: AllocatorPSRAM.h:21
Computes pixel-wise differences between consecutive grayscale camera images.
Definition: CameraImageDiff.h:41
std::tuple< uint32_t, uint32_t, uint32_t > countChangesSplitVertical()
Definition: CameraImageDiff.h:77
uint32_t countChanges()
Count number of pixels above threshold.
Definition: CameraImageDiff.h:65
std::tuple< uint32_t, uint32_t, uint32_t > countChangesSplitHorizontal()
Definition: CameraImageDiff.h:102
void threshold(uint8_t thresh)
Simple thresholding: convert difference to binary mask.
Definition: CameraImageDiff.h:57
uint8_t * getDiff()
Definition: CameraImageDiff.h:132