Skip to content

Commit d502b20

Browse files
author
trevor.stout
committed
Added edge case fixes. Added small buffer to bat call contour
1 parent 87f3627 commit d502b20

1 file changed

Lines changed: 34 additions & 19 deletions

File tree

batbot/spectrogram/__init__.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def get_islands(data):
5151

5252

5353
def get_slope_islands(slope_flags):
54-
flags = slope_flags.astype(np.uint8)
54+
flags = slope_flags.astype(np.uint16)
5555
islands = get_islands(flags)
5656
idx = int(np.argmax([val.sum() for val in islands]))
5757
islands = [val * (1 if i == idx else 0) for i, val in enumerate(islands)]
@@ -443,7 +443,10 @@ def filter_candidates_to_ranges(
443443
views = np.lib.stride_tricks.sliding_window_view(candidate, (window, candidate.shape[1]))[
444444
::stride_, 0
445445
]
446-
skews = scipy.stats.skew(views, axis=(1, 2))
446+
with warnings.catch_warnings():
447+
# handle cases with mono-valued data
448+
warnings.simplefilter('ignore', category=RuntimeWarning)
449+
skews = scipy.stats.skew(views, axis=(1, 2))
447450

448451
# Center and clip the skew values
449452
skew_thresh = calculate_mean_within_stddev_window(skews, skew_stddev)
@@ -452,7 +455,7 @@ def filter_candidates_to_ranges(
452455
skews = normalize_skew(skews, skew_thresh)
453456

454457
# Calculate the largest contiguous island of non-zeros
455-
skews = (skews > 0).astype(np.uint8)
458+
skews = (skews > 0).astype(np.uint16)
456459
islands = get_islands(skews)
457460
area = float(max([val.sum() for val in islands]))
458461
area /= len(skews)
@@ -555,7 +558,7 @@ def normalize_skew(skews, skew_thresh):
555558

556559
with warnings.catch_warnings():
557560
warnings.simplefilter('ignore', category=RuntimeWarning)
558-
skews /= skews.max()
561+
skews /= np.nanmax(skews)
559562

560563
skews = np.nan_to_num(skews, nan=0.0, posinf=0.0, neginf=-0.0)
561564

@@ -564,8 +567,8 @@ def normalize_skew(skews, skew_thresh):
564567

565568
def calculate_mean_within_stddev_window(values, window):
566569
# Calculate the average skew within X standard deviations (temperature scaling)
567-
values_mean = np.mean(values)
568-
values_std = np.std(values)
570+
values_mean = np.nanmean(values)
571+
values_std = np.nanstd(values)
569572
values_flags = np.abs(values - values_mean) <= (values_std * window)
570573
values_mean_windowed = values[values_flags].mean()
571574
return values_mean_windowed
@@ -585,19 +588,22 @@ def tighten_ranges(
585588
# Extract the candidate window of the STFT
586589
candidate = stft_db[:, start:stop]
587590

588-
# Create a vertical (frequency) sliding window of Numpy views
591+
# Create a horizontal (time) sliding window of Numpy views
589592
views = np.lib.stride_tricks.sliding_window_view(candidate, (candidate.shape[0], window))[
590593
0, ::stride_
591594
]
592-
skews = scipy.stats.skew(views, axis=(1, 2))
595+
with warnings.catch_warnings():
596+
# handle cases with mono-valued data
597+
warnings.simplefilter('ignore', category=RuntimeWarning)
598+
skews = scipy.stats.skew(views, axis=(1, 2))
593599

594600
# Center and clip the skew values
595601
skew_thresh = calculate_mean_within_stddev_window(skews, skew_stddev)
596602
skews = normalize_skew(skews, skew_thresh)
597603

598604
# Calculate the largest contiguous island of non-zeros
599605
skew_flags = skews > 0
600-
skews = skew_flags.astype(np.uint8)
606+
skews = skew_flags.astype(np.uint16)
601607
islands = get_islands(skews)
602608
islands = [(index + 1) * val for index, val in enumerate(islands)]
603609
island = np.hstack(islands)
@@ -1212,14 +1218,15 @@ def find_contour_and_peak(
12121218
# (note that these were computed prior to CDF weighting)
12131219
threshold = peak_db - threshold_std * peak_db_std
12141220

1215-
# pad left and right edges to handle signal that extends beyond segment edge
1216-
segment_pad = np.pad(segment, ((0,0),(1,1)))
1221+
# pad all edges to handle signal that butts up against segment edges
1222+
segment_pad = np.pad(segment, ((2,2),(2,2)))
12171223
contours = measure.find_contours(
12181224
segment_pad, level=threshold, fully_connected='high', positive_orientation='high'
12191225
)
12201226
# remove padding in output contour
12211227
for contour in contours:
1222-
contour[:,1] -= 1
1228+
contour[:,0] -= 2
1229+
contour[:,1] -= 2
12231230

12241231
# Display the image and plot all contours found
12251232
if output_path:
@@ -1249,6 +1256,11 @@ def find_contour_and_peak(
12491256

12501257
contour_ = np.vstack((y, x), dtype=contour.dtype).T
12511258
polygon_ = Polygon(contour).convex_hull
1259+
1260+
# Add small buffer to smoothed contour be sure to include maximum value location.
1261+
polygon = Polygon(contour).buffer(1.0)
1262+
xx, yy = polygon.exterior.coords.xy
1263+
contour_ = np.vstack((xx, yy)).T
12521264
assert idx not in counter
12531265
counter[idx] = (found, polygon_)
12541266

@@ -1299,13 +1311,16 @@ def calculate_harmonic_and_echo_flags(
12991311
write_contour_debug_image(negative_, index, 7, 'negative', output_path=output_path)
13001312

13011313
negative_skew = scipy.stats.skew(original[np.logical_and(nonzeros, negative)])
1302-
harmonic_skew = scipy.stats.skew(original[np.logical_and(nonzeros, harmonic)]) - negative_skew
1303-
if echo.any():
1304-
echo_skew = (
1305-
scipy.stats.skew(original[np.logical_and(np.logical_and(nonzeros, echo), ~harmonic)])
1306-
- negative_skew
1307-
)
1308-
else:
1314+
with warnings.catch_warnings():
1315+
# allow for nan outputs in cases of empty or mono-valued selections
1316+
warnings.simplefilter('ignore', category=RuntimeWarning)
1317+
selection = np.logical_and(nonzeros, harmonic)
1318+
harmonic_skew = scipy.stats.skew(original[selection]) - negative_skew
1319+
selection = np.logical_and(np.logical_and(nonzeros, echo), ~harmonic)
1320+
echo_skew = scipy.stats.skew(original[selection]) - negative_skew
1321+
if np.isnan(harmonic_skew):
1322+
harmonic_skew = -np.inf
1323+
if np.isnan(echo_skew):
13091324
echo_skew = -np.inf
13101325

13111326
skew_thresh = np.abs(negative_skew * 0.1)

0 commit comments

Comments
 (0)