open source driving agent
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
8.0 KiB

#include "camera_webcam.h"
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include "common/util.h"
#include "common/timing.h"
#include "common/clutil.h"
#include "common/swaglog.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-inline"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#pragma clang diagnostic pop
extern volatile sig_atomic_t do_exit;
#define FRAME_WIDTH 1164
#define FRAME_HEIGHT 874
#define FRAME_WIDTH_FRONT 1152
#define FRAME_HEIGHT_FRONT 864
namespace {
void camera_open(CameraState *s, bool rear) {
}
void camera_close(CameraState *s) {
s->buf.stop();
}
void camera_init(CameraState *s, int camera_id, unsigned int fps, cl_device_id device_id, cl_context ctx) {
assert(camera_id < ARRAYSIZE(cameras_supported));
s->ci = cameras_supported[camera_id];
assert(s->ci.frame_width != 0);
s->fps = fps;
s->buf.init(device_id, ctx, s, FRAME_BUF_COUNT, "frame");
}
static void* rear_thread(void *arg) {
int err;
set_thread_name("webcam_rear_thread");
CameraState* s = (CameraState*)arg;
cv::VideoCapture cap_rear(1); // road
5 years ago
cap_rear.set(cv::CAP_PROP_FRAME_WIDTH, 853);
cap_rear.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
cap_rear.set(cv::CAP_PROP_FPS, s->fps);
cap_rear.set(cv::CAP_PROP_AUTOFOCUS, 0); // off
cap_rear.set(cv::CAP_PROP_FOCUS, 0); // 0 - 255?
// cv::Rect roi_rear(160, 0, 960, 720);
cv::Size size;
size.height = s->ci.frame_height;
size.width = s->ci.frame_width;
// transforms calculation see tools/webcam/warp_vis.py
5 years ago
float ts[9] = {1.50330396, 0.0, -59.40969163,
0.0, 1.50330396, 76.20704846,
0.0, 0.0, 1.0};
5 years ago
// if camera upside down:
// float ts[9] = {-1.50330396, 0.0, 1223.4,
// 0.0, -1.50330396, 797.8,
// 0.0, 0.0, 1.0};
const cv::Mat transform = cv::Mat(3, 3, CV_32F, ts);
if (!cap_rear.isOpened()) {
err = 1;
}
uint32_t frame_id = 0;
TBuffer* tb = &s->buf.camera_tb;
while (!do_exit) {
cv::Mat frame_mat;
cv::Mat transformed_mat;
cap_rear >> frame_mat;
// int rows = frame_mat.rows;
// int cols = frame_mat.cols;
// printf("Raw Rear, R=%d, C=%d\n", rows, cols);
cv::warpPerspective(frame_mat, transformed_mat, transform, size, cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0);
int transformed_size = transformed_mat.total() * transformed_mat.elemSize();
const int buf_idx = tbuffer_select(tb);
s->buf.camera_bufs_metadata[buf_idx] = {
.frame_id = frame_id,
};
cl_command_queue q = s->buf.camera_bufs[buf_idx].copy_q;
cl_mem yuv_cl = s->buf.camera_bufs[buf_idx].buf_cl;
cl_event map_event;
void *yuv_buf = (void *)CL_CHECK_ERR(clEnqueueMapBuffer(q, yuv_cl, CL_TRUE,
CL_MAP_WRITE, 0, transformed_size,
0, NULL, &map_event, &err));
clWaitForEvents(1, &map_event);
clReleaseEvent(map_event);
memcpy(yuv_buf, transformed_mat.data, transformed_size);
CL_CHECK(clEnqueueUnmapMemObject(q, yuv_cl, yuv_buf, 0, NULL, &map_event));
clWaitForEvents(1, &map_event);
clReleaseEvent(map_event);
tbuffer_dispatch(tb, buf_idx);
frame_id += 1;
frame_mat.release();
transformed_mat.release();
}
cap_rear.release();
return NULL;
}
void front_thread(CameraState *s) {
int err;
cv::VideoCapture cap_front(2); // driver
5 years ago
cap_front.set(cv::CAP_PROP_FRAME_WIDTH, 853);
cap_front.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
cap_front.set(cv::CAP_PROP_FPS, s->fps);
// cv::Rect roi_front(320, 0, 960, 720);
cv::Size size;
size.height = s->ci.frame_height;
size.width = s->ci.frame_width;
// transforms calculation see tools/webcam/warp_vis.py
5 years ago
float ts[9] = {1.42070485, 0.0, -30.16740088,
0.0, 1.42070485, 91.030837,
0.0, 0.0, 1.0};
5 years ago
// if camera upside down:
// float ts[9] = {-1.42070485, 0.0, 1182.2,
// 0.0, -1.42070485, 773.0,
// 0.0, 0.0, 1.0};
const cv::Mat transform = cv::Mat(3, 3, CV_32F, ts);
if (!cap_front.isOpened()) {
err = 1;
}
uint32_t frame_id = 0;
TBuffer* tb = &s->buf.camera_tb;
while (!do_exit) {
cv::Mat frame_mat;
cv::Mat transformed_mat;
cap_front >> frame_mat;
// int rows = frame_mat.rows;
// int cols = frame_mat.cols;
// printf("Raw Front, R=%d, C=%d\n", rows, cols);
cv::warpPerspective(frame_mat, transformed_mat, transform, size, cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0);
int transformed_size = transformed_mat.total() * transformed_mat.elemSize();
const int buf_idx = tbuffer_select(tb);
s->buf.camera_bufs_metadata[buf_idx] = {
.frame_id = frame_id,
};
cl_command_queue q = s->buf.camera_bufs[buf_idx].copy_q;
cl_mem yuv_cl = s->buf.camera_bufs[buf_idx].buf_cl;
cl_event map_event;
void *yuv_buf = (void *)CL_CHECK_ERR(clEnqueueMapBuffer(q, yuv_cl, CL_TRUE,
CL_MAP_WRITE, 0, transformed_size,
0, NULL, &map_event, &err));
clWaitForEvents(1, &map_event);
clReleaseEvent(map_event);
memcpy(yuv_buf, transformed_mat.data, transformed_size);
CL_CHECK(clEnqueueUnmapMemObject(q, yuv_cl, yuv_buf, 0, NULL, &map_event));
clWaitForEvents(1, &map_event);
clReleaseEvent(map_event);
tbuffer_dispatch(tb, buf_idx);
frame_id += 1;
frame_mat.release();
transformed_mat.release();
}
cap_front.release();
return;
}
} // namespace
CameraInfo cameras_supported[CAMERA_ID_MAX] = {
// road facing
[CAMERA_ID_LGC920] = {
.frame_width = FRAME_WIDTH,
.frame_height = FRAME_HEIGHT,
.frame_stride = FRAME_WIDTH*3,
.bayer = false,
.bayer_flip = false,
},
// driver facing
[CAMERA_ID_LGC615] = {
.frame_width = FRAME_WIDTH_FRONT,
.frame_height = FRAME_HEIGHT_FRONT,
.frame_stride = FRAME_WIDTH_FRONT*3,
.bayer = false,
.bayer_flip = false,
},
};
void cameras_init(MultiCameraState *s, cl_device_id device_id, cl_context ctx) {
camera_init(&s->rear, CAMERA_ID_LGC920, 20, device_id, ctx);
s->rear.transform = (mat3){{
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
}};
camera_init(&s->front, CAMERA_ID_LGC615, 10, device_id, ctx);
s->front.transform = (mat3){{
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
}};
s->pm = new PubMaster({"frame", "frontFrame"});
}
void camera_autoexposure(CameraState *s, float grey_frac) {}
void cameras_open(MultiCameraState *s) {
// LOG("*** open front ***");
camera_open(&s->front, false);
// LOG("*** open rear ***");
camera_open(&s->rear, true);
}
void cameras_close(MultiCameraState *s) {
camera_close(&s->rear);
camera_close(&s->front);
delete s->pm;
}
void camera_process_front(MultiCameraState *s, CameraState *c, int cnt) {
MessageBuilder msg;
auto framed = msg.initEvent().initFrontFrame();
framed.setFrameType(cereal::FrameData::FrameType::FRONT);
fill_frame_data(framed, c->buf.cur_frame_data, cnt);
s->pm->send("frontFrame", msg);
}
void camera_process_rear(MultiCameraState *s, CameraState *c, int cnt) {
const CameraBuf *b = &c->buf;
MessageBuilder msg;
auto framed = msg.initEvent().initFrame();
fill_frame_data(framed, b->cur_frame_data, cnt);
framed.setImage(kj::arrayPtr((const uint8_t *)b->yuv_ion[b->cur_yuv_idx].addr, b->yuv_buf_size));
framed.setTransform(b->yuv_transform.v);
s->pm->send("frame", msg);
}
void cameras_run(MultiCameraState *s) {
std::vector<std::thread> threads;
threads.push_back(start_process_thread(s, "processing", &s->rear, 51, camera_process_rear));
threads.push_back(start_process_thread(s, "frontview", &s->front, 51, camera_process_front));
std::thread t_rear = std::thread(rear_thread, &s->rear);
set_thread_name("webcam_thread");
front_thread(&s->front);
t_rear.join();
cameras_close(s);
for (auto &t : threads) t.join();
5 years ago
}