blob: a0a0dc700b18cd497cbc61891dc3632325ee9c4d [file] [log] [blame]
Parker Schuh24ee58d2017-03-11 16:13:23 -08001#include <sys/stat.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07002
3#include <cstdio>
4#include <cstdlib>
Parker Schuh2cd173d2017-01-28 00:12:01 -08005#include <fstream>
6#include <iostream>
7#include <memory>
8#include <thread>
9#include <vector>
10
John Park33858a32018-09-28 23:05:48 -070011#include "aos/time/time.h"
Parker Schuh2cd173d2017-01-28 00:12:01 -080012#include "aos/vision/events/socket_types.h"
13#include "aos/vision/events/udp.h"
14#include "aos/vision/image/image_stream.h"
15#include "aos/vision/image/jpeg_routines.h"
16#include "aos/vision/image/reader.h"
17#include "y2016/vision/blob_filters.h"
18#include "y2016/vision/stereo_geometry.h"
19#include "y2016/vision/vision_data.pb.h"
20
21namespace y2016 {
22namespace vision {
Parker Schuh2cd173d2017-01-28 00:12:01 -080023using aos::events::DataSocket;
Tyler Chatowbf0609c2021-07-31 16:13:27 -070024using aos::events::TCPServer;
25using aos::events::TXUdpSocket;
26using aos::vision::BlobList;
27using aos::vision::BlobLRef;
28using aos::vision::CornerFinder;
29using aos::vision::DataRef;
30using aos::vision::HistogramBlobFilter;
Parker Schuh2cd173d2017-01-28 00:12:01 -080031using aos::vision::ImageFormat;
Tyler Chatowbf0609c2021-07-31 16:13:27 -070032using aos::vision::ImageStreamEvent;
33using aos::vision::ImageValue;
34using aos::vision::Int32Codec;
35using aos::vision::Int64Codec;
36using aos::vision::PixelRef;
37using aos::vision::RangeImage;
38using aos::vision::Vector;
Parker Schuh2cd173d2017-01-28 00:12:01 -080039
Parker Schuh24ee58d2017-03-11 16:13:23 -080040::aos::vision::CameraParams GetCameraParams(const Calibration &calibration) {
41 ::aos::vision::CameraParams params;
42 params.set_width(calibration.camera_image_width());
43 params.set_height(calibration.camera_image_height());
44 params.set_exposure(calibration.camera_exposure());
45 params.set_brightness(calibration.camera_brightness());
46 params.set_gain(calibration.camera_gain());
47 params.set_fps(calibration.camera_fps());
48 return params;
Parker Schuh2cd173d2017-01-28 00:12:01 -080049}
50
51int64_t Nanos(aos::monotonic_clock::duration time_diff) {
52 return std::chrono::duration_cast<std::chrono::nanoseconds>(time_diff)
53 .count();
54}
55
56int64_t NowNanos() {
57 return Nanos(aos::monotonic_clock::now().time_since_epoch());
58}
59
60inline bool FileExist(const std::string &name) {
61 struct stat buffer;
62 return (stat(name.c_str(), &buffer) == 0);
63}
64
65class ImageSender : public ImageStreamEvent {
66 public:
Parker Schuh24ee58d2017-03-11 16:13:23 -080067 ImageSender(int camera_index, aos::vision::CameraParams params,
Parker Schuh2cd173d2017-01-28 00:12:01 -080068 const std::string &fname, const std::string &ipadder, int port)
69 : ImageStreamEvent(fname, params),
70 camera_index_(camera_index),
71 udp_serv_(ipadder, 8080),
72 tcp_serv_(port),
Parker Schuh24ee58d2017-03-11 16:13:23 -080073 blob_filt_(ImageFormat(params.width(), params.height()), 40, 750,
74 250000),
Parker Schuh2cd173d2017-01-28 00:12:01 -080075 finder_(0.25, 35) {
76 int index = 0;
77 while (true) {
78 std::string file = "./logging/blob_record_" + std::to_string(index) +
79 "_" + std::to_string(camera_index_) + ".dat";
80 if (FileExist(file)) {
81 index++;
82 } else {
83 printf("Logging to file (%s)\n", file.c_str());
84 ofst_.open(file);
85 assert(ofst_.is_open());
86 break;
87 }
88 }
89 }
90
91 ~ImageSender() { ofst_.close(); }
92
93 void ProcessImage(DataRef data, aos::monotonic_clock::time_point tp) {
94 int64_t timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
95 tp.time_since_epoch())
96 .count();
97 DecodeJpeg(data, &image_);
98 auto fmt = image_.fmt();
99
Brian Silverman37b15b32019-03-10 13:30:18 -0700100 RangeImage rimg = ThresholdImageWithFunction(
101 image_.get(), [](PixelRef px) { return (px.g > 88); });
Parker Schuh2cd173d2017-01-28 00:12:01 -0800102
103 // flip the right image as this camera is mount backward
104 if (camera_index_ == 0) {
105 rimg.Flip(fmt.w, fmt.h);
106 }
107
108 BlobList blobl = aos::vision::FindBlobs(rimg);
109 auto whatever = blob_filt_.FilterBlobs(blobl);
110
111 VisionData target;
112 target.set_camera_index(camera_index_);
113 target.set_image_timestamp(timestamp);
114
115 if (!whatever.empty()) {
116 std::vector<std::pair<Vector<2>, Vector<2>>> corners =
117 finder_.Find(whatever);
118
119 if (!corners.empty()) {
120 for (int i = 0; i < (int)corners.size(); i++) {
121 Target *pos = target.add_target();
122 pos->set_left_corner_x(corners[i].first.x());
123 pos->set_left_corner_y(corners[i].first.y());
124 pos->set_right_corner_x(corners[i].second.x());
125 pos->set_right_corner_y(corners[i].second.y());
126 }
127 }
128 }
129 target.set_send_timestamp(NowNanos());
130
131 // always send data
132 std::string dat;
133 if (target.SerializeToString(&dat)) {
134 if (print_once_) {
135 printf("Beginning data streaming camera %d...\n", camera_index_);
136 print_once_ = false;
137 }
138
139 // Send only target over udp.
140 udp_serv_.Send(dat.data(), dat.size());
141 }
142
143 // Write blob to file for logging.
144 int blob_size = CalculateSize(blobl);
145 int tmp_size = blob_size + sizeof(int32_t) + sizeof(uint64_t);
146 char *buf;
147 blob_data_.resize(tmp_size, 0);
148 {
149 buf = Int32Codec::Write(&blob_data_[0], tmp_size);
150 buf = Int64Codec::Write(buf, timestamp);
151 SerializeBlob(blobl, buf);
152 }
153 ofst_.write(&blob_data_[0], tmp_size);
154
155 // Add blob debug
156 bool debug = true;
157 if (debug) {
158 target.set_raw(buf, blob_size);
159 if (target.SerializeToString(&dat)) {
160 tcp_serv_.Broadcast([&](DataSocket *client) { client->Emit(dat); });
161 }
162 }
163
164 bool timing = false;
165 if (timing) {
166 if (n_time > 0) {
167 auto now = aos::monotonic_clock::now();
168 printf("%g, %g\n",
169 (((double)Nanos(now - tstart)) / (double)(n_time)) / 1e6,
170 (double)Nanos(now - tp) / 1e6);
171 } else {
172 tstart = aos::monotonic_clock::now();
173 }
174 ++n_time;
175 }
176 }
177
178 TCPServer<DataSocket> *GetTCPServ() { return &tcp_serv_; }
179
180 // print when we start
181 bool print_once_ = true;
182
183 // left or right camera
184 int camera_index_;
185
186 // udp socket on which to send to robot
187 TXUdpSocket udp_serv_;
188
189 // tcp socket on which to debug to laptop
190 TCPServer<DataSocket> tcp_serv_;
191
192 // our blob processing object
193 HistogramBlobFilter blob_filt_;
194
195 // corner finder to align aiming
196 CornerFinder finder_;
197
198 ImageValue image_;
199 std::string blob_data_;
200 std::ofstream ofst_;
201 aos::monotonic_clock::time_point tstart;
202 int n_time = 0;
203
204 private:
205};
206
Parker Schuh24ee58d2017-03-11 16:13:23 -0800207void RunCamera(int camera_index, aos::vision::CameraParams params,
Parker Schuh2cd173d2017-01-28 00:12:01 -0800208 const std::string &device, const std::string &ip_addr,
209 int port) {
Parker Schuh24ee58d2017-03-11 16:13:23 -0800210 printf("Creating camera %d (%d, %d).\n", camera_index, params.width(),
211 params.height());
Parker Schuh2cd173d2017-01-28 00:12:01 -0800212 ImageSender strm(camera_index, params, device, ip_addr, port);
213
214 aos::events::EpollLoop loop;
215 loop.Add(strm.GetTCPServ());
216 loop.Add(&strm);
217 printf("Running Camera (%d)\n", camera_index);
218 loop.Run();
219}
220
221} // namespace vision
222} // namespace y2016
223
224int main(int, char **) {
225 using namespace y2016::vision;
226 StereoGeometry stereo("./stereo_rig.calib");
Parker Schuh2cd173d2017-01-28 00:12:01 -0800227 std::thread cam0([stereo]() {
228 RunCamera(0, GetCameraParams(stereo.calibration()),
229 stereo.calibration().right_camera_name(),
Parker Schuhef47dbf2017-03-04 16:59:30 -0800230 stereo.calibration().roborio_ip_addr(), 8080);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800231 });
232 std::thread cam1([stereo]() {
233 RunCamera(1, GetCameraParams(stereo.calibration()),
234 stereo.calibration().left_camera_name(),
Parker Schuhef47dbf2017-03-04 16:59:30 -0800235 stereo.calibration().roborio_ip_addr(), 8080);
Parker Schuh2cd173d2017-01-28 00:12:01 -0800236 });
237 cam0.join();
238 cam1.join();
239
240 return EXIT_SUCCESS;
241}