diff --git a/skais/ais/ais_trajectory.py b/skais/ais/ais_trajectory.py index db1cd8f7311fbdd1e17cb2e6afc863d1bdc997c6..e6ba885dcafca82f0a023eee0196003472ce28b4 100644 --- a/skais/ais/ais_trajectory.py +++ b/skais/ais/ais_trajectory.py @@ -59,6 +59,13 @@ def apply_time_sequence(dat, time, func): return result +def __get_image_value__(features, bounds): + value = [] + for f, b in zip(features, bounds): + value.append(1 - (b[1] - f) / b[1]) + return value + + class AISTrajectory(AISPoints): def __init__(self, df, mmsi=0, interpolation_time=None): df = df.drop_duplicates(subset=['ts_sec']) @@ -228,9 +235,7 @@ class AISTrajectory(AISPoints): def generate_array_from_positions(self, height=256, width=256, link=True, bounding_box='fit', features=None, node_size=0): nb_channels = 1 - if features is not None: - nb_channels = len(features) - data = np.zeros((height, width, nb_channels), dtype=np.uint8) + if bounding_box != 'fit': raise ValueError("feature not implemented") positions = self.df[['longitude', 'latitude']].to_numpy() @@ -243,26 +248,70 @@ class AISTrajectory(AISPoints): min_lon -= 1 max_lon += 1 - for longitude, latitude in positions: - x_coord, y_coord = get_coord(latitude, longitude, height, width, min_lat, max_lat, min_lon, max_lon) + if features is None: + data = np.zeros((height, width, nb_channels), dtype=np.uint8) + for longitude, latitude in positions: + x_coord, y_coord = get_coord(latitude, longitude, height, width, min_lat, max_lat, min_lon, max_lon) - x_lower_bound = max(0, x_coord - node_size) - x_upper_bound = min(height - 1, x_coord + node_size) + x_lower_bound = max(0, x_coord - node_size) + x_upper_bound = min(height - 1, x_coord + node_size) - y_lower_bound = max(0, y_coord - node_size) - y_upper_bound = min(width - 1, y_coord + node_size) + y_lower_bound = max(0, y_coord - node_size) + y_upper_bound = min(width - 1, y_coord + node_size) - for x in range(x_lower_bound, x_upper_bound + 1): - for y in range(y_lower_bound, y_upper_bound + 1): - data[x, y] = [1] + for x in range(x_lower_bound, x_upper_bound + 1): + for y in range(y_lower_bound, y_upper_bound + 1): + data[x, y] = [1] + if link: + lon, lat = positions[0, 0], positions[0, 1] + for longitude, latitude in positions[1:]: + x_prv, y_prev = get_coord(lat, lon, height, width, min_lat, max_lat, min_lon, max_lon) + x_nxt, y_nxt = get_coord(latitude, longitude, height, width, min_lat, max_lat, min_lon, max_lon) - if link: - lon, lat = positions[0, 0], positions[0, 1] - for longitude, latitude in positions[1:]: - x_prv, y_prev = get_coord(lat, lon, height, width, min_lat, max_lat, min_lon, max_lon) - x_nxt, y_nxt = get_coord(latitude, longitude, height, width, min_lat, max_lat, min_lon, max_lon) + lon, lat = longitude, latitude + for x, y in bresenham(x_prv, y_prev, x_nxt, y_nxt): + data[x, y] = [1] - lon, lat = longitude, latitude - for x, y in bresenham(x_prv, y_prev, x_nxt, y_nxt): - data[x, y] = [1] + else: + if type(features) is list: + nb_channels = len(features) + elif type(features) is str: + features = [features] + else: + raise TypeError("Type not supported") + data = np.zeros((height, width, nb_channels), dtype=np.float) + features_vectors = self.df[features].to_numpy() + bounds = [] + for c in features_vectors.T: + bounds.append((min(c), max(c))) + + for pos, f in zip(positions, features_vectors): + latitude = pos[1] + longitude = pos[0] + x_coord, y_coord = get_coord(latitude, longitude, height, width, min_lat, max_lat, min_lon, max_lon) + value = __get_image_value__(f, bounds) + x_lower_bound = max(0, x_coord - node_size) + x_upper_bound = min(height - 1, x_coord + node_size) + + y_lower_bound = max(0, y_coord - node_size) + y_upper_bound = min(width - 1, y_coord + node_size) + + for x in range(x_lower_bound, x_upper_bound + 1): + for y in range(y_lower_bound, y_upper_bound + 1): + for i, v in enumerate(value): + data[x, y, i] = v + if link: + lon, lat = positions[0, 0], positions[0, 1] + + value = __get_image_value__(features_vectors[0], bounds) + for pos, f in zip(positions[1:], features_vectors[1:]): + latitude = pos[1] + longitude = pos[0] + x_prv, y_prev = get_coord(lat, lon, height, width, min_lat, max_lat, min_lon, max_lon) + x_nxt, y_nxt = get_coord(latitude, longitude, height, width, min_lat, max_lat, min_lon, max_lon) + lon, lat = longitude, latitude + for x, y in bresenham(x_prv, y_prev, x_nxt, y_nxt): + for i, v in enumerate(value): + data[x, y, i] = v + value = __get_image_value__(f, bounds) return data diff --git a/skais/tests/ais/test_ais_trajectory.py b/skais/tests/ais/test_ais_trajectory.py index 6f2b6fa628eb4f52844fb2e07a869f223222e6ea..d5e64a0e87a67f15f19289c2f1d527f215b178db 100644 --- a/skais/tests/ais/test_ais_trajectory.py +++ b/skais/tests/ais/test_ais_trajectory.py @@ -503,4 +503,57 @@ class TestAISTrajectory(unittest.TestCase): [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0]]) + np.testing.assert_array_equal(result, expected) + + def test_generate_array_from_positions_with_line_grey_scale(self): + trajectory = AISTrajectory( + pd.DataFrame( + { + "latitude": [0, 10, 0, 20], + "longitude": [0, 10, 20, 20], + "ts_sec": [i for i in range(4)], + "sog": [10,10,20,40] + } + ) + ) + + result = trajectory.generate_array_from_positions(height=9, width=18, link=True, bounding_box='fit', + features="sog", node_size=0).reshape((9, 18)) + expected = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5], + [0, 0, 0, 0, 0, 0, 0, 0.25, 0.25, 0.25, 0, 0, 0, 0, 0, 0, 0, 0.5], + [0, 0, 0, 0, 0, 0.25, 0.25, 0, 0, 0, 0.25, 0.25, 0, 0, 0, 0, 0, 0.5], + [0, 0, 0, 0.25, 0.25, 0, 0, 0, 0, 0, 0, 0, 0.25, 0.25, 0, 0, 0, 0.5], + [0, 0.25, 0.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0.25, 0, 0.5], + [0.25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0.5]]) + + np.testing.assert_array_equal(result, expected) + + def test_generate_array_from_positions_with_line_multi_chanel(self): + trajectory = AISTrajectory( + pd.DataFrame( + { + "latitude": [0, 10, 0, 20], + "longitude": [0, 10, 20, 20], + "ts_sec": [i for i in range(4)], + "sog": [10,10,20,40], + "cog": [40, 20, 10, 10] + } + ) + ) + + result = trajectory.generate_array_from_positions(height=9, width=18, link=True, bounding_box='fit', + features=['sog', 'cog'], node_size=0) + expected = np.array([[[0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.25,1], [0.25,0.5], [0.25,0.5], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0,0], [0,0], [0,0], [0,0], [0.25,1], [0.25,1], [0,0], [0,0], [0,0], [0.25,0.5], [0.25,0.5], [0,0], [0,0], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0,0], [0,0], [0.25,1], [0.25,1], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.25,0.5], [0.25,0.5], [0,0], [0,0], [0,0], [0.5,0.25]], + [[0,0], [0.25,1], [0.25,1], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.25,0.5], [0.25,0.5], [0,0], [0.5,0.25]], + [[0.25,1], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0,0], [0.25,0.5], [0.5,0.25]]]) + np.testing.assert_array_equal(result, expected) \ No newline at end of file