|
@@ -0,0 +1,510 @@
|
|
|
+/**
|
|
|
+ * \file mark_extract.cpp
|
|
|
+ * \brief 简要介绍
|
|
|
+ * \details 详细说明
|
|
|
+ * \author lenotary
|
|
|
+ * \version 1.0
|
|
|
+ * \date 2021/11/24
|
|
|
+ * \pre 先决条件。(有的话才添加。)
|
|
|
+ * \bug 存在的bug。(有的话才添加,注明“还未发现”也可以。)
|
|
|
+ * \warning 警告。(有的话才添加。)
|
|
|
+ * \copyright 版权声明。(通常只写遵循什么协议,版权详细内容应放在LICENSE文件中,并且应该与LICENSE文件的内容统一,不能自相矛盾。)
|
|
|
+ * \since 一些历史情况记录。(有的话才添加。)
|
|
|
+ */
|
|
|
+
|
|
|
+//
|
|
|
+// Created by lenotary on 2021/11/24.
|
|
|
+//
|
|
|
+
|
|
|
+#include "mark_extract.h"
|
|
|
+
|
|
|
+MarkExtract::MarkExtract(ros::NodeHandle &nh, ros::NodeHandle &nhPrivate) : m_iNh_(nh), m_iNhPrivate_(nhPrivate) {
|
|
|
+
|
|
|
+ nhPrivate.getParam("image_width", m_nWidth_);
|
|
|
+ nhPrivate.getParam("image_height", m_nHeight_);
|
|
|
+ nhPrivate.getParam("threshold", m_nThresh_);
|
|
|
+ nhPrivate.getParam("point_diameter", m_dPointSize_);
|
|
|
+ nhPrivate.getParam("point_distance", m_dPointDistance_);
|
|
|
+
|
|
|
+ m_dMinPointArea_ = std::pow(m_dPointSize_ / 2,2) * M_PI / 2 * 15 * m_nWidth_;
|
|
|
+ m_dMinPointWidth_ = m_dPointSize_ * m_nWidth_ * 0.26;
|
|
|
+ ROS_INFO("min %f %f",m_dMinPointArea_,m_dMinPointWidth_);
|
|
|
+ XmlRpc::XmlRpcValue scanner_params;
|
|
|
+ std::vector<double> K, D;
|
|
|
+ nhPrivate.param<std::vector<double>>("camera_matrix/data", K, std::vector<double>());
|
|
|
+ nhPrivate.param<std::vector<double>>("distortion_coefficients/data", D, std::vector<double>());
|
|
|
+ m_mK_ = (cv::Mat_<double>(3, 3) << K[0], K[1], K[2], K[3], K[4], K[5], K[6], K[7], K[8]);
|
|
|
+ m_mD_ = (cv::Mat_<double>(5, 1) << D[0], D[1], D[2], D[3], D[4]);
|
|
|
+ const double alpha = 1;
|
|
|
+ cv::Size imageSize(m_nWidth_, m_nHeight_);
|
|
|
+ m_mNewCameraMatrix_ = getOptimalNewCameraMatrix(m_mK_, m_mD_, imageSize, alpha, imageSize, 0);
|
|
|
+
|
|
|
+// cv::Mat UndistortImage;
|
|
|
+// cv::undistort(RawImage, UndistortImage, m_mK_, m_mD_, m_mK_);
|
|
|
+// cv::undistort(RawImage, UndistortImage, K, D, NewCameraMatrix);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void MarkExtract::process(cv::Mat &image) {
|
|
|
+ cv::Size imageSize(m_nWidth_, m_nHeight_);
|
|
|
+ cv::undistort(image, m_mDistortionImage, m_mK_, m_mD_, m_mK_);
|
|
|
+// cv::undistort(image, UndistortImage, K, D, NewCameraMatrix);
|
|
|
+ cv::Mat gray, binaryImage;
|
|
|
+ cv::cvtColor(m_mDistortionImage, gray, cv::COLOR_RGB2GRAY); //要二值化图像,要先进行灰度化处理
|
|
|
+ threshold(gray, m_mBinary, m_nThresh_, 255, cv::THRESH_BINARY);
|
|
|
+// int s = 3 * 2 + 1;
|
|
|
+// cv::Mat structureElement = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(s, s), cv::Point(-1, -1)); //创建结构元
|
|
|
+// dilate(m_mBinary, m_mBinary, structureElement, cv::Point(-1, -1), 1); //调用膨胀API
|
|
|
+
|
|
|
+//新方法获取联通区域中心店
|
|
|
+ cv::Mat outImage, stats, centroids;
|
|
|
+ int count = connectedComponentsWithStats(m_mBinary, outImage, stats, centroids, 8, CV_16U);
|
|
|
+// cv::RNG rng(time(nullptr));
|
|
|
+// std::vector<cv::Vec3b> colors;
|
|
|
+// for (int i = 0; i < count; i++) {
|
|
|
+// cv::Vec3b vec3 = cv::Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
|
|
|
+// colors.push_back(vec3);
|
|
|
+// }
|
|
|
+ cv::Mat dst = cv::Mat::zeros(gray.size(), gray.type());
|
|
|
+ int width = dst.cols;
|
|
|
+ int height = dst.rows;
|
|
|
+ std::vector<cv::Point2d> mc;
|
|
|
+ for (int i = 1; i < count; i++) {
|
|
|
+ //找到连通域的质心
|
|
|
+ cv::Point2d center;
|
|
|
+ center.x = centroids.at<double>(i, 0);
|
|
|
+ center.y = centroids.at<double>(i, 1);
|
|
|
+ //矩形的点和边
|
|
|
+ int x = stats.at<int>(i, cv::CC_STAT_LEFT);
|
|
|
+ int y = stats.at<int>(i, cv::CC_STAT_TOP);
|
|
|
+ int w = stats.at<int>(i, cv::CC_STAT_WIDTH);
|
|
|
+ int h = stats.at<int>(i, cv::CC_STAT_HEIGHT);
|
|
|
+ int area = stats.at<int>(i, cv::CC_STAT_AREA) / 10;
|
|
|
+// ROS_INFO("info i %d : %d %d %d %d %d ",i,w,h,x,y,area);
|
|
|
+// ROS_INFO("cc %f", 5 / 0.015/ m_nWidth_);
|
|
|
+
|
|
|
+ if (std::abs(w - h) < 5 and w > m_dMinPointWidth_ and area > m_dMinPointArea_) { // 5 / std::pow(m_dPointSize_ / 2,2) * M_PI / 2 * m_nWidth_ / m_nWidth_
|
|
|
+
|
|
|
+ mc.push_back(center);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //绘制中心点
|
|
|
+// circle(image, center, 1, cv::Scalar(0, 255, 122), 2, 8, 0);
|
|
|
+ //外接矩形
|
|
|
+// cv::Rect rect(x, y, w, h);
|
|
|
+// rectangle(image, rect, colors[i], 1, 8, 0);
|
|
|
+ //putText(image, format("%d", i), Point(center_x, center_y), FONT_HERSHEY_COMPLEX, 0.5, Scalar(0, 0, 255), 1);
|
|
|
+ }
|
|
|
+// ROS_INFO("size of center %ld",mc.size());
|
|
|
+// for (auto p: mc) {
|
|
|
+// printPoint(p, "pp");
|
|
|
+// }
|
|
|
+
|
|
|
+//原始方法获取 联通区域中心点
|
|
|
+/* std::vector<std::vector<cv::Point> > contours;//contours的类型,双重的vector
|
|
|
+ std::vector<cv::Vec4i> hierarchy;//Vec4i是指每一个vector元素中有四个int型数据。
|
|
|
+
|
|
|
+
|
|
|
+ findContours(binaryImage.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
|
|
|
+ std::vector<cv::Moments> mu(contours.size());
|
|
|
+ for (int i = 0; i < contours.size(); i++) {
|
|
|
+ mu[i] = moments(contours[i], false);
|
|
|
+ }
|
|
|
+ /// 计算中心矩:
|
|
|
+ std::vector<cv::Point2f> mc;
|
|
|
+ for (int i = 0; i < contours.size(); i++) {
|
|
|
+
|
|
|
+ double x = mu[i].m10 / mu[i].m00;
|
|
|
+ double y = mu[i].m01 / mu[i].m00;
|
|
|
+ if (x > 0 and x < 10000 and y > 0 and y < 10000) {
|
|
|
+ mc.emplace_back(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(mc.size() > 16){
|
|
|
+ return;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ auto allPints = DBSCAN(mc,200,3);
|
|
|
+ m_vIds.clear();
|
|
|
+ m_vTS.clear();
|
|
|
+ m_vRS.clear();
|
|
|
+
|
|
|
+ for(auto map_iter: allPints){
|
|
|
+ cv::Mat r,t;
|
|
|
+ auto points = removeOutlier(map_iter.second,500,3);
|
|
|
+
|
|
|
+ if(points.size() < 5){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto id = getIdAndPose(points,r,t);
|
|
|
+ m_vIds.push_back(id);
|
|
|
+ m_vTS.push_back(t);
|
|
|
+ m_vRS.push_back(r);
|
|
|
+ }
|
|
|
+
|
|
|
+// ROS_INFO("id %d",cc);
|
|
|
+// cv::imshow("aa", m_mBinary_);
|
|
|
+// cv::waitKey(10);
|
|
|
+ /// 绘制轮廓
|
|
|
+// cv::Mat drawing = cv::Mat::zeros(binaryImage.size(), CV_8UC1);
|
|
|
+// for (int i = 0; i < cc.size(); i++) {
|
|
|
+// cv::Scalar color = cv::Scalar(255);
|
|
|
+//// drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, cv::Point());
|
|
|
+// circle(drawing, cc[i], 4, color, -1, 8, 0);
|
|
|
+// }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int MarkExtract::getIdAndPose(std::vector<cv::Point2d> &mc,cv::Mat &r,cv::Mat &t) {
|
|
|
+ bool getTruePoint{false};
|
|
|
+ std::vector<PointDisSet> pointDisList;
|
|
|
+ std::vector<std::vector<cv::Point2d>> allPoints;
|
|
|
+
|
|
|
+ cv::Point2d A, B, C, D, E;
|
|
|
+
|
|
|
+ PointDisSet pointDis;
|
|
|
+ cv::Point2d image_center(0,0);
|
|
|
+
|
|
|
+ std::vector<cv::Point2d> cameraPoints;
|
|
|
+ for (auto p: mc) {
|
|
|
+ auto cameraP = pixToCamera(p);
|
|
|
+ cameraPoints.push_back(cameraP);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < cameraPoints.size(); ++i) {
|
|
|
+ for (int j = 0; j < cameraPoints.size(); ++j) {
|
|
|
+ auto point1 = cameraPoints[i];
|
|
|
+ auto point2 = cameraPoints[j];
|
|
|
+// auto dis = std::hypot(point1.x - point2.x, point1.y - point2.y);
|
|
|
+ auto dis = distanceTwoPoint(point1,point2);
|
|
|
+ pointDisList.emplace_back(dis,point1,point2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int count = 1;
|
|
|
+ while (not getTruePoint and count < pointDisList.size()){
|
|
|
+ count ++;
|
|
|
+
|
|
|
+ double maxDis{0};
|
|
|
+ for(const auto& twoPoint: pointDisList){
|
|
|
+ if(twoPoint.mDis > maxDis){
|
|
|
+ maxDis = twoPoint.mDis;
|
|
|
+ pointDis = twoPoint;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for(auto& twoPoint: pointDisList){
|
|
|
+ if(twoPoint.mDis == maxDis){
|
|
|
+ twoPoint.mDis = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ cv::Point2d center, origin;
|
|
|
+ maxDis = 0;
|
|
|
+ center.x = (pointDis.mP1.x + pointDis.mP2.x) / 2.0;
|
|
|
+ center.y = (pointDis.mP1.y + pointDis.mP2.y) / 2.0;
|
|
|
+ for (const auto &p: cameraPoints) {
|
|
|
+ auto dis = distanceTwoPoint(p,center);
|
|
|
+// auto dis = std::hypot(p.x - center.x, p.y - center.y);
|
|
|
+ if (dis > maxDis and p!=pointDis.mP1 and p !=pointDis.mP2) {
|
|
|
+ origin = p;
|
|
|
+ maxDis = dis;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::vector<cv::Point2d> out;
|
|
|
+
|
|
|
+ double angle1 = std::atan2(pointDis.mP1.y - origin.y, pointDis.mP1.x - origin.x) * 180 / 3.1415926;
|
|
|
+ double angle2 = std::atan2(pointDis.mP2.y - origin.y, pointDis.mP2.x - origin.x) * 180 / 3.1415926;
|
|
|
+ E = origin;
|
|
|
+ if(angle1 * angle2 > 0){
|
|
|
+ if (angle1 > angle2) {
|
|
|
+ A = pointDis.mP1;
|
|
|
+ B = pointDis.mP2;
|
|
|
+ } else {
|
|
|
+ A = pointDis.mP2;
|
|
|
+ B = pointDis.mP1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if(angle1 > angle2) {
|
|
|
+ if(angle1 - angle2 < 180){
|
|
|
+ A = pointDis.mP1;
|
|
|
+ B = pointDis.mP2;
|
|
|
+ }else{
|
|
|
+ A = pointDis.mP2;
|
|
|
+ B = pointDis.mP1;
|
|
|
+ }
|
|
|
+ }else if(angle2 > angle1 ){
|
|
|
+ if(angle2 - angle1 < 180){
|
|
|
+ A = pointDis.mP2;
|
|
|
+ B = pointDis.mP1;
|
|
|
+ }else{
|
|
|
+ A = pointDis.mP1;
|
|
|
+ B = pointDis.mP2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ double x_length_x = (B.x - E.x) / 3.0;
|
|
|
+ double x_length_y = (B.y - E.y) / 3.0;
|
|
|
+ double y_length_x = (A.x - E.x) / 3.0;
|
|
|
+ double y_length_y = (A.y - E.y) / 3.0;
|
|
|
+ for (int i = 0; i < 4; ++i) {
|
|
|
+ std::vector<cv::Point2d> colPoints;
|
|
|
+ for (int j = 0; j < 4; ++j) {
|
|
|
+ cv::Point2d p;
|
|
|
+ p.x = E.x + x_length_x * i + y_length_x * j;
|
|
|
+ p.y = E.y + x_length_y * i + y_length_y * j;
|
|
|
+// out.push_back(cameraToPix(p));
|
|
|
+ colPoints.push_back(p);
|
|
|
+ }
|
|
|
+ allPoints.push_back(colPoints);
|
|
|
+ }
|
|
|
+ C = allPoints[2][3];
|
|
|
+ D = allPoints[3][2];
|
|
|
+
|
|
|
+ C = getRecentPoint(A,B,C,cameraPoints);
|
|
|
+ D = getRecentPoint(A,B,D,cameraPoints);
|
|
|
+ if(C.x == -100000 or D.x == -100000 or C == D){
|
|
|
+ getTruePoint = false;
|
|
|
+ }else{
|
|
|
+ getTruePoint = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ auto cPix = cameraToPix(C);
|
|
|
+ auto dPix = cameraToPix(D);
|
|
|
+ }
|
|
|
+ if(not getTruePoint){
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ int id{0};
|
|
|
+ id += (getRecentPoint(A,B,allPoints[1][0],cameraPoints).x > -100000) << 0;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[2][0],cameraPoints).x > -100000) << 1;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[0][1],cameraPoints).x > -100000) << 2;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[1][1],cameraPoints).x > -100000) << 3;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[2][1],cameraPoints).x > -100000) << 4;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[3][1],cameraPoints).x > -100000) << 5;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[0][2],cameraPoints).x > -100000) << 6;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[1][2],cameraPoints).x > -100000) << 7;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[2][2],cameraPoints).x > -100000) << 8;
|
|
|
+ id += (getRecentPoint(A,B,allPoints[1][3],cameraPoints).x > -100000) << 9;
|
|
|
+
|
|
|
+
|
|
|
+ std::vector<cv::Point2d> imagePoints;
|
|
|
+ imagePoints.push_back(cameraToPix(E));
|
|
|
+ imagePoints.push_back(cameraToPix(B));
|
|
|
+ imagePoints.push_back(cameraToPix(A));
|
|
|
+ imagePoints.push_back(cameraToPix(C));
|
|
|
+ imagePoints.push_back(cameraToPix(D));
|
|
|
+ std::vector<cv::Point3d> objectPoints;
|
|
|
+ objectPoints.emplace_back(0.0, 0.0, 0.0);
|
|
|
+ objectPoints.emplace_back(cv::Point3d(m_dPointDistance_ * 3, 0.0, 0.0));
|
|
|
+ objectPoints.emplace_back(cv::Point3d(0.0, m_dPointDistance_ * 3, 0.0));
|
|
|
+ objectPoints.emplace_back(cv::Point3d(m_dPointDistance_ * 2 , m_dPointDistance_ * 3, 0.0));
|
|
|
+ objectPoints.emplace_back(cv::Point3d(m_dPointDistance_ * 3, m_dPointDistance_ * 2, 0.0));
|
|
|
+// objectPoints.push_back(cv::Point3d(0.0,0.0,0.15));
|
|
|
+ cv::Mat distCoeffs = (cv::Mat_<double>(5, 1) << 0, 0, 0, 0, 0);
|
|
|
+ cv::Mat rvecs = cv::Mat::zeros(3, 1, CV_64FC1);
|
|
|
+ cv::Mat tvecs = cv::Mat::zeros(3, 1, CV_64FC1);
|
|
|
+ cv::solvePnP(objectPoints, imagePoints, m_mK_, distCoeffs, rvecs, tvecs, false);
|
|
|
+
|
|
|
+ //可视化用
|
|
|
+
|
|
|
+ std::vector<cv::Point2d> reference_ImagePoint;
|
|
|
+ cv::projectPoints(objectPoints, rvecs, tvecs, m_mK_, distCoeffs, reference_ImagePoint);
|
|
|
+ m_mR = rvecs;
|
|
|
+ m_mT = tvecs;
|
|
|
+ cv::line(m_mDistortionImage, reference_ImagePoint[0], reference_ImagePoint[1], cv::Scalar(0, 0, 255));
|
|
|
+ cv::line(m_mDistortionImage, reference_ImagePoint[0], reference_ImagePoint[2], cv::Scalar(0, 255, 0));
|
|
|
+ cv::line(m_mDistortionImage, reference_ImagePoint[0], reference_ImagePoint[5], cv::Scalar(255, 0, 0));
|
|
|
+ ROS_INFO("rvecs %f %f %f",rvecs.at<double>(0),rvecs.at<double>(1),rvecs.at<double>(2));
|
|
|
+// ROS_INFO("tvecs %f %f %f",tvecs.at<double>(0),tvecs.at<double>(1),tvecs.at<double>(2));
|
|
|
+ for (auto & i : mc) {
|
|
|
+ cv::Scalar color = cv::Scalar(255, 255, 0);
|
|
|
+ circle(m_mDistortionImage, i, 4, color, -1, 8, 0);
|
|
|
+ }
|
|
|
+ cv::Scalar color_0 = cv::Scalar(255, 255, 255);
|
|
|
+ cv::Scalar color_a = cv::Scalar(0, 0, 255);
|
|
|
+ cv::Scalar color_b = cv::Scalar(0, 125, 255);
|
|
|
+ cv::Scalar color_c = cv::Scalar(255, 0, 0);
|
|
|
+ cv::Scalar color_d = cv::Scalar(255, 255, 0);
|
|
|
+ cv::Scalar color_e= cv::Scalar(0, 255, 255);
|
|
|
+ circle(m_mDistortionImage, imagePoints[0], 8, color_e, -1, 8, 0);
|
|
|
+ circle(m_mDistortionImage, imagePoints[1], 8, color_b, -1, 8, 0);
|
|
|
+ circle(m_mDistortionImage, imagePoints[2], 8, color_a, -1, 8, 0);
|
|
|
+ circle(m_mDistortionImage, imagePoints[3], 8, color_c, -1, 8, 0);
|
|
|
+ circle(m_mDistortionImage, imagePoints[4], 8, color_d, -1, 8, 0);
|
|
|
+// circle(m_mDistortionImage_, cameraToPix(image_center), 8, color_0, -1, 8, 0);
|
|
|
+
|
|
|
+// cv::imshow("aa", m_mDistortionImage_);
|
|
|
+// cv::waitKey(0);
|
|
|
+ return id;
|
|
|
+}
|
|
|
+
|
|
|
+cv::Point2d MarkExtract::pixToCamera(cv::Point2d &p) {
|
|
|
+
|
|
|
+ cv::Point2d tempP;
|
|
|
+ tempP.x = p.x - m_mK_.at<double>(0, 2);
|
|
|
+ tempP.y = m_mK_.at<double>(1, 2) - p.y;
|
|
|
+
|
|
|
+ return tempP;
|
|
|
+}
|
|
|
+
|
|
|
+cv::Point2d MarkExtract::cameraToPix(cv::Point2d &p) {
|
|
|
+ cv::Point2d tempP;
|
|
|
+ tempP.x = p.x + m_mK_.at<double>(0, 2);
|
|
|
+ tempP.y = m_mK_.at<double>(1, 2) - p.y;
|
|
|
+
|
|
|
+ return tempP;
|
|
|
+}
|
|
|
+
|
|
|
+int MarkExtract::get_char() {
|
|
|
+ fd_set rfds;
|
|
|
+ struct timeval tv;
|
|
|
+ int ch = 0;
|
|
|
+
|
|
|
+ FD_ZERO(&rfds);
|
|
|
+ FD_SET(0, &rfds);
|
|
|
+ tv.tv_sec = 0;
|
|
|
+ tv.tv_usec = 10; //设置等待超时时间
|
|
|
+
|
|
|
+ //检测键盘是否有输入
|
|
|
+ if (select(1, &rfds, NULL, NULL, &tv) > 0){
|
|
|
+ ch = getchar();
|
|
|
+ }
|
|
|
+ return ch;
|
|
|
+}
|
|
|
+
|
|
|
+cv::Point2d MarkExtract::getRecentPoint(cv::Point2d A, cv::Point2d B, cv::Point2d p, std::vector<cv::Point2d> &mc) {
|
|
|
+ double minDis{1000};
|
|
|
+ cv::Point2d recentPoint;
|
|
|
+ for(const auto& comparePoint : mc){
|
|
|
+// auto dis = std::hypot(comparePoint.x - p.x, comparePoint.y - p.y);
|
|
|
+ auto dis = distanceTwoPoint(comparePoint,p);
|
|
|
+ if(dis < minDis){
|
|
|
+ minDis = dis;
|
|
|
+ recentPoint = comparePoint;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ auto recentDis = distanceTwoPoint(recentPoint,p);
|
|
|
+
|
|
|
+ if(recentDis > distanceTwoPoint(A,B) / 10){
|
|
|
+ recentPoint.x = -100000; //设置一个很小的值,判断是否获取到了正确的点;
|
|
|
+ }
|
|
|
+ return recentPoint;
|
|
|
+}
|
|
|
+
|
|
|
+std::vector<cv::Point2d> MarkExtract::removeOutlier(std::vector<cv::Point2d> &mc, double radius, int k) {
|
|
|
+ std::vector<cv::Point2d> points;
|
|
|
+ for (int i = 0; i < mc.size(); ++i) {
|
|
|
+ cv::Point2d p1 = mc[i];
|
|
|
+ int count{0};
|
|
|
+ for (int j = 0; j < mc.size(); ++j) {
|
|
|
+ if(i != j){
|
|
|
+ auto p2 = mc[j];
|
|
|
+ auto dis = distanceTwoPoint(p1,p2);
|
|
|
+ if(dis < radius){
|
|
|
+ count +=1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(count > k){
|
|
|
+ points.push_back(p1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return points;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+std::map<int,std::vector<cv::Point2d>> MarkExtract::DBSCAN(std::vector<cv::Point2d> dataset,float Eps,int MinPts){
|
|
|
+ int len = dataset.size();
|
|
|
+ std::map<int,std::vector<cv::Point2d>> allPoints;
|
|
|
+ allPoints.clear();
|
|
|
+ std::vector<Point> data;
|
|
|
+ for (int i = 0; i < len; ++i) {
|
|
|
+ data.emplace_back(dataset[i],i);
|
|
|
+ }
|
|
|
+
|
|
|
+ //calculate pts
|
|
|
+ ROS_INFO("计算像素");
|
|
|
+ for(int i=0;i<len;i++){
|
|
|
+ for(int j=i+1;j<len;j++){
|
|
|
+ if(distanceTwoPoint(data[i].m_mPoint,data[j].m_mPoint)<Eps)
|
|
|
+ data[i].m_nPts++;
|
|
|
+ data[j].m_nPts++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //core point
|
|
|
+ std::cout<<"core point "<<std::endl;
|
|
|
+ std::vector<Point> corePoint;
|
|
|
+ for(int i=0;i<len;i++){
|
|
|
+ if(data[i].m_nPts>=MinPts) {
|
|
|
+ data[i].m_nPointType = 3;
|
|
|
+ corePoint.push_back(data[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ROS_INFO("添加核心点");
|
|
|
+ //joint core point
|
|
|
+ for(int i=0;i<corePoint.size();i++){
|
|
|
+ for(int j=i+1;j<corePoint.size();j++){
|
|
|
+ if(distanceTwoPoint(corePoint[i].m_mPoint,corePoint[j].m_mPoint)<Eps){
|
|
|
+ corePoint[i].corepts.push_back(j);
|
|
|
+ corePoint[j].corepts.push_back(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for(int i=0;i<corePoint.size();i++){
|
|
|
+ std::stack<Point*> ps;
|
|
|
+ if(corePoint[i].m_Visited == 1) continue;
|
|
|
+ ps.push(&corePoint[i]);
|
|
|
+ Point *v;
|
|
|
+ while(!ps.empty()){
|
|
|
+ v = ps.top();
|
|
|
+ v->m_Visited = 1;
|
|
|
+ ps.pop();
|
|
|
+ for(int corept : v->corepts){
|
|
|
+ if(corePoint[corept].m_Visited==1) continue;
|
|
|
+ corePoint[corept].m_nCluster = corePoint[i].m_nCluster;
|
|
|
+ corePoint[corept].m_Visited = 1;
|
|
|
+ ps.push(&corePoint[corept]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ROS_INFO("边界点,联合边界点到核心点");
|
|
|
+ //border point,joint border point to core point
|
|
|
+ for(int i=0;i<len;i++){
|
|
|
+ if(data[i].m_nPointType==3) continue;
|
|
|
+ for(auto & j : corePoint){
|
|
|
+ if(distanceTwoPoint(data[i].m_mPoint,j.m_mPoint)<Eps) {
|
|
|
+ data[i].m_nPointType = 2;
|
|
|
+ data[i].m_nCluster = j.m_nCluster;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ROS_INFO("输出");
|
|
|
+ //output
|
|
|
+// fstream clustering;
|
|
|
+// clustering.open("clustering.txt",ios::out);
|
|
|
+// for(auto & i : data){
|
|
|
+// if(i.m_nPointType == 2)
|
|
|
+// std::cout<<i.m_mPoint.x<<","<<i.m_mPoint.y<<","<<i.m_nCluster<<"\n";
|
|
|
+// }
|
|
|
+ for(auto & p : corePoint){
|
|
|
+// std::cout<<p.m_mPoint.x<<","<<p.m_mPoint.y<<","<<p.m_nCluster<<"\n";
|
|
|
+ if (allPoints.count(p.m_nCluster) == 0){
|
|
|
+ std::vector<cv::Point2d> points;
|
|
|
+ points.push_back(p.m_mPoint);
|
|
|
+ allPoints[p.m_nCluster] = points;
|
|
|
+ }else{
|
|
|
+ allPoints[p.m_nCluster].push_back(p.m_mPoint);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return allPoints;
|
|
|
+}
|
|
|
+
|
|
|
+double MarkExtract::distanceTwoPoint(cv::Point2d p1,cv::Point2d p2) {
|
|
|
+ return std::hypot(p1.x - p2.x ,p1.y - p2.y);
|
|
|
+}
|