本篇博客我们研究如何对一个区域的船舶进行区分。水域的航迹点分为两类:船舶搁浅点和船舶移动点。在确定研究水域中船舶搁浅点和运动点的速度阈值时,发现当航行速度在0〜1 kn范围内时,船舶航迹呈现出最大数量的分散点,并且没有连续的航迹点。因此,这些散落物被判断为搁置点。如果过滤器速度值范围为0‑1.1 kn,则会有连续的轨迹点,表明当前1.1 kn不是最佳速度阈值。因此,最佳速度阈值设置为1 kn,以区分搁置点和移动点。
具体的验证过程可以参考文献《RESEARCH ON SHIP TRAJECTORY EXTRACTION BASED ON MULTI-ATTRIBUTE DBSCAN OPTIMISATION ALGORITHM》
为此编写了分割程序,算法的思路是利用船舶整条轨迹AIS数据中对地航速(SOG)的均值和速度阈值vth(vth=1.1kn)对比,若船舶编号为 i 的轨迹其速度均值 vi > 1.1kn,则把船舶 i 判断为货船;若船舶编号为 j 的轨迹其速度均值 vj ≤ 1.1kn,则把船舶 j 判断为渔船。
△我们需要对一个区域的船舶进行划分,这会涉及到海量的AIS的数据,保存AIS数据的方式是利用.xlsx 进行保存的,而保存AIS数据的.xlsx文件不止一个,如图1所示。
图1 保存的AIS数据
如果手动地一个个执行AIS数据文件,那么效率会大大降低。现在需要利用计算机依次执行目标文件中的AIS数据文件,再划分完成后也要依次的输出货船的AIS数据文件。恰好Python中,有一个glob 包,可以实现了" 以读方式打开文件,批量读取.xlsx文件 ",函数名及应用如下:
import glob """-----以读方式打开文件——批量读取xlsx-----""" file_path = r'text_files' # 文件夹位置 file = glob.glob(os.path.join(file_path, "*.xlsx")) # 文件列表
file中保存了 'text_files' 文件夹下所有".xlsx"文件的名称,以列表进行保存,如图2所示。
图2 列表 file
下面就是对整体的工程编写代码:
1. 导入用到的包:
# -*- coding: utf-8 -*-
"""
File Name : 渔船的货船的区分
Description : Bistinction between the cargo ships of fishing boats
Author : 张尺
date : 2022/05/30
"""
from __future__ import division
from math import sqrt, pow
import matplotlib.pyplot as plt
import pandas as pd
import os
import glob
2. 编写函数Distinguish_between_fishing_boats_and_cargo_ships(),目的是计算一天船舶轨迹的平均速度:
def Distinguish_between_fishing_boats_and_cargo_ships(ais_data_list):
""" --------计算这条船舶的平均速度-------- """
sum_speed = 0
for index, point in enumerate(ais_data_list):
sum_speed = sum_speed + point[4]
ave_speed = sum_speed / len(ais_data_list)
return ave_speed
3. 编写主程序,实现一个文件内所有AIS数据的划分,并依次画出划分完成后渔船的轨迹图:
if __name__ == '__main__':
fig = plt.figure() # 画图准备
"""-----以读方式打开文件——批量读取xlsx-----"""
file_path = r'text_files' # 文件夹位置
file = glob.glob(os.path.join(file_path, "*.xlsx")) # 文件列表
file.sort() # 文件列表按名称排序
print(file)
for file_i in range(len(file)):
"""----依次读取文件----"""
Reading_file_path = file[file_i]
Save_file_path = Reading_file_path
"""----实现字符串相减功能----"""
for i in Save_file_path:
if i in 'text_files\sort_Mexican船舶:).xlsx':
Save_file_path = Save_file_path.replace(i,"")
"""----实现捕获文件编号和捕获船舶数目----"""
sign = 0
file_num = ''
ais_miss_num = ' '
for i in Save_file_path:
if i == '(': # 分割标志
sign = 1
continue
if sign == 0: # 文件号
file_num = file_num + i
if sign == 1: # 船舶数目
ais_miss_num = ais_miss_num + i
Save_file_path = "Shift_Mexican" + file_num + ".xlsx"
print("保存文件:%s,船舶数目:%s,读取文件路径:%s"%(Save_file_path,ais_miss_num,Reading_file_path))
AIS_MMIS = [] # 储存各个船舶的MMSI号
AIS_MMIS_NUM = int(ais_miss_num) # MISS号的个数,手动输入
AIS_MMIS_NUM_LIST = [] # MISS号每个船舶,对应的AIS数据个数
ship = pd.read_excel(Reading_file_path)
mmsi = ship['MMSI']
time = ship['BaseDateTime']
lat = ship['LAT']
lon = ship['LON']
sog = ship['SOG']
cog = ship['COG']
heading = ship['Heading']
# print(shipdata.index) # 获取行的索引名称
# print(shipdata.columns) # 获取列的索引名称
Temporary_variable_miss = mmsi[0]
AIS_MMIS.append(mmsi[0]) # 先赋值第一个船舶的MMSI号
all_ships = list() # 创建货船的数据的AIS_MMIS_NUM个列表
for i in range(AIS_MMIS_NUM):
all_ships.append([])
""" ---统计各个MMSI号的AIS数据个数,这里要求数据必须是对齐的--- """
i = 0
j = 1
while i < len(lon):
if mmsi[i] == Temporary_variable_miss:
j = j + 1
Temporary_variable_miss = mmsi[i]
else:
AIS_MMIS_NUM_LIST.append(j)
AIS_MMIS.append(mmsi[i])
j = 1
Temporary_variable_miss = mmsi[i]
i = i + 1
AIS_MMIS_NUM_LIST.append(j)
AIS_MMIS_NUM_LIST[0] = AIS_MMIS_NUM_LIST[0] - 1
""" ---不同MMSI号对应着不同的AIS数据个数,创建这个列表--- """
i = 0
j = 0
while i < AIS_MMIS_NUM:
for j in range(AIS_MMIS_NUM_LIST[i]):
all_ships[i].append([])
i = i + 1
""" ---往 all_ships 赋值--- """
i = 0
j = 0
k = 0
for i in range(AIS_MMIS_NUM):
for j in range(AIS_MMIS_NUM_LIST[i]):
all_ships[i][j].append(mmsi[k])
all_ships[i][j].append(time[k])
all_ships[i][j].append(lat[k])
all_ships[i][j].append(lon[k])
all_ships[i][j].append(sog[k])
all_ships[i][j].append(cog[k])
all_ships[i][j].append(heading[k])
k = k + 1
i = i + 1
""" ----创建货船的数据列表---- """
cargo_ships = list() # 创建货船的数据列表
fishing_ships = list() # 创建渔船的数据列表
''' ----利用船舶的速度去判断---- '''
for i in range(AIS_MMIS_NUM):
judge_value = Distinguish_between_fishing_boats_and_cargo_ships(all_ships[i])
if judge_value > 1.1:
cargo_ships.append(all_ships[i])
else:
fishing_ships.append(all_ships[i])
'''---- 储存一下货船的MMSI号 ----'''
cargo_ships_mmsi = []
for cargo_data in cargo_ships:
cargo_ships_mmsi.append(cargo_ships[0][0])
'''---- 储存一下渔船的MMSI号 ----'''
fishing_ships_mmsi = []
for fishing_data in fishing_ships:
fishing_ships_mmsi.append(fishing_ships[0][0])
print("渔船个数:%s" % len(fishing_ships_mmsi))
print("货船个数:%s" % len(cargo_ships_mmsi))
'''---- 储存渔船到 excel 中 ----'''
# for i in fishing_ships_mmsi:
# ship.drop(ship[(ship.MMSI == i)].index, inplace=True)
# ship.to_excel(Save_file_path)
'''---- 储存货船到 excel 中 ----'''
# for i in cargo_ships_mmsi:
# ship.drop(ship[(ship.MMSI == i)].index, inplace=True)
# ship.to_excel(Save_file_path)
""" ----------画图、显示出来---------- """
for i in range(len(cargo_ships)):
show_original_line_x = []
show_original_line_y = []
for show_point in cargo_ships[i]:
show_original_line_x.append(show_point[3])
show_original_line_y.append(show_point[2])
plt.clf() # 用于画多个图时, 清空画面
ax1 = fig.add_subplot(111) # 111,指的就是将这块画布分为1×1,然后1对应的就是1号区
plt.plot(show_original_line_x, show_original_line_y, color='green',linestyle='--')
plt.scatter(show_original_line_x, show_original_line_y, color='green')
# plt.title("ship_ships")
plt.title("cargo_ships")
plt.sca(ax1)
plt.pause(1) # 显示秒数
4. 示例,分离的渔船轨迹图,如图3所示:
(a) 示例1
(b) 示例2
(c) 示例3
图 3 渔船轨迹图
5. 示例,分离的货船轨迹图,如图4所示:
(a) 示例1
(b) 示例2
(c) 示例3
图 4 货船轨迹图
参考文献:
[1] RESEARCH ON SHIP TRAJECTORY EXTRACTION BASED ON MULTI-ATTRIBUTE DBSCAN OPTIMISATION ALGORITHM
完整工程(数据集+Python),在我的博客“资源”界面下,需要下载~
欢迎留言,欢迎指正~