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.
285 lines
7.9 KiB
285 lines
7.9 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
|
|
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
|
|
float ts[9] = {1.50330396, 0.0, -59.40969163,
|
|
0.0, 1.50330396, 76.20704846,
|
|
0.0, 0.0, 1.0};
|
|
// 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
|
|
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
|
|
float ts[9] = {1.42070485, 0.0, -30.16740088,
|
|
0.0, 1.42070485, 91.030837,
|
|
0.0, 0.0, 1.0};
|
|
// 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, camera_process_rear));
|
|
threads.push_back(start_process_thread(s, "frontview", &s->front, 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();
|
|
}
|
|
|