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