Victoria Oberascher commited on
Commit
db9ef5e
·
1 Parent(s): d0f1574

add implementation

Browse files
Files changed (2) hide show
  1. horizonmetrics.py +56 -13
  2. utils.py +266 -0
horizonmetrics.py CHANGED
@@ -15,7 +15,7 @@
15
 
16
  import evaluate
17
  import datasets
18
-
19
 
20
  # TODO: Add BibTeX citation
21
  _CITATION = """\
@@ -31,7 +31,6 @@ _DESCRIPTION = """\
31
  This new module is designed to solve this great ML task and is crafted with a lot of care.
32
  """
33
 
34
-
35
  # TODO: Add description of the arguments of the module here
36
  _KWARGS_DESCRIPTION = """
37
  Calculates how good are predictions given some references, using certain scores
@@ -57,10 +56,25 @@ Examples:
57
  BAD_WORDS_URL = "http://url/to/external/resource/bad_words.txt"
58
 
59
 
60
- @evaluate.utils.file_utils.add_start_docstrings(_DESCRIPTION, _KWARGS_DESCRIPTION)
 
61
  class horizonmetrics(evaluate.Metric):
62
  """TODO: Short description of my evaluation module."""
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  def _info(self):
65
  # TODO: Specifies the evaluate.EvaluationModuleInfo object
66
  return evaluate.MetricInfo(
@@ -78,18 +92,47 @@ class horizonmetrics(evaluate.Metric):
78
  homepage="http://module.homepage",
79
  # Additional links to the codebase or references
80
  codebase_urls=["http://github.com/path/to/codebase/of/new_module"],
81
- reference_urls=["http://path.to.reference.url/new_module"]
82
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
  def _download_and_prepare(self, dl_manager):
85
  """Optional: download external resources useful to compute the scores"""
86
  # TODO: Download external resources if needed
87
  pass
88
-
89
- def _compute(self, predictions, references):
90
- """Returns the scores"""
91
- # TODO: Compute the different scores of the module
92
- accuracy = sum(i == j for i, j in zip(predictions, references)) / len(predictions)
93
- return {
94
- "accuracy": accuracy,
95
- }
 
15
 
16
  import evaluate
17
  import datasets
18
+ from utils import *
19
 
20
  # TODO: Add BibTeX citation
21
  _CITATION = """\
 
31
  This new module is designed to solve this great ML task and is crafted with a lot of care.
32
  """
33
 
 
34
  # TODO: Add description of the arguments of the module here
35
  _KWARGS_DESCRIPTION = """
36
  Calculates how good are predictions given some references, using certain scores
 
56
  BAD_WORDS_URL = "http://url/to/external/resource/bad_words.txt"
57
 
58
 
59
+ @evaluate.utils.file_utils.add_start_docstrings(_DESCRIPTION,
60
+ _KWARGS_DESCRIPTION)
61
  class horizonmetrics(evaluate.Metric):
62
  """TODO: Short description of my evaluation module."""
63
 
64
+ def __init__(self,
65
+ slope_threshold=0.1,
66
+ midpoint_threshold=0.1,
67
+ vertical_fov_degrees=25.6,
68
+ **kwargs):
69
+ super().__init__(**kwargs)
70
+ self.slope_threshold = slope_threshold
71
+ self.midpoint_threshold = midpoint_threshold
72
+ self.vertical_fov_degrees = vertical_fov_degrees
73
+ self.predictions = None
74
+ self.ground_truth_det = None
75
+ self.slope_error_list = None
76
+ self.midpoint_error_list = None
77
+
78
  def _info(self):
79
  # TODO: Specifies the evaluate.EvaluationModuleInfo object
80
  return evaluate.MetricInfo(
 
92
  homepage="http://module.homepage",
93
  # Additional links to the codebase or references
94
  codebase_urls=["http://github.com/path/to/codebase/of/new_module"],
95
+ reference_urls=["http://path.to.reference.url/new_module"])
96
+
97
+ def add(self, *, predictions, references, **kwargs):
98
+ """
99
+ Update the predictions and ground truth detections.
100
+
101
+ Parameters
102
+ ----------
103
+ predictions : list
104
+ List of predicted horizons.
105
+ ground_truth_det : list
106
+ List of ground truth horizons.
107
+
108
+ """
109
+ self.predictions = predictions
110
+ self.ground_truth_det = references
111
+ self.slope_error_list = []
112
+ self.midpoint_error_list = []
113
+
114
+ for annotated_horizon, proposed_horizon in zip(self.ground_truth_det,
115
+ self.predictions):
116
+ slope_error, midpoint_error = calculate_horizon_error(
117
+ annotated_horizon, proposed_horizon)
118
+ self.slope_error_list.append(slope_error)
119
+ self.midpoint_error_list.append(midpoint_error)
120
+
121
+ def _compute(self, predictions, references):
122
+ """
123
+ Compute the horizon error across the sequence.
124
+
125
+ Returns
126
+ -------
127
+ float
128
+ The computed horizon error.
129
+
130
+ """
131
+ return calculate_horizon_error_across_sequence(
132
+ self.slope_error_list, self.midpoint_error_list,
133
+ self.slope_threshold, self.midpoint_threshold)
134
 
135
  def _download_and_prepare(self, dl_manager):
136
  """Optional: download external resources useful to compute the scores"""
137
  # TODO: Download external resources if needed
138
  pass
 
 
 
 
 
 
 
 
utils.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def xy_points_to_slope_midpoint(xy_points):
5
+ """
6
+ Given two points, return the slope and midpoint of the line
7
+
8
+ Args:
9
+ xy_points: list of two points, each point is a list of two elements
10
+ Points are in the form of [x, y], where x and y are normalized to [0, 1]
11
+
12
+ Returns:
13
+ slope: Slope of the line
14
+ midpoint : Midpoint is in the form of [x,y], and is also normalized to [0, 1]
15
+ """
16
+
17
+ x1, y1, x2, y2 = xy_points[0][0], xy_points[0][1], xy_points[1][
18
+ 0], xy_points[1][1]
19
+ slope = (y2 - y1) / (x2 - x1)
20
+
21
+ midpoint_x = 0.5
22
+ midpoint_y = slope * (0.5 - x1) + y1
23
+ midpoint = [midpoint_x, midpoint_y]
24
+ return slope, midpoint
25
+
26
+
27
+ def calculate_horizon_error(annotated_horizon, proposed_horizon):
28
+ """
29
+ Calculate the error between the annotated horizon and the proposed horizon
30
+
31
+ Args:
32
+ annotated_horizon: list of two points, each point is a list of two elements
33
+ Points are in the form of [x, y], where x and y are normalized to [0, 1]
34
+ proposed_horizon: list of two points, each point is a list of two elements
35
+ Points are in the form of [x, y], where x and y are normalized to [0, 1]
36
+
37
+ Returns:
38
+ slope_error: Error in the slope of the lines
39
+ midpoint_error: Error in the midpoint_y of the lines
40
+ """
41
+
42
+ slope_annotated, midpoint_annotated = xy_points_to_slope_midpoint(
43
+ annotated_horizon)
44
+ slope_proposed, midpoint_proposed = xy_points_to_slope_midpoint(
45
+ proposed_horizon)
46
+
47
+ slope_error = abs(slope_annotated - slope_proposed)
48
+ midpoint_error = abs(midpoint_annotated[1] - midpoint_proposed[1])
49
+
50
+ return slope_error, midpoint_error
51
+
52
+
53
+ def calculate_horizon_error_across_sequence(slope_error_list,
54
+ midpoint_error_list,
55
+ slope_error_jump_threshold,
56
+ midpoint_error_jump_threshold):
57
+ """
58
+ Calculate the error statistics across a sequence of frames
59
+
60
+ Args:
61
+ slope_error_list: List of errors in the slope of the lines
62
+ midpoint_error_list: List of errors in the midpoint_y of the lines
63
+
64
+ Returns:
65
+ average_slope_error: Average error in the slope of the lines
66
+ average_midpoint_error: Average error in the midpoint_y of the lines
67
+ """
68
+
69
+ # Calculate the average and standard deviation of the errors
70
+ average_slope_error = np.mean(slope_error_list)
71
+ average_midpoint_error = np.mean(midpoint_error_list)
72
+
73
+ stddev_slope_error = np.std(slope_error_list)
74
+ stddev_midpoint_error = np.std(midpoint_error_list)
75
+
76
+ # Calculate the maximum errors
77
+ max_slope_error = np.max(slope_error_list)
78
+ max_midpoint_error = np.max(midpoint_error_list)
79
+
80
+ # Calculate the differences between errors in successive frames
81
+ diff_slope_error = np.abs(np.diff(slope_error_list))
82
+ diff_midpoint_error = np.abs(np.diff(midpoint_error_list))
83
+
84
+ # Calculate the number of jumps in the errors
85
+ num_slope_error_jumps = np.sum(
86
+ diff_slope_error > slope_error_jump_threshold)
87
+ num_midpoint_error_jumps = np.sum(
88
+ diff_midpoint_error > midpoint_error_jump_threshold)
89
+
90
+ # Create a dictionary to store the results
91
+ sequence_results = {
92
+ 'average_slope_error': average_slope_error,
93
+ 'average_midpoint_error': average_midpoint_error,
94
+ 'stddev_slope_error': stddev_slope_error,
95
+ 'stddev_midpoint_error': stddev_midpoint_error,
96
+ 'max_slope_error': max_slope_error,
97
+ 'max_midpoint_error': max_midpoint_error,
98
+ 'num_slope_error_jumps': num_slope_error_jumps,
99
+ 'num_midpoint_error_jumps': num_midpoint_error_jumps
100
+ }
101
+
102
+ return sequence_results
103
+
104
+
105
+ import numpy as np
106
+ import cv2
107
+ import matplotlib.pyplot as plt
108
+
109
+
110
+ def xy_points_to_slope_midpoint(xy_points):
111
+ """
112
+ Given two points, return the slope and midpoint of the line
113
+
114
+ Args:
115
+ xy_points: list of two points, each point is a list of two elements
116
+ Points are in the form of [x, y], where x and y are normalized to [0, 1]
117
+
118
+ Returns:
119
+ slope: Slope of the line
120
+ midpoint : Midpoint is in the form of [x,y], and is also normalized to [0, 1]
121
+ """
122
+
123
+ x1, y1, x2, y2 = xy_points[0][0], xy_points[0][1], xy_points[1][
124
+ 0], xy_points[1][1]
125
+ slope = (y2 - y1) / (x2 - x1)
126
+
127
+ midpoint_x = 0.5
128
+ midpoint_y = slope * (0.5 - x1) + y1
129
+ midpoint = [midpoint_x, midpoint_y]
130
+ return slope, midpoint
131
+
132
+
133
+ def calculate_horizon_error(annotated_horizon, proposed_horizon):
134
+ """
135
+ Calculate the error between the annotated horizon and the proposed horizon
136
+
137
+ Args:
138
+ annotated_horizon: list of two points, each point is a list of two elements
139
+ Points are in the form of [x, y], where x and y are normalized to [0, 1]
140
+ proposed_horizon: list of two points, each point is a list of two elements
141
+ Points are in the form of [x, y], where x and y are normalized to [0, 1]
142
+
143
+ Returns:
144
+ slope_error: Error in the slope of the lines
145
+ midpoint_error: Error in the midpoint_y of the lines
146
+ """
147
+
148
+ slope_annotated, midpoint_annotated = xy_points_to_slope_midpoint(
149
+ annotated_horizon)
150
+ slope_proposed, midpoint_proposed = xy_points_to_slope_midpoint(
151
+ proposed_horizon)
152
+
153
+ slope_error = abs(slope_annotated - slope_proposed)
154
+ midpoint_error = abs(midpoint_annotated[1] - midpoint_proposed[1])
155
+
156
+ return slope_error, midpoint_error
157
+
158
+
159
+ def calculate_horizon_error_across_sequence(slope_error_list,
160
+ midpoint_error_list,
161
+ slope_error_jump_threshold,
162
+ midpoint_error_jump_threshold):
163
+ """
164
+ Calculate the error statistics across a sequence of frames
165
+
166
+ Args:
167
+ slope_error_list: List of errors in the slope of the lines
168
+ midpoint_error_list: List of errors in the midpoint_y of the lines
169
+
170
+ Returns:
171
+ average_slope_error: Average error in the slope of the lines
172
+ average_midpoint_error: Average error in the midpoint_y of the lines
173
+ """
174
+
175
+ # Calculate the average and standard deviation of the errors
176
+ average_slope_error = np.mean(slope_error_list)
177
+ average_midpoint_error = np.mean(midpoint_error_list)
178
+
179
+ stddev_slope_error = np.std(slope_error_list)
180
+ stddev_midpoint_error = np.std(midpoint_error_list)
181
+
182
+ # Calculate the maximum errors
183
+ max_slope_error = np.max(slope_error_list)
184
+ max_midpoint_error = np.max(midpoint_error_list)
185
+
186
+ # Calculate the differences between errors in successive frames
187
+ diff_slope_error = np.abs(np.diff(slope_error_list))
188
+ diff_midpoint_error = np.abs(np.diff(midpoint_error_list))
189
+
190
+ # Calculate the number of jumps in the errors
191
+ num_slope_error_jumps = np.sum(
192
+ diff_slope_error > slope_error_jump_threshold)
193
+ num_midpoint_error_jumps = np.sum(
194
+ diff_midpoint_error > midpoint_error_jump_threshold)
195
+
196
+ # Create a dictionary to store the results
197
+ sequence_results = {
198
+ 'average_slope_error': average_slope_error,
199
+ 'average_midpoint_error': average_midpoint_error,
200
+ 'stddev_slope_error': stddev_slope_error,
201
+ 'stddev_midpoint_error': stddev_midpoint_error,
202
+ 'max_slope_error': max_slope_error,
203
+ 'max_midpoint_error': max_midpoint_error,
204
+ 'num_slope_error_jumps': num_slope_error_jumps,
205
+ 'num_midpoint_error_jumps': num_midpoint_error_jumps
206
+ }
207
+
208
+ return sequence_results
209
+
210
+
211
+ def slope_to_roll(slope):
212
+ """
213
+ Convert the slope of the horizon to roll
214
+
215
+ Args:
216
+ slope: Slope of the horizon
217
+
218
+ Returns:
219
+ roll: Roll in degrees
220
+ """
221
+ roll = np.arctan(slope) * 180 / np.pi
222
+ return roll
223
+
224
+
225
+ def roll_to_slope(roll):
226
+ """
227
+ Convert the roll of the horizon to slope
228
+
229
+ Args:
230
+ roll: Roll of the horizon in degrees
231
+
232
+ Returns:
233
+ slope: Slope of the horizon
234
+ """
235
+ slope = np.tan(roll * np.pi / 180)
236
+ return slope
237
+
238
+
239
+ def midpoint_to_pitch(midpoint, vertical_fov_degrees):
240
+ """
241
+ Convert the midpoint of the horizon to pitch
242
+
243
+ Args:
244
+ midpoint: Midpoint of the horizon
245
+ vertical_fov_degrees: Vertical field of view of the camera in degrees
246
+
247
+ Returns:
248
+ pitch: Pitch in degrees
249
+ """
250
+ pitch = midpoint * vertical_fov_degrees
251
+ return pitch
252
+
253
+
254
+ def pitch_to_midpoint(pitch, vertical_fov_degrees):
255
+ """
256
+ Convert the pitch of the horizon to midpoint
257
+
258
+ Args:
259
+ pitch: Pitch of the horizon in degrees
260
+ vertical_fov_degrees: Vertical field of view of the camera in degrees
261
+
262
+ Returns:
263
+ midpoint: Midpoint of the horizon
264
+ """
265
+ midpoint = pitch / vertical_fov_degrees
266
+ return midpoint