Sundry tweaks to aos/vision libs
Change-Id: Ia5578dcf2d42ac53b81af239bf329eb084fcf1d9
diff --git a/aos/common/util/global_factory.h b/aos/common/util/global_factory.h
index 148fc1e..aac49bb 100644
--- a/aos/common/util/global_factory.h
+++ b/aos/common/util/global_factory.h
@@ -44,7 +44,7 @@
class GlobalFactory {
public:
using FactoryFunction =
- std::function<std::unique_ptr<BaseClass>(FactoryArgs&&...)>;
+ std::function<std::unique_ptr<BaseClass>(FactoryArgs &&...)>;
// Gets the factory function by named. This will return a null factory
// std::function if the factory is not available, so one would be wise
@@ -67,13 +67,18 @@
class SubClassRegisterer {
public:
explicit SubClassRegisterer(const char *name) {
- (*GetMap())[name] = [](FactoryArgs&&... args) {
+ (*GetMap())[name] = [](FactoryArgs &&... args) {
return std::unique_ptr<BaseClass>(
new SubClass(std::forward<FactoryArgs>(args)...));
};
}
};
+ // Fetch all factory functions.
+ static const std::unordered_map<std::string, FactoryFunction> &GetAll() {
+ return *GetMap();
+ }
+
private:
// Actual map. (Protected by static from concurrent construction
// if there is nothing registered at static linkage time).
diff --git a/aos/vision/blob/move_scale.h b/aos/vision/blob/move_scale.h
index c113bca..e45e14d 100644
--- a/aos/vision/blob/move_scale.h
+++ b/aos/vision/blob/move_scale.h
@@ -1,8 +1,8 @@
#ifndef AOS_VISION_BLOB_MOVE_SCALE_H_
#define AOS_VISION_BLOB_MOVE_SCALE_H_
-#include <vector>
#include <limits>
+#include <vector>
#include "aos/vision/blob/range_image.h"
diff --git a/aos/vision/blob/range_image.cc b/aos/vision/blob/range_image.cc
index 5f2f29f..946859d 100644
--- a/aos/vision/blob/range_image.cc
+++ b/aos/vision/blob/range_image.cc
@@ -75,7 +75,7 @@
if (span.ed > maxx) maxx = span.ed;
}
}
- LOG(INFO, "maxx: %d minx: %d\n", maxx, minx);
+ printf("maxx: %d minx: %d\n", maxx, minx);
char buf[maxx - minx];
for (const auto &range : rimg.ranges()) {
int i = minx;
@@ -84,7 +84,7 @@
for (; i < span.ed; ++i) buf[i - minx] = '#';
}
for (; i < maxx; ++i) buf[i - minx] = ' ';
- LOG(INFO, "%.*s\n", maxx - minx, buf);
+ printf("%.*s\n", maxx - minx, buf);
}
}
diff --git a/aos/vision/blob/stream_view.h b/aos/vision/blob/stream_view.h
index 2ae56ac..a6a661a 100644
--- a/aos/vision/blob/stream_view.h
+++ b/aos/vision/blob/stream_view.h
@@ -29,56 +29,51 @@
memset(image_.data(), 0, fmt.ImgSize() * sizeof(PixelRef));
}
- inline void DrawBlobList(const BlobList &blob_list, PixelRef color) {
+ template <typename PixelCallback>
+ inline void ForPxInBlobList(const BlobList &blob_list,
+ PixelCallback pixel_callback) {
ImagePtr ptr = img();
- for (const RangeImage &blob : blob_list) {
+ auto fmt = ptr.fmt();
+ for (const auto &blob : blob_list) {
for (int i = 0; i < (int)blob.ranges().size(); ++i) {
- for (const auto &range : blob.ranges()[i]) {
- for (int j = range.st; j < range.ed; ++j) {
- ptr.get_px(j, i + blob.min_y()) = color;
+ int y = blob.min_y() + i;
+ if (y >= 0 && y < fmt.h) {
+ for (const auto &range : blob.ranges()[i]) {
+ for (int j = std::max(0, range.st); j < std::min(fmt.w, range.ed);
+ ++j) {
+ pixel_callback(ptr.get_px(j, y));
+ }
}
}
}
}
}
+ inline void DrawBlobList(const BlobList &blob_list, PixelRef color) {
+ ForPxInBlobList(blob_list, [&](PixelRef &px) { px = color; });
+ }
+
inline void DrawSecondBlobList(const BlobList &blob_list, PixelRef color1,
PixelRef color2) {
- ImagePtr ptr = img();
- for (const auto &blob : blob_list) {
- for (int i = 0; i < (int)blob.ranges().size(); ++i) {
- for (const auto &range : blob.ranges()[i]) {
- for (int j = range.st; j < range.ed; ++j) {
- auto px = ptr.get_px(j, i + blob.min_y());
- if (px.r == 0 && px.g == 0 && px.b == 0) {
- ptr.get_px(j, i + blob.min_y()) = color1;
- } else {
- ptr.get_px(j, i + blob.min_y()) = color2;
- }
- }
- }
+ ForPxInBlobList(blob_list, [&](PixelRef &px) {
+ if (px.r == 0 && px.g == 0 && px.b == 0) {
+ px = color1;
+ } else {
+ px = color2;
}
- }
+ });
}
inline void DrawSecondBlobList(const BlobList &blob_list, PixelRef color1,
PixelRef color2, PixelRef prev_color) {
- ImagePtr ptr = img();
- for (const auto &blob : blob_list) {
- for (int i = 0; i < (int)blob.ranges().size(); ++i) {
- for (const auto &range : blob.ranges()[i]) {
- for (int j = range.st; j < range.ed; ++j) {
- auto px = ptr.get_px(j, i + blob.min_y());
- if (px.r == prev_color.r && px.g == prev_color.g &&
- px.b == prev_color.b) {
- ptr.get_px(j, i + blob.min_y()) = color2;
- } else {
- ptr.get_px(j, i + blob.min_y()) = color1;
- }
- }
- }
+ ForPxInBlobList(blob_list, [&](PixelRef &px) {
+ if (px.r == prev_color.r && px.g == prev_color.g &&
+ px.b == prev_color.b) {
+ px = color2;
+ } else {
+ px = color1;
}
- }
+ });
}
// Backwards compatible.
diff --git a/aos/vision/blob/transpose.cc b/aos/vision/blob/transpose.cc
index 19ac965..72e1cc1 100644
--- a/aos/vision/blob/transpose.cc
+++ b/aos/vision/blob/transpose.cc
@@ -1,6 +1,7 @@
#include "aos/vision/blob/transpose.h"
#include <algorithm>
+#include <limits>
namespace aos {
namespace vision {
@@ -14,27 +15,30 @@
kPointAdd = 3,
kPointDel = 2,
};
+ int min_y = std::numeric_limits<int>::max();
+ for (const std::vector<ImageRange> &row : img) {
+ if (!row.empty()) min_y = std::min(row[0].st, min_y);
+ }
+
std::vector<std::vector<std::pair<int, EventT>>> events;
int y = img.min_y();
for (const std::vector<ImageRange> &row : img) {
for (const ImageRange &range : row) {
- if (range.ed >= static_cast<int>(events.size()))
- events.resize(range.ed + 1);
- events[range.st].emplace_back(y, kPointAdd);
- events[range.ed].emplace_back(y, kPointDel);
+ if (range.ed - min_y >= static_cast<int>(events.size())) {
+ events.resize(range.ed - min_y + 1);
+ }
+ events[range.st - min_y].emplace_back(y, kPointAdd);
+ events[range.ed - min_y].emplace_back(y, kPointDel);
}
++y;
}
- int min_y = 0;
- while (min_y < (int)events.size() && events[min_y].empty()) ++min_y;
-
std::vector<ImageRange> prev_ranges;
std::vector<ImageRange> cur_ranges;
std::vector<std::vector<ImageRange>> rows;
- for (int y = min_y; y < static_cast<int>(events.size()) - 1; ++y) {
- auto row_events = std::move(events[y]);
+ for (int dy = 0; dy < static_cast<int>(events.size()) - 1; ++dy) {
+ auto row_events = std::move(events[dy]);
for (const auto &range : prev_ranges) {
row_events.emplace_back(range.st, kRangeStart);
row_events.emplace_back(range.ed, kRangeEnd);
diff --git a/aos/vision/debug/debug_viewer.cc b/aos/vision/debug/debug_viewer.cc
index 331f733..b0cf295 100644
--- a/aos/vision/debug/debug_viewer.cc
+++ b/aos/vision/debug/debug_viewer.cc
@@ -101,6 +101,10 @@
window_height_ = h;
window_width_ = w;
}
+ if (!shown_yet_) {
+ gtk_widget_show_all(self->window);
+ shown_yet_ = true;
+ }
}
void DebugViewer::MoveTo(int x, int y) {
@@ -149,7 +153,6 @@
window_height_ * scale_factor);
gtk_container_add(GTK_CONTAINER(window), drawing_area);
- gtk_widget_show_all(window);
}
DebugViewer::~DebugViewer() {}
diff --git a/aos/vision/debug/debug_viewer.h b/aos/vision/debug/debug_viewer.h
index 3bada28..ab2c716 100644
--- a/aos/vision/debug/debug_viewer.h
+++ b/aos/vision/debug/debug_viewer.h
@@ -66,6 +66,7 @@
std::function<void(uint32_t)> key_press_event;
private:
+ bool shown_yet_ = false;
double scale_factor = 1.0;
int window_width_ = 100;
int window_height_ = 100;
diff --git a/aos/vision/events/BUILD b/aos/vision/events/BUILD
index 2b5b9e7..9c55a1c 100644
--- a/aos/vision/events/BUILD
+++ b/aos/vision/events/BUILD
@@ -1,5 +1,5 @@
load('/tools/build_rules/gtk_dependent', 'gtk_dependent_cc_binary', 'gtk_dependent_cc_library')
-package(default_visibility = ["//visibility:public"])
+package(default_visibility = ['//visibility:public'])
cc_library(
name = 'epoll_events',
@@ -12,12 +12,14 @@
],
)
-cc_library(name = "socket_types",
- hdrs = ["socket_types.h"],
- deps = [
- "//aos/vision/events:tcp_server",
- "//aos/vision/image:image_types",
- ],
+cc_library(
+ name = 'socket_types',
+ hdrs = ['socket_types.h'],
+ deps = [
+ '//aos/vision/events:tcp_server',
+ '//aos/vision/image:image_types',
+ '//third_party/protobuf:protobuf',
+ ],
)
cc_library(
@@ -59,10 +61,10 @@
)
gtk_dependent_cc_library(
- name = "gtk_event",
- srcs = ["gtk_event.cc"],
+ name = 'gtk_event',
+ srcs = ['gtk_event.cc'],
deps = [
- ":epoll_events",
+ ':epoll_events',
'@usr_repo//:gtk+-3.0',
],
)
diff --git a/aos/vision/events/epoll_events.cc b/aos/vision/events/epoll_events.cc
index e4f789f..d49043c 100644
--- a/aos/vision/events/epoll_events.cc
+++ b/aos/vision/events/epoll_events.cc
@@ -36,7 +36,7 @@
for (int i = 0; i < number_events; i++) {
EpollEvent *event = static_cast<EpollEvent *>(events[i].data.ptr);
- if ((events[i].events & ~(EPOLLIN | EPOLLPRI)) != 0) {
+ if ((events[i].events & ~(EPOLLIN | EPOLLPRI | EPOLLERR)) != 0) {
LOG(FATAL, "unexpected epoll events set in %x on %d\n",
events[i].events, event->fd());
}
diff --git a/aos/vision/events/epoll_events.h b/aos/vision/events/epoll_events.h
index ee288c4..3b7d75a 100644
--- a/aos/vision/events/epoll_events.h
+++ b/aos/vision/events/epoll_events.h
@@ -44,7 +44,7 @@
// Duplicate above to allow Done to change itself.
if (time_ < monotonic_clock::epoch()) return -1;
if (time_ <= now) {
- return -1;// Recalculate(now);
+ return -1;
}
if (time_ - now > ::std::chrono::milliseconds(INT_MAX)) {
diff --git a/aos/vision/events/gtk_event.cc b/aos/vision/events/gtk_event.cc
index e8b43aa..0c518e0 100644
--- a/aos/vision/events/gtk_event.cc
+++ b/aos/vision/events/gtk_event.cc
@@ -1,9 +1,9 @@
-#include <gtk/gtk.h>
#include <gdk/gdk.h>
-#include <thread>
+#include <gtk/gtk.h>
#include <sys/epoll.h>
-#include <mutex>
#include <condition_variable>
+#include <mutex>
+#include <thread>
#include "aos/vision/events/epoll_events.h"
@@ -43,16 +43,19 @@
std::thread t([&]() {
std::unique_lock<std::mutex> lk(m);
while (true) {
- cv.wait(lk, [&all_events_handled]{return all_events_handled;});
+ cv.wait(lk, [&all_events_handled] { return all_events_handled; });
// Wait for handle_cb to be done.
- number_events = PCHECK(epoll_wait(epoll_fd(), events, kNumberOfEvents, timeout));
+ number_events =
+ PCHECK(epoll_wait(epoll_fd(), events, kNumberOfEvents, timeout));
all_events_handled = false;
// Trigger handle_cb on main_thread to avoid concurrency.
- gdk_threads_add_idle(+[](gpointer user_data) -> gboolean {
- auto& handle_cb = *reinterpret_cast<HandleCBType*>(user_data);
- handle_cb();
- return G_SOURCE_REMOVE;
- }, &handle_cb);
+ gdk_threads_add_idle(
+ +[](gpointer user_data) -> gboolean {
+ auto &handle_cb = *reinterpret_cast<HandleCBType *>(user_data);
+ handle_cb();
+ return G_SOURCE_REMOVE;
+ },
+ &handle_cb);
}
});
gtk_main();
diff --git a/aos/vision/events/socket_types.h b/aos/vision/events/socket_types.h
index 2432cb9..d377214 100644
--- a/aos/vision/events/socket_types.h
+++ b/aos/vision/events/socket_types.h
@@ -3,6 +3,8 @@
#include <poll.h>
#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include "aos/vision/events/tcp_server.h"
#include "aos/vision/image/image_types.h"
@@ -32,7 +34,12 @@
char buf[512];
while (true) {
count = read(fd(), &buf, sizeof buf);
- if (count <= 0) return;
+ if (count <= 0) {
+ if (errno != EAGAIN) {
+ CloseConnection();
+ return;
+ }
+ }
}
}
@@ -46,14 +53,15 @@
void Emit(vision::DataRef data) {
data_len len;
len.len = data.size();
- int res = write(fd(), len.buf, sizeof len.buf);
+ int res = send(fd(), len.buf, sizeof len.buf, MSG_NOSIGNAL);
if (res == -1) {
- printf("Emit Error on write\n");
+ CloseConnection();
+ return;
}
size_t write_count = 0;
while (write_count < data.size()) {
- int len =
- write(fd(), &data.data()[write_count], data.size() - write_count);
+ int len = send(fd(), &data.data()[write_count], data.size() - write_count,
+ MSG_NOSIGNAL);
if (len == -1) {
if (errno == EAGAIN) {
struct pollfd waiting;
@@ -61,7 +69,7 @@
waiting.events = POLLOUT;
poll(&waiting, 1, -1);
} else {
- close(fd());
+ CloseConnection();
return;
}
} else {
@@ -70,6 +78,13 @@
if (write_count != data.size()) printf("wrote: %d\n", len);
}
}
+
+ private:
+ void CloseConnection() {
+ loop()->Delete(this);
+ close(fd());
+ delete this;
+ }
};
} // namespace events
diff --git a/aos/vision/events/tcp_client.cc b/aos/vision/events/tcp_client.cc
index 41485f9..4ac45af 100644
--- a/aos/vision/events/tcp_client.cc
+++ b/aos/vision/events/tcp_client.cc
@@ -30,7 +30,7 @@
return 0;
}
-int OpenClient(const char *hostname, int portno) {
+int OpenClient(const std::string &hostname, int portno) {
int sockfd;
struct sockaddr_in serveraddr;
struct hostent *server;
@@ -38,9 +38,9 @@
PCHECK(sockfd = socket(AF_INET, SOCK_STREAM, 0));
/* gethostbyname: get the server's DNS entry */
- server = gethostbyname(hostname);
+ server = gethostbyname(hostname.c_str());
if (server == NULL) {
- fprintf(stderr, "ERROR, no such host as %s\n", hostname);
+ fprintf(stderr, "ERROR, no such host as %s\n", hostname.c_str());
exit(-1);
}
@@ -60,7 +60,7 @@
}
} // namespace
-TcpClient::TcpClient(const char *hostname, int portno)
+TcpClient::TcpClient(const std::string &hostname, int portno)
: EpollEvent(OpenClient(hostname, portno)) {}
} // namespace events
diff --git a/aos/vision/events/tcp_client.h b/aos/vision/events/tcp_client.h
index 7ce01f7..74f1418 100644
--- a/aos/vision/events/tcp_client.h
+++ b/aos/vision/events/tcp_client.h
@@ -4,6 +4,7 @@
#include "aos/vision/events/epoll_events.h"
#include <memory>
+#include <string>
namespace aos {
namespace events {
@@ -11,7 +12,7 @@
// Handles the client connection logic to hostname:portno
class TcpClient : public EpollEvent {
public:
- TcpClient(const char *hostname, int portno);
+ TcpClient(const std::string &hostname, int portno);
// Implement ReadEvent from EpollEvent to use this class.
};
diff --git a/aos/vision/events/udp.cc b/aos/vision/events/udp.cc
index b5367f6..4c0437b 100644
--- a/aos/vision/events/udp.cc
+++ b/aos/vision/events/udp.cc
@@ -22,7 +22,8 @@
}
int TXUdpSocket::Send(const char *data, int size) {
- return PCHECK(send(fd_.get(), data, size, 0));
+ // Don't fail on send. If no one is connected that is fine.
+ return send(fd_.get(), data, size, 0);
}
RXUdpSocket::RXUdpSocket(int port)
diff --git a/aos/vision/image/image_stream.h b/aos/vision/image/image_stream.h
index ac25394..5a1ad21 100644
--- a/aos/vision/image/image_stream.h
+++ b/aos/vision/image/image_stream.h
@@ -18,8 +18,8 @@
camera::CameraParams params) {
using namespace std::placeholders;
std::unique_ptr<::camera::Reader> camread(new ::camera::Reader(
- fname,
- std::bind(&ImageStreamEvent::ProcessHelper, obj, _1, _2), params));
+ fname, std::bind(&ImageStreamEvent::ProcessHelper, obj, _1, _2),
+ params));
camread->StartAsync();
return camread;
}
@@ -33,12 +33,13 @@
void ProcessHelper(DataRef data, aos::monotonic_clock::time_point timestamp) {
if (data.size() < 300) {
- LOG(INFO, "got bad img of size(%zu)\n", data.size());
+ LOG(INFO, "got bad img of size(%d)\n", static_cast<int>(data.size()));
return;
}
ProcessImage(data, timestamp);
}
- virtual void ProcessImage(DataRef data, aos::monotonic_clock::time_point timestamp) = 0;
+ virtual void ProcessImage(DataRef data,
+ aos::monotonic_clock::time_point timestamp) = 0;
void ReadEvent() override { reader_->HandleFrame(); }
diff --git a/aos/vision/image/image_types.h b/aos/vision/image/image_types.h
index 2c9ba56..68e6d67 100644
--- a/aos/vision/image/image_types.h
+++ b/aos/vision/image/image_types.h
@@ -19,7 +19,7 @@
struct ImageFormat {
ImageFormat() : w(0), h(0) {}
ImageFormat(int nw, int nh) : w(nw), h(nh) {}
- std::string ToString() {
+ std::string ToString() const {
std::ostringstream s;
s << "ImageFormat {" << w << ", " << h << "}";
return s.str();
diff --git a/aos/vision/image/reader.cc b/aos/vision/image/reader.cc
index 95729da..3a4b349 100644
--- a/aos/vision/image/reader.cc
+++ b/aos/vision/image/reader.cc
@@ -29,6 +29,9 @@
}
Init();
+
+ InitMMap();
+ LOG(INFO, "Bat Vision Successfully Initialized.\n");
}
void Reader::QueueBuffer(v4l2_buffer *buf) {
@@ -57,6 +60,18 @@
}
--queued_;
+ if (tick_id_ % 10 == 0) {
+ if (!SetCameraControl(V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO",
+ V4L2_EXPOSURE_MANUAL)) {
+ LOG(FATAL, "Failed to set exposure\n");
+ }
+
+ if (!SetCameraControl(V4L2_CID_EXPOSURE_ABSOLUTE,
+ "V4L2_CID_EXPOSURE_ABSOLUTE", params_.exposure)) {
+ LOG(FATAL, "Failed to set exposure\n");
+ }
+ }
+ ++tick_id_;
// Get a timestamp now as proxy for when the image was taken
// TODO(ben): the image should come with a timestamp, parker
// will know how to get it.
@@ -66,6 +81,7 @@
reinterpret_cast<const char *>(buffers_[buf.index].start),
buf.bytesused),
time);
+
QueueBuffer(&buf);
}
@@ -105,7 +121,7 @@
}
}
queued_ = kNumBuffers;
- if (req.count < kNumBuffers) {
+ if (req.count != kNumBuffers) {
LOG(FATAL, "Insufficient buffer memory on %s\n", dev_name_.c_str());
}
}
@@ -236,9 +252,6 @@
setfps->parm.capture.timeperframe.numerator,
setfps->parm.capture.timeperframe.denominator);
// #endif
-
- InitMMap();
- LOG(INFO, "Bat Vision Successfully Initialized.\n");
}
aos::vision::ImageFormat Reader::get_format() {
diff --git a/aos/vision/image/reader.h b/aos/vision/image/reader.h
index eabb80a..28735fb 100644
--- a/aos/vision/image/reader.h
+++ b/aos/vision/image/reader.h
@@ -41,8 +41,8 @@
void HandleFrame();
void StartAsync() {
- Start();
MMapBuffers();
+ Start();
}
int fd() { return fd_; }
@@ -60,6 +60,7 @@
ProcessCb process_;
+ int tick_id_ = 0;
// The number of buffers currently queued in v4l2.
uint32_t queued_;
struct Buffer;
@@ -67,7 +68,10 @@
// because the buffers are not ummapped.
Buffer *buffers_;
- static const unsigned int kNumBuffers = 10;
+ // TODO(parker): The timestamps should be queue insertion timestamps
+ // which will remove the impact of kNumBuffers.
+ // TODO(parker): Flush the queue (or tweak the FPS) if we fall behind.
+ static const unsigned int kNumBuffers = 5;
// set only at initialize
CameraParams params_;
diff --git a/aos/vision/tools/jpeg_vision_test.cc b/aos/vision/tools/jpeg_vision_test.cc
index 37d9ffe..52dd22f 100644
--- a/aos/vision/tools/jpeg_vision_test.cc
+++ b/aos/vision/tools/jpeg_vision_test.cc
@@ -2,42 +2,64 @@
// should not placed on a robot. This is okay as it is a utility of limited use
// only.
-#include <stdio.h>
-#include <stdlib.h>
+#include <gtk/gtk.h>
#include <netdb.h>
#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <gtk/gtk.h>
-#include <vector>
-#include <memory>
#include <fstream>
+#include <memory>
+#include <vector>
-#include "aos/common/logging/logging.h"
#include "aos/common/logging/implementations.h"
-#include "aos/vision/math/vector.h"
-#include "aos/vision/image/reader.h"
-#include "aos/vision/image/jpeg_routines.h"
-#include "aos/vision/blob/threshold.h"
+#include "aos/common/logging/logging.h"
#include "aos/vision/blob/range_image.h"
#include "aos/vision/blob/stream_view.h"
+#include "aos/vision/blob/threshold.h"
#include "aos/vision/events/epoll_events.h"
-#include "aos/vision/image/image_stream.h"
#include "aos/vision/events/tcp_server.h"
+#include "aos/vision/image/image_stream.h"
+#include "aos/vision/image/jpeg_routines.h"
+#include "aos/vision/image/reader.h"
+#include "aos/vision/math/vector.h"
namespace aos {
namespace vision {
+void DrawVLine(ImagePtr ptr, int x, PixelRef color = {255, 0, 0}) {
+ for (int y = 0; y < ptr.fmt().h; ++y) {
+ ptr.get_px(x, y) = color;
+ }
+}
+void DrawHLine(ImagePtr ptr, int y, PixelRef color = {255, 0, 0}) {
+ for (int x = 0; x < ptr.fmt().w; ++x) {
+ ptr.get_px(x, y) = color;
+ }
+}
+
// Connects up a camera with our processing.
class ChannelImageStream : public ImageStreamEvent {
public:
ChannelImageStream(const std::string &fname,
const camera::CameraParams ¶ms)
- : ImageStreamEvent(fname, params), view_(true) {
+ : ImageStreamEvent(fname, params), view_(false) {
// Lambda to record image data to a file on key press.
- view_.view()->key_press_event = [this](uint32_t /*keyval*/) {
- std::ofstream ofs("/tmp/test.jpg", std::ofstream::out);
- ofs << prev_data_;
- ofs.close();
+ view_.view()->key_press_event = [this](uint32_t keyval) {
+ if (keyval == 'j') {
+ std::ofstream ofs("/tmp/test.jpg", std::ofstream::out);
+ ofs << prev_data_;
+ ofs.close();
+ } else if (keyval == 'a') {
+ ++dx;
+ } else if (keyval == 'd') {
+ --dx;
+ } else if (keyval == 'w') {
+ ++dy;
+ } else if (keyval == 's') {
+ --dy;
+ }
+ fprintf(stderr, "dx: %d dy: %d\n", dx, dy);
};
}
@@ -51,7 +73,6 @@
ImagePtr img_ptr = view_.img();
prev_data_ = data.to_string();
-
// Threshold the image with the given lambda.
RangeImage rimg = DoThreshold(img_ptr, [](PixelRef &px) {
if (px.g > 88) {
@@ -65,6 +86,13 @@
return false;
});
+ DrawVLine(img_ptr, fmt.w / 4);
+ DrawVLine(img_ptr, fmt.w / 2 + dy, {0, 255, 0});
+ DrawVLine(img_ptr, fmt.w - fmt.w / 4);
+
+ DrawHLine(img_ptr, fmt.h / 4);
+ DrawHLine(img_ptr, fmt.h / 2 + dx, {0, 255, 0});
+ DrawHLine(img_ptr, fmt.h - fmt.h / 4);
view_.DrawBlobList({rimg}, {255, 255, 255});
view_.Redraw();
@@ -75,6 +103,9 @@
// responsible for handling drawing
BlobStreamViewer view_;
+
+ int dx = 0;
+ int dy = 0;
};
} // namespace aos
} // namespace vision
@@ -91,7 +122,7 @@
.exposure = 10,
.brightness = 128,
.gain = 0,
- .fps = 10};
+ .fps = 25};
aos::vision::ChannelImageStream strm1("/dev/video1", params);