123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952 |
- //
- // Created by zx on 2020/7/1.
- //
- #include "detect_wheel_ceres3d.h"
- #include "interpolated_grid.hpp"
- #include <pcl/common/transforms.h>
- #include "point_tool.h"
- class CostFunctor3d
- {
- private:
- const InterpolatedProbabilityGrid m_left_interpolated_grid;
- const InterpolatedProbabilityGrid m_right_interpolated_grid;
- mutable double m_costs_lf, m_costs_rf, m_costs_lr, m_costs_rr;
- pcl::PointCloud<pcl::PointXYZ> m_left_front_cloud; //左前点云
- pcl::PointCloud<pcl::PointXYZ> m_right_front_cloud; //右前点云
- pcl::PointCloud<pcl::PointXYZ> m_left_rear_cloud; //左后点云
- pcl::PointCloud<pcl::PointXYZ> m_right_rear_cloud; //右后点云
- // 20220118 added by yct
- float m_ratio; // 模型变换比例,用于贴合模型,cloud / ratio --> model
- public:
- CostFunctor3d(pcl::PointCloud<pcl::PointXYZ> left_front, pcl::PointCloud<pcl::PointXYZ> right_front,
- pcl::PointCloud<pcl::PointXYZ> left_rear, pcl::PointCloud<pcl::PointXYZ> right_rear,
- const HybridGrid& left_interpolated_grid,
- const HybridGrid& right_interpolated_grid, float ratio)
- :m_left_interpolated_grid(left_interpolated_grid),m_right_interpolated_grid(right_interpolated_grid)
- {
- m_left_front_cloud = left_front;
- m_right_front_cloud = right_front;
- m_left_rear_cloud = left_rear;
- m_right_rear_cloud = right_rear;
- m_costs_lf = 0.0;
- m_costs_rf = 0.0;
- m_costs_lr = 0.0;
- m_costs_rr = 0.0;
- m_ratio = ratio;
- }
- template<typename T>
- bool operator()(const T *const variable, T *residual) const
- {
- T cx = variable[0];
- T cy = variable[1];
- T theta = variable[2];
- T length = variable[3];
- T width = variable[4];
- T theta_front = variable[5];
- //整车旋转
- Eigen::Rotation2D<T> rotation(theta);
- Eigen::Matrix<T, 2, 2> rotation_matrix = rotation.toRotationMatrix();
- //左前偏移
- Eigen::Matrix<T, 2, 1> wheel_center_normal_left_front(length / 2.0, width / 2.0);
- //右前偏移
- Eigen::Matrix<T, 2, 1> wheel_center_normal_right_front(length / 2.0, -width / 2.0);
- //左后偏移
- Eigen::Matrix<T, 2, 1> wheel_center_normal_left_rear(-length / 2.0, width / 2.0);
- //右后偏移
- Eigen::Matrix<T, 2, 1> wheel_center_normal_right_rear(-length / 2.0, -width / 2.0);
- //前轮旋转
- Eigen::Rotation2D<T> rotation_front(theta_front);
- Eigen::Matrix<T, 2, 2> rotation_matrix_front = rotation_front.toRotationMatrix();
- //左前轮
- int left_front_num = m_left_front_cloud.size();
- for (int i = 0; i < m_left_front_cloud.size(); ++i)
- {
- const Eigen::Matrix<T, 2, 1> point((T(m_left_front_cloud[i].x) - cx),
- (T(m_left_front_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<T, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_left_front;
- //旋转
- const Eigen::Matrix<T, 2, 1> point_rotation = rotation_matrix_front * (tanslate_point*T(m_ratio));
- residual[i] = T(1.0) - m_left_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
- T(m_left_front_cloud[i].z));
- }
- //右前轮
- int right_front_num = m_right_front_cloud.size();
- for (int i = 0; i < m_right_front_cloud.size(); ++i)
- {
- const Eigen::Matrix<T, 2, 1> point((T(m_right_front_cloud[i].x) - cx),
- (T(m_right_front_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<T, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_right_front;
- //旋转
- const Eigen::Matrix<T, 2, 1> point_rotation = rotation_matrix_front * (tanslate_point*T(m_ratio));
- residual[left_front_num + i] = T(1.0) - m_right_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
- T(m_right_front_cloud[i].z));
- }
- //左后轮
- int left_rear_num = m_left_rear_cloud.size();
- for (int i = 0; i < m_left_rear_cloud.size(); ++i)
- {
- const Eigen::Matrix<T, 2, 1> point((T(m_left_rear_cloud[i].x) - cx),
- (T(m_left_rear_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<T, 2, 1> tanslate_point = (rotation_matrix * point - wheel_center_normal_left_rear)*T(m_ratio);;
- residual[left_front_num + right_front_num + i] = T(1.0) -
- m_left_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
- T(m_left_rear_cloud[i].z));
- }
- //右后轮
- int right_rear_num = m_right_rear_cloud.size();
- for (int i = 0; i < m_right_rear_cloud.size(); ++i)
- {
- const Eigen::Matrix<T, 2, 1> point((T(m_right_rear_cloud[i].x) - cx),
- (T(m_right_rear_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<T, 2, 1> tanslate_point = (rotation_matrix * point - wheel_center_normal_right_rear)*T(m_ratio);
- residual[left_front_num + right_front_num + left_rear_num+i] = T(1.0) -
- m_right_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
- T(m_right_rear_cloud[i].z));
- }
- return true;
- }
- };
- detect_wheel_ceres3d::detect_wheel_ceres3d(pcl::PointCloud<pcl::PointXYZ>::Ptr left_grid_cloud,
- pcl::PointCloud<pcl::PointXYZ>::Ptr right_grid_cloud)
- {
- m_left_model_cloud.clear();
- m_right_model_cloud.clear();
- m_left_model_cloud += *left_grid_cloud;
- m_right_model_cloud += *right_grid_cloud;
- mp_left_grid = nullptr;
- mp_right_grid = nullptr;
- // LOG(INFO) << "init model start";
- update_model();
- // LOG(INFO) <<"init model end";
- // save_model("/home/zx/zzw/catkin_ws/src/feature_extra");
- }
- // 根据点云与模型比例参数更新模型
- bool detect_wheel_ceres3d::update_model(float ratio)
- {
- float del_x=0.05;
- float del_y=0.03;
- float del_z=0.05;
- Eigen::Matrix3f delta=Eigen::MatrixXf::Identity(3,3);
- delta(0,0)=del_x*del_x;
- delta(1,1)=del_y*del_y;
- delta(2,2)=del_z*del_z;
- Eigen::Matrix3f delta_inv=delta.inverse();
- Eigen::Vector3f d(0,0,0.02);
- Eigen::MatrixXf ce=-0.5*((d).transpose()*delta_inv*(d));
- float cut_p=exp(ce(0,0));
- // std::cout << "1111" << std::endl;
- float resolution=0.01;
- if(mp_left_grid!=nullptr){
- delete mp_left_grid;
- mp_left_grid = nullptr;
- }
- if(mp_right_grid != nullptr){
- delete mp_right_grid;
- mp_right_grid = nullptr;
- }
- mp_left_grid=new HybridGrid(resolution);
- mp_right_grid=new HybridGrid(resolution);
- // 变换模型点云
- pcl::PointCloud<pcl::PointXYZ> t_left_model;
- t_left_model += m_left_model_cloud;
- pcl::PointCloud<pcl::PointXYZ> t_right_model;
- t_right_model += m_right_model_cloud;
- for (size_t i = 0; i < t_left_model.size(); i++)
- {
- t_left_model[i].x = t_left_model[i].x * ratio;
- t_left_model[i].y = t_left_model[i].y * ratio;
- t_left_model[i].z = t_left_model[i].z * ratio;
- }
- for (size_t i = 0; i < t_right_model.size(); i++)
- {
- t_right_model[i].x = t_right_model[i].x * ratio;
- t_right_model[i].y = t_right_model[i].y * ratio;
- t_right_model[i].z = t_right_model[i].z * ratio;
- }
- // LOG(INFO) << "--------------------------------------------------------------------------------------------------------";
- // LOG(INFO) << "mp_left_grid.resolution() = " << mp_left_grid->resolution();
- // LOG(INFO) << "t_left_model.size() = " <<t_left_model.size();
- for(int i=0;i<t_left_model.size();++i)
- {
- pcl::PointXYZ pt=t_left_model[i];
- Eigen::Vector3f u(pt.x,pt.y,pt.z);
- for(float x=pt.x-0.1;x<pt.x+0.1;x+=mp_left_grid->resolution())
- {
- for(float y=pt.y-0.1;y<pt.y+0.1;y+=mp_left_grid->resolution())
- {
- for(float z=pt.z-0.1;z<pt.z+0.1;z+=mp_left_grid->resolution())
- {
- Eigen::Vector3f p(x,y,z);
- Eigen::MatrixXf B=-0.5*((p-u).transpose()*delta_inv*(p-u));
- float prob=exp(B(0,0));
- if(prob>cut_p)
- prob=cut_p;
- Eigen::Array3i index=mp_left_grid->GetCellIndex(p);
- if(mp_left_grid->GetProbability(index)<prob){
- mp_left_grid->SetProbability(index,prob);
- }
- }
- }
- }
- }
- // std::cout << "3333" << std::endl;
- for(int i=0;i<t_right_model.size();++i)
- {
- pcl::PointXYZ pt=t_right_model[i];
- Eigen::Vector3f u(pt.x,pt.y,pt.z);
- for(float x=pt.x-0.1;x<pt.x+0.1;x+=mp_right_grid->resolution())
- {
- for(float y=pt.y-0.1;y<pt.y+0.1;y+=mp_right_grid->resolution())
- {
- for(float z=pt.z-0.1;z<pt.z+0.1;z+=mp_right_grid->resolution())
- {
- Eigen::Vector3f p(x,y,z);
- Eigen::MatrixXf B=-0.5*((p-u).transpose()*delta_inv*(p-u));
- float prob=exp(B(0,0));
- if(prob>cut_p)
- prob=cut_p;
- Eigen::Array3i index=mp_right_grid->GetCellIndex(p);
- if(mp_right_grid->GetProbability(index)<prob)
- mp_right_grid->SetProbability(index,prob);
- }
- }
- }
- }
- // LOG(INFO) << "=========================================================================================================-";
- return true;
- }
- void detect_wheel_ceres3d::save_model(std::string dir)
- {
- InterpolatedProbabilityGrid inter_grid(*mp_left_grid);
- pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_grid(new pcl::PointCloud<pcl::PointXYZRGB>);
- for(int x=0;x<mp_left_grid->grid_size();++x)
- {
- for(int y=0;y<mp_left_grid->grid_size();++y)
- {
- for(int z=0;z<mp_left_grid->grid_size();++z)
- {
- Eigen::Array3i index(x-mp_left_grid->grid_size()/2,
- y-mp_left_grid->grid_size()/2,z-mp_left_grid->grid_size()/2);
- Eigen::Vector3f pt=mp_left_grid->GetCenterOfCell(index);
- float prob=inter_grid.GetInterpolatedValue(double(pt[0]),double(pt[1]),double(pt[2]));
- if(prob>0.01)
- {
- Eigen::Vector3f pt=mp_left_grid->GetCenterOfCell(index);
- int rgb=int((prob-0.01)*255);
- pcl::PointXYZRGB point;
- point.x=pt[0];
- point.y=pt[1];
- point.z=pt[2];
- point.r=rgb;
- point.g=0;
- point.b=255-rgb;
- cloud_grid->push_back(point);
- }
- }
- }
- }
- InterpolatedProbabilityGrid right_grid(*mp_right_grid);
- pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_right_grid(new pcl::PointCloud<pcl::PointXYZRGB>);
- for(int x=0;x<mp_right_grid->grid_size();++x)
- {
- for(int y=0;y<mp_right_grid->grid_size();++y)
- {
- for(int z=0;z<mp_right_grid->grid_size();++z)
- {
- Eigen::Array3i index(x-mp_right_grid->grid_size()/2,
- y-mp_right_grid->grid_size()/2,z-mp_right_grid->grid_size()/2);
- Eigen::Vector3f pt=mp_right_grid->GetCenterOfCell(index);
- float prob=right_grid.GetInterpolatedValue(double(pt[0]),double(pt[1]),double(pt[2]));
- if(prob>0.01)
- {
- Eigen::Vector3f pt=mp_right_grid->GetCenterOfCell(index);
- int rgb=int((prob-0.01)*255);
- pcl::PointXYZRGB point;
- point.x=pt[0];
- point.y=pt[1];
- point.z=pt[2];
- point.r=rgb;
- point.g=0;
- point.b=255-rgb;
- cloud_right_grid->push_back(point);
- }
- }
- }
- }
- //std::cout<<" save model :"<<dir<<std::endl;
- //save_cloud_txt(cloud_grid,dir+"/left_model.txt");
- //save_cloud_txt(cloud_right_grid,dir+"/right_model.txt");
- }
- detect_wheel_ceres3d::~detect_wheel_ceres3d(){
- delete mp_left_grid;
- delete mp_right_grid;
- mp_left_grid= nullptr;
- mp_right_grid= nullptr;
- }
- bool detect_wheel_ceres3d::detect(std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> cloud_vec,
- Detect_result &detect_result, std::string &error_info)
- {
- error_info = "";
- //清理点云
- m_left_front_cloud.clear();
- m_right_front_cloud.clear();
- m_left_rear_cloud.clear();
- m_right_rear_cloud.clear();
- //重新计算点云,按方位分割
- //第一步,计算整体中心,主轴方向
- pcl::PointCloud<pcl::PointXYZ> cloud_all;
- for (int i = 0; i < cloud_vec.size(); ++i)
- {
- cloud_all += (*cloud_vec[i]);
- }
- // std::cout<<"cloud size: "<<cloud_all.size()<<std::endl;
- if (cloud_all.size() < 20)
- return false;
- Eigen::Vector4f centroid;
- pcl::compute3DCentroid(cloud_all, centroid);
- double center_x = centroid[0];
- double center_y = centroid[1];
-
- // printf("3dwheel x,y:%.3f, %.3f\n", center_x, center_y);
- // save_cloud_txt(cloud_all.makeShared(), "total_wheel.txt");
- //计算外接旋转矩形
- std::vector<cv::Point2f> points_cv;
- for (int i = 0; i < cloud_all.size(); ++i)
- {
- points_cv.push_back(cv::Point2f(cloud_all[i].x, cloud_all[i].y));
- }
- cv::RotatedRect rotate_rect = cv::minAreaRect(points_cv);
- //计算旋转矩形与X轴的夹角
- cv::Point2f vec;
- cv::Point2f vertice[4];
- rotate_rect.points(vertice);
- float len1 = pow(vertice[0].x - vertice[1].x, 2.0) + pow(vertice[0].y - vertice[1].y, 2.0);
- float len2 = pow(vertice[1].x - vertice[2].x, 2.0) + pow(vertice[1].y - vertice[2].y, 2.0);
- // 寻找长边,倾角为长边与x轴夹角
- if (len1 > len2)
- {
- vec.x = vertice[0].x - vertice[1].x;
- vec.y = vertice[0].y - vertice[1].y;
- }
- else
- {
- vec.x = vertice[1].x - vertice[2].x;
- vec.y = vertice[1].y - vertice[2].y;
- }
- float angle_x = 180.0 / M_PI * acos(vec.x / sqrt(vec.x * vec.x + vec.y * vec.y));
- // printf("rect theta: %.3f\n",angle_x);
- // 20211203 added by yct, 初始xy不准确,逻辑调整
- pcl::PointCloud<pcl::PointXYZ> t_cloud_left, t_cloud_right, t_cloud_front, t_cloud_rear;
- //第二步, 将每份点云旋转回去,计算点云重心所在象限
- for (int i = 0; i < cloud_vec.size(); ++i)
- {
- pcl::PointCloud<pcl::PointXYZ> cloud = (*cloud_vec[i]);
- Eigen::Affine3f traslation = Eigen::Affine3f::Identity();//初始化变换矩阵为单位矩阵
- // 平移
- traslation.translation() << -center_x, -center_y, 0.0;
- pcl::PointCloud<pcl::PointXYZ> translate_cloud;
- pcl::transformPointCloud(cloud, translate_cloud, traslation);
- // 旋转; Z 轴上旋转angle_x 弧度,Y轴上旋转0弧度
- Eigen::Affine3f rotation = Eigen::Affine3f::Identity();
- rotation.rotate(Eigen::AngleAxisf(-angle_x * M_PI / 180.0, Eigen::Vector3f::UnitZ()));
- pcl::PointCloud<pcl::PointXYZ> transformed_cloud;
- pcl::transformPointCloud(translate_cloud, transformed_cloud, rotation);
- //计算重心
- Eigen::Vector4f centroid;
- pcl::compute3DCentroid(transformed_cloud, centroid);
- double x = centroid[0];
- double y = centroid[1];
- //计算象限
- if (x > 0 && y > 0)
- {
- //第一象限
- m_left_front_cloud = cloud;
- t_cloud_left+=(m_left_front_cloud);
- t_cloud_front+=(m_left_front_cloud);
- }
- if (x > 0 && y < 0)
- {
- //第四象限
- m_right_front_cloud = cloud;
- t_cloud_right+=(m_right_front_cloud);
- t_cloud_front+=(m_right_front_cloud);
- }
- if (x < 0 && y > 0)
- {
- //第二象限
- m_left_rear_cloud = cloud;
- t_cloud_left+=(m_left_rear_cloud);
- t_cloud_rear+=(m_left_rear_cloud);
- }
- if (x < 0 && y < 0)
- {
- //第三象限
- m_right_rear_cloud = cloud;
- t_cloud_right+=(m_right_rear_cloud);
- t_cloud_rear+=(m_right_rear_cloud);
- }
- }
- // 20211203 added by yct, 重新计算xy
- Eigen::Vector4f centroid_left,centroid_right,centroid_front,centroid_rear;
- // 计算x
- pcl::compute3DCentroid(t_cloud_left, centroid_left);
- pcl::compute3DCentroid(t_cloud_right, centroid_right);
- // 计算y
- pcl::compute3DCentroid(t_cloud_front, centroid_front);
- pcl::compute3DCentroid(t_cloud_rear, centroid_rear);
- // LOG(WARNING)<<"x,y: "<<(centroid_left.x()+centroid_right.x())/2.0f<<", "<<(centroid_front.y()+centroid_rear.y())/2.0f;
-
- // 使用外部第一步优化产生的x,以及当前计算后的y作为初值
- // 多次优化,获取最佳优化结果
- // detect_result.cx = center_x;
- detect_result.cx = detect_result.cx;
- detect_result.cy = (centroid_front.y()+centroid_rear.y())/2.0f;
- detect_result.wheel_base = centroid_front.y() - centroid_rear.y() + 0.12; //std::max(len1,len2);
- // 已计算次数,初始传入值正常,之后solve函数会修改初始值,需要恢复角度单位为弧度
- int calc_count = 0;
- // double final_theta = 0;
- // 误差结构体,保存左前、右前、左后、右后、整体平均误差
- Loss_result loss_result;
- // 平均误差值,用于获取最小整体平均误差
- double avg_loss = 100;
- // 定义图像列数,控制图像大小
- int map_cols = 800;
- // 优化后图像行数,用于保存优化后结果图像
- int optimized_map_rows = 200;
- // 优化结果
- bool solve_result = false;
- double total_solve_time = 0;
- bool stop_sign = false;
- Detect_result t_detect_result = detect_result;
- // 寻找最小loss值对应的初始旋转角
- // LOG(WARNING) <<cloud_all.size()<< ", car angle: "<<t_detect_result.theta<<", "<<(-angle_x ) * M_PI / 180.0;
- // t_detect_result.theta = (-angle_x ) * M_PI / 180.0;
- Loss_result t_loss_result;
- t_loss_result.total_avg_loss = 1000;
- //输出角度已变化,需恢复成弧度
- if (calc_count > 0)
- {
- t_detect_result.front_theta *= (-M_PI) / 180.0;
- }
- std::string t_error_info;
- bool current_result = Solve(t_detect_result, t_loss_result, t_error_info);
- error_info = t_error_info;
- // std::cout<<"current_result: "<<current_result<<std::endl;
- if (current_result)
- {
- avg_loss = t_loss_result.total_avg_loss;
- // final_theta = -input_vars[2] * M_PI / 180.0;
- detect_result = t_detect_result;
- detect_result.loss = t_loss_result;
- solve_result = current_result;
- loss_result = t_loss_result;
- }
- detect_result.success = solve_result;
- return solve_result;
- }
- void detect_wheel_ceres3d::get_costs(double* variable,double &lf, double &rf, double &lr, double &rr)
- {
- double losses[4]={0};
- double cx = variable[0];
- double cy = variable[1];
- double theta = variable[2];
- double length = variable[3];
- double width = variable[4];
- double theta_front = variable[5];
- //整车旋转
- Eigen::Rotation2D<double> rotation(theta);
- Eigen::Matrix<double, 2, 2> rotation_matrix = rotation.toRotationMatrix();
- //左前偏移
- Eigen::Matrix<double, 2, 1> wheel_center_normal_left_front(length / 2.0, width / 2.0);
- //右前偏移
- Eigen::Matrix<double, 2, 1> wheel_center_normal_right_front(length / 2.0, -width / 2.0);
- //左后偏移
- Eigen::Matrix<double, 2, 1> wheel_center_normal_left_rear(-length / 2.0, width / 2.0);
- //右后偏移
- Eigen::Matrix<double, 2, 1> wheel_center_normal_right_rear(-length / 2.0, -width / 2.0);
- //前轮旋转
- Eigen::Rotation2D<double> rotation_front(theta_front);
- Eigen::Matrix<double, 2, 2> rotation_matrix_front = rotation_front.toRotationMatrix();
- InterpolatedProbabilityGrid left_interpolated_grid(*mp_left_grid);
- InterpolatedProbabilityGrid right_interpolated_grid(*mp_right_grid);
- //左前轮
- int left_front_num = m_left_front_cloud.size();
- m_left_front_transformed_cloud.clear();
- for (int i = 0; i < m_left_front_cloud.size(); ++i)
- {
- const Eigen::Matrix<double, 2, 1> point((double(m_left_front_cloud[i].x) - cx),
- (double(m_left_front_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_left_front;
- //旋转
- const Eigen::Matrix<double, 2, 1> point_rotation = rotation_matrix_front * tanslate_point;
- losses[0] += 1.0 - left_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
- double(m_left_front_cloud[i].z));
- m_left_front_transformed_cloud.push_back(pcl::PointXYZ(point_rotation[0],point_rotation[1],m_left_front_cloud[i].z));
- }
- //右前轮
- int right_front_num = m_right_front_cloud.size();
- m_right_front_transformed_cloud.clear();
- for (int i = 0; i < m_right_front_cloud.size(); ++i)
- {
- const Eigen::Matrix<double, 2, 1> point((double(m_right_front_cloud[i].x) - cx),
- (double(m_right_front_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_right_front;
- //旋转
- const Eigen::Matrix<double, 2, 1> point_rotation = rotation_matrix_front * tanslate_point;
- losses[1]+= 1.0 - right_interpolated_grid.GetInterpolatedValue(point_rotation[0],point_rotation[1],
- double(m_right_front_cloud[i].z));
- m_right_front_transformed_cloud.push_back(pcl::PointXYZ(point_rotation[0],point_rotation[1],
- double(m_right_front_cloud[i].z)));
- }
- //左后轮
- int left_rear_num = m_left_rear_cloud.size();
- m_left_rear_transformed_cloud.clear();
- for (int i = 0; i < m_left_rear_cloud.size(); ++i)
- {
- const Eigen::Matrix<double, 2, 1> point((double(m_left_rear_cloud[i].x) - cx),
- (double(m_left_rear_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_left_rear;
- losses[2] += 1.0 -
- left_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
- double(m_left_rear_cloud[i].z));
- m_left_rear_transformed_cloud.push_back(pcl::PointXYZ(tanslate_point[0],tanslate_point[1],
- double(m_left_rear_cloud[i].z)));
- }
- //右后轮
- int right_rear_num = m_right_rear_cloud.size();
- m_right_rear_transformed_cloud.clear();
- for (int i = 0; i < m_right_rear_cloud.size(); ++i)
- {
- const Eigen::Matrix<double, 2, 1> point((double(m_right_rear_cloud[i].x) - cx),
- (double(m_right_rear_cloud[i].y) - cy));
- //减去经过车辆旋转计算的左前中心
- const Eigen::Matrix<double, 2, 1> tanslate_point = rotation_matrix * point - wheel_center_normal_right_rear;
- losses[3]+= 1.0 -
- right_interpolated_grid.GetInterpolatedValue(tanslate_point[0],tanslate_point[1],
- double(m_right_rear_cloud[i].z));
- m_right_rear_transformed_cloud.push_back(pcl::PointXYZ(tanslate_point[0],tanslate_point[1],
- double(m_right_rear_cloud[i].z)));
- }
- lf=losses[0];
- rf=losses[1];
- lr =losses[2];
- rr =losses[3];
- }
- void detect_wheel_ceres3d::save_debug_data(std::string dir )
- {
- ::save_cloud_txt(m_left_front_transformed_cloud.makeShared(),dir+"/left_front_tranformed.txt");
- ::save_cloud_txt(m_right_front_transformed_cloud.makeShared(),dir+"/right_front_tranformed.txt");
- ::save_cloud_txt(m_left_rear_transformed_cloud.makeShared(),dir+"/left_rear_tranformed.txt");
- ::save_cloud_txt(m_right_rear_transformed_cloud.makeShared(),dir+"/right_rear_tranformed.txt");
- }
- // 外接矩形估算车轮宽度,以此调整模型比例
- bool detect_wheel_ceres3d::wheel_size_estimate(double &wheel_width, double &wheel_length, double car_angle, float &ratio)
- {
- // 分别对四轮寻找外接矩形
- int rect_res = 0;
- cv::RotatedRect rects[4]; // t_left_front_rect, t_right_front_rect, t_left_rear_rect, t_right_rear_rect;
- double rot_angles[4], lengths[4], widths[4];
- rect_res += get_wheel_rect(m_left_front_cloud, rects[0], rot_angles[0], lengths[0], widths[0]) ? 0 : 1;
- rect_res += get_wheel_rect(m_right_front_cloud, rects[1], rot_angles[1], lengths[1], widths[1]) ? 0 : 1;
- rect_res += get_wheel_rect(m_left_rear_cloud, rects[2], rot_angles[2], lengths[2], widths[2]) ? 0 : 1;
- rect_res += get_wheel_rect(m_right_rear_cloud, rects[3], rot_angles[3], lengths[3], widths[3]) ? 0 : 1;
- // 只允许一个异常轮胎
- if(rect_res > 1)
- {
- // std::cout << "异常轮胎过多 " << rect_res << std::endl;
- return false;
- }
- // 计算轮宽
- double avg_width = 0.0;
- double avg_length = 0.0;
- for (size_t i = 2; i < 4; i++)
- {
- avg_width += widths[i];
- avg_length += lengths[i];
- }
- avg_width /= 2.0;
- avg_length /= 2.0;
- // std::cout << "avg width: " << avg_width << ", avg length: " << avg_length << std::endl;
- // 以投影方式计算轮宽
- Eigen::Vector2d car_angle_vec(cos(-car_angle), sin(-car_angle));
- double left_min=INT_MAX, left_max=-INT_MAX, right_min=INT_MAX, right_max=-INT_MAX;
- if(m_left_rear_cloud.size()==0 || m_right_rear_cloud.size()==0)
- {
- ratio = 1.0f;
- return false;
- }
- for (size_t i = 0; i < m_left_rear_cloud.size(); i++)
- {
- Eigen::Vector2d point_vec(m_left_rear_cloud[i].x, m_left_rear_cloud[i].y);
- double res = sqrt(point_vec.squaredNorm() - pow(car_angle_vec.dot(point_vec),2));
- // std::cout<<"lres: "<<res<<std::endl;
- if(res<left_min)
- left_min=res;
- if(res>left_max)
- left_max=res;
- }
- for (size_t i = 0; i < m_right_rear_cloud.size(); i++)
- {
- Eigen::Vector2d point_vec(m_right_rear_cloud[i].x, m_right_rear_cloud[i].y);
- double res = sqrt(point_vec.squaredNorm() - pow(car_angle_vec.dot(point_vec),2));
- // std::cout<<"rres: "<<res<<std::endl;
- if(res<right_min)
- right_min=res;
- if(res>right_max)
- right_max=res;
- }
- double new_wheel_width = (left_max+right_max-left_min-right_min)/2.0;
- // std::cout << "avg width: " << avg_width << ", new width: " << new_wheel_width << std::endl;
-
- wheel_width = new_wheel_width;
- wheel_length = avg_length;
- // ratio = 1.0f;
- // 轮宽范围,实际0.185-0.3,通常会少0.03-0.04,(新方法不会少),因此设定范围0.175-0.275
- // 比例以半径0.64为模板,范围0.6-0.7
- if(wheel_width<0.18||wheel_width>0.3)
- {
- ratio = 1.0f;
- }else{
- float t_model_ratio = float((0.6 + ((wheel_width - 0.175) * 0.1 / 0.1)) / 0.64);
- t_model_ratio = std::max(0.6f/0.64f, t_model_ratio);
- t_model_ratio = std::min(0.7f/0.64f, t_model_ratio);
- ratio = 1.0f / t_model_ratio;
- }
- return true;
- }
- // 使用外接矩形,车轮越大,多条线照到车轮的概率与车轮半径都越大,导致外接矩形向内侧收拢的趋势更明显,轴距偏小得越厉害
- bool detect_wheel_ceres3d::wheebase_estimate(double &wheelbase, double &wheel_width, double &wheel_length)
- {
- // 分别对四轮寻找外接矩形
- int rect_res = 0;
- cv::RotatedRect rects[4]; // t_left_front_rect, t_right_front_rect, t_left_rear_rect, t_right_rear_rect;
- double rot_angles[4], lengths[4], widths[4];
- rect_res += get_wheel_rect(m_left_front_cloud, rects[0], rot_angles[0], lengths[0], widths[0]) ? 0 : 1;
- rect_res += get_wheel_rect(m_right_front_cloud, rects[1], rot_angles[1], lengths[1], widths[1]) ? 0 : 1;
- rect_res += get_wheel_rect(m_left_rear_cloud, rects[2], rot_angles[2], lengths[2], widths[2]) ? 0 : 1;
- rect_res += get_wheel_rect(m_right_rear_cloud, rects[3], rot_angles[3], lengths[3], widths[3]) ? 0 : 1;
- // 只允许一个异常轮胎
- if(rect_res > 1)
- {
- // std::cout << "异常轮胎过多 " << rect_res << std::endl;
- return false;
- }
- // 计算轮宽
- double avg_width = 0.0;
- double avg_length = 0.0;
- for (size_t i = 2; i < 4; i++)
- {
- avg_width += widths[i];
- avg_length += lengths[i];
- }
- avg_width /= 2.0;
- avg_length /= 2.0;
- // std::cout << "avg width: " << avg_width << ", avg length: " << avg_length << std::endl;
- wheel_width = avg_width;
- wheel_length = avg_length;
- // 检查角度,后轮不可超过5度,前轮不可超过30度
- int rear_limit_count = 0, front_limit_count = 0;
- int rear_abnormal_index = -1, front_abnormal_index = -1;
- for (size_t i = 2; i < 4; i++)
- {
- if (90-rot_angles[i] > 5)
- {
- // std::cout << "后轮角度 " << rot_angles[i] << std::endl;
- rear_limit_count++;
- rear_abnormal_index = i;
- }
- // else
- // {
- // // 后轮记录
- // rear_index = i;
- // }
- }
- for (size_t i = 0; i < 2; i++)
- {
- if (90-rot_angles[i] > 30)
- {
- // std::cout << "前轮角度 " << rot_angles[i] << std::endl;
- front_limit_count++;
- front_abnormal_index = i;
- }
- // else
- // {
- // // 前轮记录
- // front_index = i;
- // }
- }
- // 异常矩形超过一个
- if (rear_limit_count + front_limit_count > 1)
- {
- // std::cout << "异常矩形过多 " << rear_limit_count<<", "<<front_limit_count << std::endl;
- return false;
- }
- // 剔除可能异常数据,计算轴距
- Eigen::Vector2d wb_vector;
- if (rear_abnormal_index != 2 && front_abnormal_index != 0)
- {
- wb_vector << rects[0].center.x - rects[2].center.x, rects[0].center.y - rects[2].center.y;
- }else if(rear_abnormal_index != 3 && front_abnormal_index != 1){
- wb_vector << rects[1].center.x - rects[3].center.x, rects[1].center.y - rects[3].center.y;
- }else{
- return false;
- }
- wheelbase = wb_vector.norm();
- double alpha = 0.2;
- wheelbase = wheelbase + alpha * (wheelbase - 2.55);
- return true;
- }
- bool detect_wheel_ceres3d::get_wheel_rect(pcl::PointCloud<pcl::PointXYZ> cloud, cv::RotatedRect &rect, double &theta, double &length, double &width)
- {
- std::vector<cv::Point2f> t_point_vec;
- for (size_t i = 0; i < cloud.size(); i++)
- {
- t_point_vec.push_back(cv::Point2f(cloud[i].x, cloud[i].y));
- }
- if(t_point_vec.size()<=0)
- return false;
- rect = cv::minAreaRect(t_point_vec);
- length = std::max(rect.size.width, rect.size.height);
- width = std::min(rect.size.width, rect.size.height);
- // 车轮范围,轮胎直径600-800,宽度165-245
- if (length < 0.3 || length >0.9 || width < 0.1 || width > 0.3)
- {
- // std::cout << "车轮范围越界 0.3-0.9, 0.1-0.3: "<<length<<", "<<width << std::endl;
- return false;
- }
- // 获得真实旋转角,前轮y更大
- cv::Point2f corners[4];
- rect.points(corners);
- for (size_t i = 0; i < 4; i++)
- {
- for (size_t j = 0; j < 3-i; j++)
- {
- if(corners[j].y > corners[j+1].y)
- {
- std::swap(corners[j], corners[j + 1]);
- }
- }
- }
- Eigen::Vector2d rear2front;
- rear2front << corners[2].x + corners[3].x - corners[0].x - corners[1].x, corners[2].y + corners[3].y - corners[0].y - corners[1].y;
- rear2front /= 2;
- theta = std::atan2(rear2front.y(), rear2front.x()) * 180.0 / M_PI;
- return true;
- }
- bool detect_wheel_ceres3d::Solve(Detect_result &detect_result, Loss_result &loss_result, std::string &error_info)
- {
- // 20220118 added by yct. 计算比例传入模型
- float model_ratio = 1.0f;
- // bool ws_res = wheel_size_estimate(detect_result.single_wheel_width, detect_result.single_wheel_length, detect_result.theta, model_ratio);
- // std::cout << "change cloud with ratio: " << model_ratio << std::endl;
- double cx=detect_result.cx;
- double cy=detect_result.cy;
- double init_theta=detect_result.theta;
- double init_wheel_base=2.7;
- if(detect_result.wheel_base>2.55 && detect_result.wheel_base<3.2)
- init_wheel_base=detect_result.wheel_base;
- double init_width=1.85;
- double init_theta_front=0*M_PI/180.0;
- double variable[] = {cx, cy, init_theta, init_wheel_base, init_width, init_theta_front};
- // printf("init solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
- // variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);
- // 第二部分:构建寻优问题
- ceres::Problem problem;
- CostFunctor3d *cost_func = new CostFunctor3d(m_left_front_cloud,m_right_front_cloud,m_left_rear_cloud,m_right_rear_cloud,
- *mp_left_grid,*mp_right_grid, model_ratio);
- //使用自动求导,将之前的代价函数结构体传入,第一个1是输出维度,即残差的维度,第二个1是输入维度,即待寻优参数x的维度。
- ceres::CostFunction* cost_function =new
- ceres::AutoDiffCostFunction<CostFunctor3d, ceres::DYNAMIC, 6>(
- cost_func,
- m_left_front_cloud.size()+m_right_front_cloud.size()+m_left_rear_cloud.size()+m_right_rear_cloud.size());
- problem.AddResidualBlock(cost_function, NULL, variable); //向问题中添加误差项,本问题比较简单,添加一个就行。
- //第三部分: 配置并运行求解器
- ceres::Solver::Options options;
- // options.use_nonmonotonic_steps=false;
- options.linear_solver_type = ceres::DENSE_QR; //配置增量方程的解法
- //options.logging_type = ceres::LoggingType::SILENT;
- options.max_num_iterations=500;
- options.num_threads=1;
- options.minimizer_progress_to_stdout = false;//输出到cout
- ceres::Solver::Summary summary;//优化信息
- ceres::Solve(options, &problem, &summary);//求解!!!
- // printf("after solve x:%.3f y: %.3f wheel:%.3f width:%.3f theta : %.3f front theta: %.3f\n",
- // variable[0], variable[1], variable[3], variable[4], variable[2], variable[5]);
- double loss=summary.final_cost/(m_left_front_cloud.size()+m_right_front_cloud.size()+m_left_rear_cloud.size()+m_right_rear_cloud.size());
- detect_result.cx=variable[0];
- detect_result.cy=variable[1];
- detect_result.theta=(-variable[2])*180.0/M_PI;
- detect_result.wheel_base=variable[3];
- detect_result.width=variable[4];
- detect_result.front_theta=-(variable[5]*180.0/M_PI);
- if(detect_result.theta>180.0)
- detect_result.theta=detect_result.theta-180.0;
- if(detect_result.theta<0)
- detect_result.theta+=180.0;
- if(summary.iterations.size()<=1){
- error_info.append(std::string("仅迭代一轮,优化异常"));
- return false;
- }
- if(summary.iterations[summary.iterations.size()-1].iteration<=1){
- error_info.append(std::string("最终仅迭代一轮,优化异常"));
- return false;
- }
- /*printf("it : %d ,summary loss: %.5f \n",
- summary.iterations.size(),loss);*/
- if (detect_result.width < 1.25 || detect_result.width > 1.95 || detect_result.wheel_base > 3.15 || detect_result.wheel_base < 2.200)
- {
- error_info.append(std::string("宽度(1.25, 1.950) 轴距(2.20, 3.15): ").append(
- std::to_string(detect_result.width).append(", ").append(
- std::to_string(detect_result.wheel_base)).append("\t")));
- return false;
- }
- if(detect_result.theta > 120 || detect_result.theta < 60)
- {
- error_info.append("车身角度错误 ").append(std::to_string(detect_result.theta)).append("\t");
- // LOG(WARNING) <<"总角度错误 "<<detect_result.theta;
- return false;
- }
- if(fabs(detect_result.front_theta)>35)
- {
- error_info.append("前轮角度错误 ").append(std::to_string(detect_result.front_theta)).append("\t");
- return false;
- }
- // 将loss传出
- if(cost_func!=nullptr)
- {
- double costs_lf, costs_rf, costs_lr, costs_rr;
- get_costs(variable,costs_lf, costs_rf, costs_lr, costs_rr);
- loss_result.lf_loss = costs_lf/float(m_left_front_cloud.size()+1e-6);
- loss_result.rf_loss = costs_rf/float(m_right_front_cloud.size()+1e-6);
- loss_result.lb_loss = costs_lr/float(m_left_rear_cloud.size()+1e-6);
- loss_result.rb_loss = costs_rr/float(m_right_rear_cloud.size()+1e-6);
- loss_result.total_avg_loss = loss;
- detect_result.loss=loss_result;
- if(loss_result.lf_loss>0.4 || loss_result.rf_loss>0.4
- ||loss_result.lb_loss>0.4||loss_result.rb_loss>0.4)
- {
- error_info.append("loss过大 lf").append(std::to_string(loss_result.lf_loss)).append(",rf").append(std::to_string(loss_result.rf_loss)).append(", lr").
- append(std::to_string(loss_result.lb_loss)).append(",rb").append(std::to_string(loss_result.rb_loss));
- return false;
- }
- }
- else
- {
- return false;
- }
- return true;
- }
|