轨迹去噪

作者: 大鱼馆长 | 来源:发表于2022-03-31 16:53 被阅读0次

1. 定义

轨迹去噪:过滤掉轨迹中不需要的GPS点,保留需要的GPS点,然后组成新的子轨迹。

2. 算法描述

情况1:轨迹的GPS点是由传感器采集的特定时间点的位置信息,由于信号干扰等因素可能会造成GPS点与车辆的真实位置存在较大偏差。偏差过大的GPS点会影响后续的轨迹计算和可视化,这类偏差过大的GPS点被称为轨迹的噪点,需要从轨迹中剔除掉。图1所示的轨迹中,红色的GPS点都是噪点。

图1 轨迹噪点示意图[1]
算法1:识别情况1中噪点的关键在于设计一个合理的偏差的度量(Metric),文献[1]中用相邻两GPS点之间的平均速度(Average Speed)作为度量,如果相邻两个GPS的平均速度大于一个不合理的常量(Threshold),则认为后一个GPS点为噪点,比如出租车的行驶速度一般不超过200KM/H。剔除掉噪点之后剩余的多个连续的轨迹段就是去噪后的子轨迹,如图1中的p1->p4,p6->p9。

需要注意的是,图1中的p10和p11的平均速度可能小于,这种情况下p10相对p9是噪点,但是p11相对p10不是噪点,p10->p11就会被作为一个子轨迹(虽然是由两个相邻噪点组成的),出现连续多个噪点相距都很近的情况极其少,所以这类子轨迹一般不会太长,只需要在去噪后生成的自轨迹中把长度点数量小于一个值(GPS Number)的轨迹丢弃即可。

算法实现参考3.1。

情况2:用户只关心某特定空间区域内的轨迹,区域以外的GPS点则直接丢弃。
算法2:给定多边形空间区域(Spatial Boundary),从原始的轨迹中截取该区域内连续的轨迹段组成子轨迹。

情况3:用户只关心某特定时间范围内的轨迹,时间范围之外的GPS点则直接丢弃。
算法3:给定目标时间范围(Time Boundary),截取包含在该时间范围内的连续轨迹段生成子轨迹。

3. 代码实现

代码是用Scala实现的,完整项目请查看我的Github
接口类

trait AbstractTrajectoryFilter {
  /**
   * Filter the sub-trajectories from raw long trajectory
   *
   * @param trajectory raw trajectory
   * @return sub-trajectories
   */
  def filter(trajectory: Trajectory): Array[Trajectory]
}

3.1 轨迹去噪(算法1)

class TrajectoryNoiseFilter(maxSpeedMPS: Double) extends AbstractTrajectoryFilter {

  override def filter(trajectory: Trajectory): Array[Trajectory] = {
    val gpsCoordinates = trajectory.getCoordinatesGPS

    var startIndex = 0
    var currIndex = 0
    val subTrajectories = new ArrayBuffer[Trajectory]()
    while (currIndex < gpsCoordinates.length - 1) {
      val speed = calSpeed(gpsCoordinates(currIndex), gpsCoordinates(currIndex + 1))
      if (speed > maxSpeedMPS) {
        if (startIndex < currIndex) {
          val subCoordinates = gpsCoordinates.slice(startIndex, currIndex + 1)
          subTrajectories += new Trajectory(trajectory.oid, subCoordinates)
        }
        startIndex = currIndex + 2 //ignore the noisy coordinate
        currIndex = startIndex
      } else {
        currIndex += 1
      }
    }

    if (startIndex < gpsCoordinates.length - 1) {
      subTrajectories += new Trajectory(trajectory.oid, gpsCoordinates.slice(startIndex, gpsCoordinates.length))
    }
    subTrajectories.toArray
  }

  private def calSpeed(from: CoordinateGPS, to: CoordinateGPS): Double = {
    val timeIntervalInSec = to.time.toInstant.getEpochSecond - from.time.toInstant.getEpochSecond
    val distanceInMeter = DistanceCalculator.distInMeter(from, to)
    distanceInMeter / timeIntervalInSec
  }

3.2 轨迹时间过滤(算法2)

class TrajectorySpatialFilter(spatialBound: Polygon) extends AbstractTrajectoryFilter {

  override def filter(trajectory: Trajectory): Array[Trajectory] = {
    val gpsCoordinates = trajectory.getCoordinatesGPS

    var startIndex = -1
    val subTrajectories = new ArrayBuffer[Trajectory]()
    for (index <- gpsCoordinates.indices.dropRight(1)) {
      if (spatialBound.contains(trajectory.getPointN(index))) {
        if (startIndex == -1) {
          //enter spatial bound
          startIndex = index
        }
      } else {
        if (startIndex != -1) {
          //leave spatial bound
          if (startIndex < index - 1) {
            subTrajectories += new Trajectory(trajectory.oid, gpsCoordinates.slice(startIndex, index))
          }
          startIndex = -1
        }
      }
    }

    if (startIndex != -1 && startIndex < gpsCoordinates.length - 1) {
      //the last sub trajectory
      subTrajectories += new Trajectory(trajectory.oid, gpsCoordinates.slice(startIndex, gpsCoordinates.length))
    }
    subTrajectories.toArray
  }
}

3.3 轨迹时间过滤(算法3)

class TrajectoryTemporalFilter(timeBound: (Timestamp, Timestamp)) extends AbstractTrajectoryFilter {

  override def filter(trajectory: Trajectory): Array[Trajectory] = {
    if (!trajectory.getStartTime.before(timeBound._2) || !trajectory.getEndTime.after(timeBound._1)) {
      return Array.empty
    }

    val gpsCoordinates = trajectory.getCoordinatesGPS
    val startIndex = gpsCoordinates.indexWhere(_.time.after(timeBound._1))
    val endIndex = gpsCoordinates.lastIndexWhere(_.time.before(timeBound._2))
    assert(startIndex != -1 && endIndex != -1)

    Array(new Trajectory(trajectory.oid, gpsCoordinates.slice(startIndex, endIndex + 1)))
  }
}

4. 总结

轨迹去噪就根据目标需求,将不需要的GPS点剔除,并将连续的GPS点组成子轨迹。不同算法的差异在于对"不需要的GPS点"的定义不同。

参考文献

[1] Zheng Y. Trajectory data mining: an overview[J]. ACM Transactions on Intelligent Systems and Technology (TIST), 2015, 6(3): 1-41.

相关文章

  • 轨迹去噪

    1. 定义 轨迹去噪:过滤掉轨迹中不需要的GPS点,保留需要的GPS点,然后组成新的子轨迹。 2. 算法描述 情况...

  • 轨迹分段

    1. 定义 轨迹分段:对去噪后的轨迹,根据驻留点信息或者相邻GPS点之间的时间间隔,将其划分成多个连续的GPS子序...

  • KSVD去噪

    在解释KSVD去噪原理之前先解释几个名词,首先: 原子:信号的基本构成成分,比如一个长为N的列向量; ...

  • 阳谋去噪

    清晨六点,窗外的鸟儿就开始叽叽喳喳的开始鸣叫,不知道她们是为了早歺吃什么而讨论,还是在议论今天的太阳要被云层遮挡出...

  • 图像去噪

    图像去噪可以分为固定阈值去噪和自适应阈值去噪 固定阈值去噪 opencv函数(python):cv2.thresh...

  • 数据去噪方法

    一. 异常值填补方法 1.1 k-近邻替换法 1.2 局部加权替换法 1.3 有序最近邻替换法 1.4 均值法 1...

  • 图像去噪

    图像去噪 图像去噪(noise reduction)也被称为图像噪声清除或者噪声平滑。 Coherence(和谐)...

  • 传统地震去噪算法实战(一)——中值滤波去噪

    各位同学,地震信号的去噪是地震勘探工作中的一个重要的预处理步骤。通过这个工作,可以排除错误信号干扰、提高地震信号的...

  • 传统地震去噪算法实战(二)——构造导向滤波去噪

    上一节课给各位同学介绍了传统信号最常用的算法——中值滤波算法。这个算法以优异的去噪性能和对信号本身较小的破坏,成为...

  • 云朵被雨噪去

    天上的云一朵一朵 逍遥自在轻轻地飘 一场又一场的春雨 争先恐后地下 一截又一截的麦苗 急急忙忙地长 留下一片片 美...

网友评论

    本文标题:轨迹去噪

    本文链接:https://www.haomeiwen.com/subject/mflnjrtx.html