openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
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.

164 lines
7.8 KiB

#include <string.h>
#include "dmonitoring.h"
#include "common/mat.h"
#include "common/timing.h"
// #include <fastcv.h>
#include <libyuv.h>
#define MODEL_WIDTH 160
#define MODEL_HEIGHT 320
#define FULL_W 426
void dmonitoring_init(DMonitoringModelState* s) {
s->m = new DefaultRunModel("../../models/dmonitoring_model_q.dlc", (float*)&s->output, OUTPUT_SIZE, USE_DSP_RUNTIME);
}
DMonitoringResult dmonitoring_eval_frame(DMonitoringModelState* s, void* stream_buf, int width, int height) {
uint8_t *raw_buf = (uint8_t*) stream_buf;
uint8_t *raw_y_buf = raw_buf;
uint8_t *raw_u_buf = raw_y_buf + (width * height);
uint8_t *raw_v_buf = raw_u_buf + ((width/2) * (height/2));
int cropped_width = height/2;
int cropped_height = height;
int resized_width = MODEL_WIDTH;
int resized_height = MODEL_HEIGHT;
uint8_t *cropped_buf = new uint8_t[cropped_width*cropped_height*3/2];
uint8_t *cropped_y_buf = cropped_buf;
uint8_t *cropped_u_buf = cropped_y_buf + (cropped_width * cropped_height);
uint8_t *cropped_v_buf = cropped_u_buf + ((cropped_width/2) * (cropped_height/2));
if (true) {
for (int r = 0; r < height/2; r++) {
memcpy(cropped_y_buf + 2*r*cropped_width, raw_y_buf + 2*r*width + (width - cropped_width), cropped_width);
memcpy(cropped_y_buf + (2*r+1)*cropped_width, raw_y_buf + (2*r+1)*width + (width - cropped_width), cropped_width);
memcpy(cropped_u_buf + r*cropped_width/2, raw_u_buf + r*width/2 + ((width/2) - (cropped_width/2)), cropped_width/2);
memcpy(cropped_v_buf + r*cropped_width/2, raw_v_buf + r*width/2 + ((width/2) - (cropped_width/2)), cropped_width/2);
}
} else {
// not tested
uint8_t *premirror_cropped_buf = new uint8_t[cropped_width*cropped_height*3/2];
uint8_t *premirror_cropped_y_buf = premirror_cropped_buf;
uint8_t *premirror_cropped_u_buf = premirror_cropped_y_buf + (cropped_width * cropped_height);
uint8_t *premirror_cropped_v_buf = premirror_cropped_u_buf + ((cropped_width/2) * (cropped_height/2));
for (int r = 0; r < height/2; r++) {
memcpy(premirror_cropped_y_buf + 2*r*cropped_width, raw_y_buf + 2*r*width, cropped_width);
memcpy(premirror_cropped_y_buf + (2*r+1)*cropped_width, raw_y_buf + (2*r+1)*width, cropped_width);
memcpy(premirror_cropped_u_buf + r*cropped_width/2, raw_u_buf + r*width/2, cropped_width/2);
memcpy(premirror_cropped_v_buf + r*cropped_width/2, raw_v_buf + r*width/2, cropped_width/2);
}
libyuv::I420Mirror(premirror_cropped_y_buf, cropped_width,
premirror_cropped_u_buf, cropped_width/2,
premirror_cropped_v_buf, cropped_width/2,
cropped_y_buf, cropped_width,
cropped_u_buf, cropped_width/2,
cropped_v_buf, cropped_width/2,
cropped_width, cropped_height);
}
uint8_t *resized_buf = new uint8_t[resized_width*resized_height*3/2];
uint8_t *resized_y_buf = resized_buf;
uint8_t *resized_u_buf = resized_y_buf + (resized_width * resized_height);
uint8_t *resized_v_buf = resized_u_buf + ((resized_width/2) * (resized_height/2));
libyuv::FilterMode mode = libyuv::FilterModeEnum::kFilterBilinear;
libyuv::I420Scale(cropped_y_buf, cropped_width,
cropped_u_buf, cropped_width/2,
cropped_v_buf, cropped_width/2,
cropped_width, cropped_height,
resized_y_buf, resized_width,
resized_u_buf, resized_width/2,
resized_v_buf, resized_width/2,
resized_width, resized_height,
mode);
int yuv_buf_len = (MODEL_WIDTH/2) * (MODEL_HEIGHT/2) * 6; // Y|u|v -> y|y|y|y|u|v
float *net_input_buf = new float[yuv_buf_len];
// one shot conversion, O(n) anyway
// yuvframe2tensor, normalize
for (int r = 0; r < MODEL_HEIGHT/2; r++) {
for (int c = 0; c < MODEL_WIDTH/2; c++) {
// Y_ul
net_input_buf[(c*MODEL_HEIGHT/2) + r] = (resized_buf[(2*r*resized_width) + (2*c)] - 128.f) * 0.0078125f;
// Y_ur
net_input_buf[(c*MODEL_HEIGHT/2) + r + ((MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = (resized_buf[(2*r*resized_width) + (2*c+1)] - 128.f) * 0.0078125f;
// Y_dl
net_input_buf[(c*MODEL_HEIGHT/2) + r + (2*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = (resized_buf[(2*r*resized_width+1) + (2*c)] - 128.f) * 0.0078125f;
// Y_dr
net_input_buf[(c*MODEL_HEIGHT/2) + r + (3*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = (resized_buf[(2*r*resized_width+1) + (2*c+1)] - 128.f) * 0.0078125f;
// U
net_input_buf[(c*MODEL_HEIGHT/2) + r + (4*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = (resized_buf[(resized_width*resized_height) + (r*resized_width/2) + c] - 128.f) * 0.0078125f;
// V
net_input_buf[(c*MODEL_HEIGHT/2) + r + (5*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = (resized_buf[(resized_width*resized_height) + ((resized_width/2)*(resized_height/2)) + (r*resized_width/2) + c] - 128.f) * 0.0078125f;
}
}
// FILE *dump_yuv_file = fopen("/sdcard/rawdump.yuv", "wb");
// fwrite(raw_buf, height*width*3/2, sizeof(uint8_t), dump_yuv_file);
// fclose(dump_yuv_file);
// FILE *dump_yuv_file2 = fopen("/sdcard/inputdump.yuv", "wb");
// fwrite(net_input_buf, MODEL_HEIGHT*MODEL_WIDTH*3/2, sizeof(float), dump_yuv_file2);
// fclose(dump_yuv_file2);
delete[] cropped_buf;
delete[] resized_buf;
s->m->execute(net_input_buf, yuv_buf_len);
delete[] net_input_buf;
DMonitoringResult ret = {0};
memcpy(&ret.face_orientation, &s->output[0], sizeof ret.face_orientation);
memcpy(&ret.face_orientation_meta, &s->output[6], sizeof ret.face_orientation_meta);
memcpy(&ret.face_position, &s->output[3], sizeof ret.face_position);
memcpy(&ret.face_position_meta, &s->output[9], sizeof ret.face_position_meta);
memcpy(&ret.face_prob, &s->output[12], sizeof ret.face_prob);
memcpy(&ret.left_eye_prob, &s->output[21], sizeof ret.left_eye_prob);
memcpy(&ret.right_eye_prob, &s->output[30], sizeof ret.right_eye_prob);
memcpy(&ret.left_blink_prob, &s->output[31], sizeof ret.right_eye_prob);
memcpy(&ret.right_blink_prob, &s->output[32], sizeof ret.right_eye_prob);
ret.face_orientation_meta[0] = softplus(ret.face_orientation_meta[0]);
ret.face_orientation_meta[1] = softplus(ret.face_orientation_meta[1]);
ret.face_orientation_meta[2] = softplus(ret.face_orientation_meta[2]);
ret.face_position_meta[0] = softplus(ret.face_position_meta[0]);
ret.face_position_meta[1] = softplus(ret.face_position_meta[1]);
return ret;
}
void dmonitoring_publish(PubSocket* sock, uint32_t frame_id, const DMonitoringResult res) {
// make msg
capnp::MallocMessageBuilder msg;
cereal::Event::Builder event = msg.initRoot<cereal::Event>();
event.setLogMonoTime(nanos_since_boot());
auto framed = event.initDriverState();
framed.setFrameId(frame_id);
kj::ArrayPtr<const float> face_orientation(&res.face_orientation[0], ARRAYSIZE(res.face_orientation));
kj::ArrayPtr<const float> face_orientation_std(&res.face_orientation_meta[0], ARRAYSIZE(res.face_orientation_meta));
kj::ArrayPtr<const float> face_position(&res.face_position[0], ARRAYSIZE(res.face_position));
kj::ArrayPtr<const float> face_position_std(&res.face_position_meta[0], ARRAYSIZE(res.face_position_meta));
framed.setFaceOrientation(face_orientation);
framed.setFaceOrientationStd(face_orientation_std);
framed.setFacePosition(face_position);
framed.setFacePositionStd(face_position_std);
framed.setFaceProb(res.face_prob);
framed.setLeftEyeProb(res.left_eye_prob);
framed.setRightEyeProb(res.right_eye_prob);
framed.setLeftBlinkProb(res.left_blink_prob);
framed.setRightBlinkProb(res.right_blink_prob);
// send message
auto words = capnp::messageToFlatArray(msg);
auto bytes = words.asBytes();
sock->send((char*)bytes.begin(), bytes.size());
}
void dmonitoring_free(DMonitoringModelState* s) {
delete s->m;
}