480 lines
16 KiB
C++
480 lines
16 KiB
C++
|
||
#include "Car.h"
|
||
|
||
namespace ORB_SLAM2
|
||
{
|
||
Car::Car(Frame &CurrentFrame, vector<double> &bbox) : mnLastFrameID(CurrentFrame.mnId),
|
||
mnFirstFrameID(CurrentFrame.mnId),
|
||
mbBad(false),
|
||
mvLostTrackTimes(0),
|
||
mmVelocity(cv::Mat::eye(4, 4, CV_32FC1)),
|
||
mnVisual(1),
|
||
myaw(bbox[7]),
|
||
mdelta_w(0),
|
||
mbStatic(false),
|
||
mbErro(false),
|
||
mvStatic(0),
|
||
mV(0),
|
||
mnInsight(0),
|
||
Tow(cv::Mat::eye(4, 4, CV_32FC1)),
|
||
mbInsight(true)
|
||
{
|
||
static int instanceCount = 0; // 计数器
|
||
|
||
instanceCount++;
|
||
mnCar_ID = instanceCount;
|
||
mRcl = mmVelocity.rowRange(0, 3).colRange(0, 3);
|
||
mtcl = mmVelocity.rowRange(0, 3).col(3);
|
||
m_bev_K = (cv::Mat_<float>(3, 3) << 608.0 / 50.0, 0, 304, 0, 608.0 / 50.0, 608, 0, 0, 1);
|
||
m_bev_K_inv = (cv::Mat_<float>(3, 3) << 50.0 / 608.0, 0, -25, 0, 50.0 / 608.0, -50, 0, 0, 1);
|
||
mRbw = (cv::Mat_<float>(3, 3) << 1, 0, 0, 0, 0, -1, 0, 1, 0); // world->bev
|
||
vector<cv::Point> vp_c;
|
||
get_bbx(bbox, vp_c);
|
||
bev2world(vp_c, mvmBboxWorldPose, CurrentFrame.mRwc, CurrentFrame.mOw);
|
||
|
||
mvmBboxWorldPosePredict.resize(4);
|
||
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
mvmBboxWorldPosePredict[i] = mvmBboxWorldPose[i];
|
||
}
|
||
cv::Point carBev;
|
||
carBev.x = bbox[1];
|
||
carBev.y = bbox[2];
|
||
bev2world(carBev, mCarWorldPose, CurrentFrame.mRwc, CurrentFrame.mOw);
|
||
updatetraj();
|
||
SetColor();
|
||
mkalman_H << 1, 0, 0, 0,
|
||
0, 1, 0, 0;
|
||
}
|
||
|
||
bool Car::isStatic()
|
||
{
|
||
return mbStatic;
|
||
}
|
||
|
||
bool Car::isErro()
|
||
{
|
||
return mbErro;
|
||
}
|
||
|
||
double Car::get_Vel(double &t)
|
||
{
|
||
mV = sqrt(pow(mtcl.at<float>(0, 0), 2) + pow(mtcl.at<float>(1, 0), 2) + pow(mtcl.at<float>(2, 0), 2)) / 0.1;
|
||
if (mV * 3.6 > 120)
|
||
{
|
||
mbBad = true;
|
||
}
|
||
if (mV < 2)
|
||
{
|
||
if (mvLostTrackTimes == 0)
|
||
{
|
||
mvStatic++;
|
||
}
|
||
mmVelocity = cv::Mat::eye(4, 4, CV_32FC1);
|
||
mRcl = mmVelocity.rowRange(0, 3).colRange(0, 3);
|
||
mtcl = mmVelocity.rowRange(0, 3).col(3);
|
||
mV = 0;
|
||
}
|
||
else
|
||
{
|
||
mvStatic = 0;
|
||
mbStatic = false;
|
||
}
|
||
|
||
if (mvStatic > 6)
|
||
{
|
||
mbStatic = true;
|
||
}
|
||
return mV;
|
||
}
|
||
|
||
void Car::SetColor()
|
||
{
|
||
int min = 0, max = 255;
|
||
random_device seed; // 硬件生成随机数种子
|
||
ranlux48 engine(seed()); // 利用种子生成随机数引擎
|
||
uniform_int_distribution<> distrib(min, max); // 设置随机数范围,并为均匀分布
|
||
int random_r = distrib(engine); // 随机数
|
||
int random_g = distrib(engine); // 随机数
|
||
int random_b = distrib(engine); // 随机数
|
||
|
||
mr = random_r / 255.0;
|
||
mg = random_g / 255.0;
|
||
mb = random_b / 255.0;
|
||
}
|
||
|
||
void Car::get_bbx(const vector<double> &label1, std ::vector<cv::Point> &pts)
|
||
{
|
||
cv::Point p1, p2, p3, p4;
|
||
double x = label1[1];
|
||
double y = label1[2];
|
||
double w = label1[3];
|
||
double l = label1[4];
|
||
double yaw = label1[7];
|
||
double cos_yaw, sin_yaw;
|
||
cos_yaw = cos(yaw);
|
||
sin_yaw = sin(yaw);
|
||
// front left
|
||
p1.x = x - w / 2 * cos_yaw - l / 2 * sin_yaw;
|
||
p1.y = y - w / 2 * sin_yaw + l / 2 * cos_yaw;
|
||
|
||
// rear left
|
||
p2.x = x - w / 2 * cos_yaw + l / 2 * sin_yaw;
|
||
p2.y = y - w / 2 * sin_yaw - l / 2 * cos_yaw;
|
||
|
||
// rear right
|
||
p3.x = x + w / 2 * cos_yaw + l / 2 * sin_yaw;
|
||
p3.y = y + w / 2 * sin_yaw - l / 2 * cos_yaw;
|
||
|
||
// front right
|
||
p4.x = x + w / 2 * cos_yaw - l / 2 * sin_yaw;
|
||
p4.y = y + w / 2 * sin_yaw + l / 2 * cos_yaw;
|
||
|
||
pts.push_back(p1);
|
||
pts.push_back(p2);
|
||
pts.push_back(p3);
|
||
pts.push_back(p4);
|
||
// cout << pts << endl;
|
||
}
|
||
|
||
void Car::bev2world(vector<cv::Point> &vp_c, vector<cv::Mat> &vmBboxWorldPose, cv::Mat &Rwc, cv::Mat &twc)
|
||
{
|
||
// cout << vp_c << endl;
|
||
vmBboxWorldPose.clear();
|
||
for (auto p_c : vp_c)
|
||
{
|
||
cv::Mat p_uv_c_bev, p_cam_c_bev, p_cam_c_cam, p_cam_w_cam, R_ij;
|
||
p_uv_c_bev = cv::Mat::zeros(3, 1, CV_32FC1);
|
||
p_uv_c_bev.at<float>(0, 0) = p_c.x; // 取bev像素坐标
|
||
p_uv_c_bev.at<float>(1, 0) = p_c.y;
|
||
p_uv_c_bev.at<float>(2, 0) = 1.0;
|
||
p_cam_c_bev = m_bev_K_inv * p_uv_c_bev; // bev像素坐标转bev相机坐标
|
||
p_cam_c_cam = mRbw.t() * p_cam_c_bev; // bev相机坐标转cam的相机坐标
|
||
|
||
p_cam_c_cam.at<float>(1, 0) = -1.0;
|
||
p_cam_w_cam = Rwc * p_cam_c_cam + twc; // 当前cam相机坐标转到世界坐标
|
||
vmBboxWorldPose.push_back(p_cam_w_cam);
|
||
}
|
||
}
|
||
|
||
void Car::bev2world(cv::Point &carBev, cv::Mat &CarWorldPose, cv::Mat &Rwc, cv::Mat &twc)
|
||
{
|
||
cv::Mat p_uv_c_bev, p_cam_c_bev, p_cam_c_cam, p_cam_w_cam, R_ij;
|
||
p_uv_c_bev = cv::Mat::zeros(3, 1, CV_32FC1);
|
||
p_uv_c_bev.at<float>(0, 0) = carBev.x; // 取bev像素坐标
|
||
p_uv_c_bev.at<float>(1, 0) = carBev.y;
|
||
p_uv_c_bev.at<float>(2, 0) = 1.0;
|
||
p_cam_c_bev = m_bev_K_inv * p_uv_c_bev; // bev像素坐标转bev相机坐标
|
||
p_cam_c_cam = mRbw.t() * p_cam_c_bev; // bev相机坐标转cam的相机坐标
|
||
p_cam_c_cam.at<float>(1, 0) = -1.0;
|
||
CarWorldPose = Rwc * p_cam_c_cam + twc; // 当前cam相机坐标转到世界坐标
|
||
}
|
||
|
||
bool Car::isBad()
|
||
{
|
||
return mbBad;
|
||
}
|
||
|
||
bool Car::isInSight()
|
||
{
|
||
return mbInsight;
|
||
}
|
||
|
||
void Car::InCreaseFound(cv::Mat Tcw)
|
||
{
|
||
mbInsight = false;
|
||
|
||
cv::Mat p_3d_w = mCarWorldPose;
|
||
cv::Mat Rcw, tcw, R_ij;
|
||
cv::Mat p_3d_w_mat = cv::Mat::zeros(3, 1, CV_32FC1);
|
||
int u, v;
|
||
p_3d_w_mat.at<float>(0, 0) = p_3d_w.at<float>(0, 0); // 取bev像素坐标
|
||
p_3d_w_mat.at<float>(1, 0) = p_3d_w.at<float>(1, 0);
|
||
p_3d_w_mat.at<float>(2, 0) = p_3d_w.at<float>(2, 0);
|
||
|
||
Rcw = Tcw.rowRange(0, 3).colRange(0, 3);
|
||
tcw = Tcw.rowRange(0, 3).col(3);
|
||
cv::Mat p_3d_c, p_3d_bev, p_uv_bev;
|
||
p_3d_c = Rcw * p_3d_w_mat + tcw; // 世界坐标转相机坐标
|
||
|
||
cv::Mat Rbc = (cv::Mat_<float>(3, 3) << 1, 0, 0, 0, 0, -1, 0, 1, 0); // 相机转bev的矩阵
|
||
p_3d_bev = Rbc * p_3d_c; // 相机转bev
|
||
p_3d_bev.at<float>(2, 0) = 1.0; // 归一
|
||
p_uv_bev = m_bev_K * p_3d_bev; // 过去bev相机坐标转过去bev像素坐标
|
||
u = p_uv_bev.at<float>(0, 0) / p_3d_bev.at<float>(2, 0);
|
||
v = p_uv_bev.at<float>(1, 0) / p_3d_bev.at<float>(2, 0);
|
||
if (u > 0 && u < 608 && v > 0 && v < 608)
|
||
{
|
||
mnInsight++;
|
||
mbInsight = true;
|
||
}
|
||
}
|
||
|
||
void Car::world2bev(vector<cv::Mat> &vm_3d_w, vector<cv::Point> &vp_bev, cv::Mat &Tcw) // 世界坐标转bev像素
|
||
{
|
||
for (auto p_3d_w : vm_3d_w)
|
||
{
|
||
cv::Mat Rcw, tcw, R_ij;
|
||
cv::Mat p_3d_w_mat = cv::Mat::zeros(3, 1, CV_32FC1);
|
||
cv::Point p_bev;
|
||
p_3d_w_mat.at<float>(0, 0) = p_3d_w.at<float>(0, 0); // 取bev像素坐标
|
||
p_3d_w_mat.at<float>(1, 0) = p_3d_w.at<float>(1, 0);
|
||
p_3d_w_mat.at<float>(2, 0) = p_3d_w.at<float>(2, 0);
|
||
|
||
Rcw = Tcw.rowRange(0, 3).colRange(0, 3);
|
||
tcw = Tcw.rowRange(0, 3).col(3);
|
||
cv::Mat p_3d_c, p_3d_bev, p_uv_bev;
|
||
p_3d_c = Rcw * p_3d_w_mat + tcw; // 世界坐标转相机坐标
|
||
|
||
cv::Mat Rbc = (cv::Mat_<float>(3, 3) << 1, 0, 0, 0, 0, -1, 0, 1, 0); // 相机转bev的矩阵
|
||
p_3d_bev = Rbc * p_3d_c; // 相机转bev
|
||
p_3d_bev.at<float>(2, 0) = 1.0; // 归一
|
||
p_uv_bev = m_bev_K * p_3d_bev; // 过去bev相机坐标转过去bev像素坐标
|
||
p_bev.x = p_uv_bev.at<float>(0, 0) / p_3d_bev.at<float>(2, 0);
|
||
p_bev.y = p_uv_bev.at<float>(1, 0) / p_3d_bev.at<float>(2, 0);
|
||
vp_bev.push_back(p_bev);
|
||
}
|
||
}
|
||
|
||
void Car::update_untracked_Car()
|
||
{
|
||
mvLostTrackTimes++;
|
||
if (mvLostTrackTimes > 6)
|
||
{
|
||
mbBad = true;
|
||
}
|
||
else
|
||
{
|
||
|
||
// Step1: 速度不变
|
||
// Step2: 恒速运动,根据速度推算目标位置
|
||
int tmp_i = 0;
|
||
for (auto bboxPose : mvmBboxWorldPose)
|
||
{
|
||
|
||
mvmBboxWorldPose[tmp_i] = mRcl * mvmBboxWorldPose[tmp_i] + mtcl;
|
||
tmp_i++;
|
||
}
|
||
|
||
mCarWorldPose = mRcl * mCarWorldPose + mtcl;
|
||
}
|
||
}
|
||
|
||
void Car::setTrackedState(bool state)
|
||
{
|
||
mnTracked = state;
|
||
}
|
||
|
||
bool Car::isTracked()
|
||
{
|
||
return mnTracked;
|
||
}
|
||
|
||
void Car::updateVelocityAndPose(cv::Mat &pose, double &delta_t, vector<cv::Point> &vp_c, cv::Mat &Rwc, cv::Mat &twc)
|
||
{
|
||
cv::Mat pose_inv;
|
||
// matrix_inv(pose, pose_inv);
|
||
cv::Mat tmp_V, tmp_R, tmp_t;
|
||
// tmp_V = pose_inv * mCarWorldPose; // pose是当前位置,mCarWorldPose在更新时已经是上一帧的位置了
|
||
tmp_R = cv::Mat::eye(3, 3, CV_32FC1);
|
||
tmp_t = pose - mCarWorldPose;
|
||
|
||
Eigen::Vector2f yk(pose.at<float>(0, 0), pose.at<float>(2, 0));
|
||
if (this->mnVisual > 1)
|
||
{
|
||
kalmanfilter(yk, 0.1);
|
||
pose.at<float>(0, 0) = mmk_1(0);
|
||
pose.at<float>(2, 0) = mmk_1(1);
|
||
cv::Point2f tmp, tmp_v;
|
||
pose.at<float>(0, 0) = mmk_1(0);
|
||
pose.at<float>(2, 0) = mmk_1(1);
|
||
tmp.x = pose.at<float>(0, 0);
|
||
tmp.y = pose.at<float>(2, 0);
|
||
tmp_v.x = mmk_1(2);
|
||
tmp_v.y = mmk_1(3);
|
||
// cout << "第 " << mnCar_ID << " 辆车的位置为: " << tmp.x << " " << tmp.y << endl;
|
||
// cout << "第 " << mnCar_ID << " 辆车的位置为: " << pose.at<float>(0, 0) << " " << pose.at<float>(1, 0) << " " << pose.at<float>(2, 0) << endl;
|
||
mvvelocity.push_back(tmp_v);
|
||
mvpose.push_back(tmp);
|
||
}
|
||
|
||
/*
|
||
这里加入卡尔曼滤波,构造
|
||
mk,mtcl里是位移
|
||
*/
|
||
|
||
if (mdelta_w * 180 / 3.1415927 < 30) // 速度变化在合理范围内:TODO hong 速度变化计算
|
||
{
|
||
// Step1: 更新速度
|
||
// mmVelocity = tmp_V;
|
||
mtcl = tmp_t;
|
||
mRcl = tmp_R;
|
||
mtcl.at<float>(1, 0) = 0.0;
|
||
// Step2: 更新位置
|
||
mCarWorldPose = pose;
|
||
mvLostTrackTimes = 0;
|
||
bev2world(vp_c, mvmBboxWorldPose, Rwc, twc);
|
||
}
|
||
else
|
||
{
|
||
mvLostTrackTimes++;
|
||
if (mvLostTrackTimes > 6)
|
||
{
|
||
mbBad = true;
|
||
}
|
||
else
|
||
{
|
||
|
||
// Step1: 速度不变
|
||
// Step2: 恒速运动,根据速度推算目标位置
|
||
int tmp_i = 0;
|
||
for (auto bboxPose : mvmBboxWorldPose)
|
||
{
|
||
|
||
mvmBboxWorldPose[tmp_i] = mRcl * mvmBboxWorldPose[tmp_i] + mtcl;
|
||
tmp_i++;
|
||
}
|
||
|
||
mCarWorldPose = mRcl * mCarWorldPose + mtcl;
|
||
}
|
||
}
|
||
}
|
||
|
||
void Car::matrix_inv(cv::Mat T, cv::Mat T_inv)
|
||
{
|
||
T.copyTo(T_inv);
|
||
cv::Mat Rcw, Rwc, tcw, twc, Twc;
|
||
Rcw = T.rowRange(0, 3).colRange(0, 3);
|
||
Rwc = Rcw.t();
|
||
tcw = T.rowRange(0, 3).col(3);
|
||
twc = -Rcw.t() * tcw;
|
||
Rwc.copyTo(T_inv.rowRange(0, 3).colRange(0, 3));
|
||
twc.copyTo(T_inv.rowRange(0, 3).col(3));
|
||
}
|
||
|
||
void Car::updateTrackState(int ID)
|
||
{
|
||
if (ID - mnLastFrameID > 6)
|
||
{
|
||
if (mnVisual < 3)
|
||
{
|
||
mbErro = true;
|
||
}
|
||
mbBad = true;
|
||
}
|
||
}
|
||
|
||
void Car::updateState(vector<double> &bbox, cv::Mat &Rwc, cv::Mat &twc, double &delta_t)
|
||
{
|
||
cv::Mat tmp_CarWorldPose;
|
||
cv::Point carBev;
|
||
carBev.x = bbox[1];
|
||
carBev.y = bbox[2];
|
||
vector<cv::Point> vp_c;
|
||
get_bbx(bbox, vp_c);
|
||
bev2world(carBev, tmp_CarWorldPose, Rwc, twc); // 获得目标框世界坐标
|
||
mdelta_w = bbox[7] - myaw;
|
||
updateVelocityAndPose(tmp_CarWorldPose, delta_t, vp_c, Rwc, twc); // 更新速度并更新世界坐标
|
||
myaw = bbox[7];
|
||
Tow.rowRange(0, 3).colRange(0, 3) = Rwc * (cv::Mat_<float>(3, 3) << cos(myaw), 0, sin(myaw),
|
||
0, 1, 0,
|
||
-sin(myaw), 0, cos(myaw));
|
||
Tow.rowRange(0, 3).col(3) = mCarWorldPose;
|
||
}
|
||
|
||
void Car::updateObservations(int CurrentFrameId)
|
||
{
|
||
if (mbBad)
|
||
return;
|
||
mnVisual++;
|
||
|
||
mnLastFrameID = CurrentFrameId;
|
||
}
|
||
|
||
void Car::updatetraj()
|
||
{
|
||
cv::Point3f pose;
|
||
pose.x = mCarWorldPose.at<float>(0, 0);
|
||
pose.y = mCarWorldPose.at<float>(1, 0);
|
||
pose.z = mCarWorldPose.at<float>(2, 0);
|
||
mtraj.push_back(pose);
|
||
}
|
||
|
||
void Car::kalmanfilter(Eigen::Vector2f &yk, double delta_t)
|
||
{
|
||
if (mnVisual == 2)
|
||
{
|
||
mmk_1 << this->mCarWorldPose.at<float>(0, 0), this->mCarWorldPose.at<float>(2, 0), (yk[0] - this->mCarWorldPose.at<float>(0, 0)) / 0.1, (yk[1] - this->mCarWorldPose.at<float>(2, 0)) / 0.1;
|
||
}
|
||
if (mnVisual == 1)
|
||
{
|
||
cout << "error in kalmanfilter" << endl;
|
||
return;
|
||
}
|
||
|
||
Eigen::Matrix4f A;
|
||
A << 1, 0, delta_t, 0,
|
||
0, 1, 0, delta_t,
|
||
0, 0, 1, 0,
|
||
0, 0, 0, 1;
|
||
float q1c, q2c;
|
||
float sigma1, sigma2;
|
||
q1c = 1.0;
|
||
q2c = 1.0;
|
||
sigma1 = 0.5;
|
||
sigma2 = 0.5;
|
||
float delta_t3 = delta_t * delta_t * delta_t / 3;
|
||
float delta_t2 = delta_t * delta_t / 2;
|
||
|
||
Eigen::Matrix4f Q;
|
||
Q << q1c * delta_t3, 0, q1c * delta_t2, 0,
|
||
0, q2c * delta_t3, 0, q2c * delta_t2,
|
||
q1c * delta_t2, 0, q1c * delta_t, 0,
|
||
0, q2c * delta_t2, 0, q2c * delta_t;
|
||
|
||
Eigen::Vector4f mk_ = A * mmk_1;
|
||
Eigen::Matrix4f Pk_ = A * mPK_1 * A.transpose() + Q;
|
||
|
||
// 更新
|
||
Eigen::Vector2f vk = yk - mkalman_H * mk_;
|
||
Eigen::Matrix2f S_k = mkalman_H * Pk_ * mkalman_H.transpose() + mkalman_R;
|
||
Eigen::MatrixXf Kk = Pk_ * mkalman_H.transpose() * S_k.inverse();
|
||
|
||
mmk_1 = mk_ + Kk * vk;
|
||
|
||
Eigen::Matrix4f tmpawd = Pk_ - Kk * S_k * Kk.transpose();
|
||
mPK_1 = tmpawd;
|
||
// cout << "row = " << tmp_mmk_1.rows() << " col = " << tmp_mmk_1.cols() << endl;
|
||
}
|
||
|
||
void Car::Save_car_v()
|
||
{
|
||
|
||
std::string filename = "./Car_data/kalmanfilter/file_" + std::to_string(this->mnCar_ID) + ".txt";
|
||
|
||
if (this->mvpose.size() < 6)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 使用文件流打开文件
|
||
std::fstream fileStream(filename, std::ios::out | std::ios::app);
|
||
if (!fileStream.is_open())
|
||
{
|
||
std::ofstream newFile(filename);
|
||
// 如果需要在创建文件后写入,请在此处添加相应的写入代码
|
||
}
|
||
|
||
// 写入位置数据
|
||
for (size_t i = 0; i < mvpose.size(); i++)
|
||
{
|
||
fileStream << mvpose[i].x << " " << mvpose[i].y << " " << mvvelocity[i].x << " " << mvvelocity[i].y << std::endl;
|
||
}
|
||
|
||
// 关闭文件流
|
||
fileStream.close();
|
||
}
|
||
|
||
}
|