Spaces:
Sleeping
Sleeping
aus10powell
commited on
Commit
•
74cd228
1
Parent(s):
ab934e0
Upload 32 files
Browse files- .gitattributes +2 -0
- Aptfile +4 -0
- Procfile +1 -0
- app.py +123 -0
- app_utils.py +83 -0
- centroidtracker.py +171 -0
- clipper.py +83 -0
- config.yaml +9 -0
- contour.py +5 -0
- counts.txt +1 -0
- herring.cfg +258 -0
- herring_count_all.csv +843 -0
- herring_final.weights +3 -0
- inference.py +168 -0
- inference_utils.py +131 -0
- notebooks/masking.ipynb +0 -0
- requirements.txt +73 -0
- setup.sh +9 -0
- static/test_images/1_2016-04-09_15-54-17_large.jpg +0 -0
- static/test_images/1_2016-04-13_13-57-11_large.jpg +0 -0
- static/test_images/1_2016-04-13_14-31-23_large.jpg +0 -0
- static/test_images/1_2016-04-13_18-03-24_large.jpg +0 -0
- static/test_images/1_2016-04-13_18-57-31_large.jpg +0 -0
- static/test_images/1_2016-04-13_19-00-23_large.jpg +0 -0
- static/test_images/1_2016-04-13_19-22-43_large.jpg +0 -0
- static/test_images/1_2016-04-14_12-01-34_large.jpg +0 -0
- static/test_images/herring_test_image.jpg +0 -0
- tests/__pycache__/test_streamlit.cpython-38-pytest-7.2.0.pyc +0 -0
- tests/__pycache__/test_streamlit.cpython-39-pytest-7.1.1.pyc +0 -0
- tests/__pycache__/test_streamlit.cpython-39-pytest-7.2.0.pyc +0 -0
- tests/test_streamlit.py +73 -0
- yolo2_out_py.mp4 +3 -0
- your_file.csv +130 -0
.gitattributes
CHANGED
@@ -32,3 +32,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
35 |
+
herring_final.weights filter=lfs diff=lfs merge=lfs -text
|
36 |
+
yolo2_out_py.mp4 filter=lfs diff=lfs merge=lfs -text
|
Aptfile
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
libsm6
|
2 |
+
libxrender1
|
3 |
+
libfontconfig1
|
4 |
+
libice6
|
Procfile
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
web: sh setup.sh && streamlit run app.py
|
app.py
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import matplotlib
|
2 |
+
|
3 |
+
matplotlib.use("Agg")
|
4 |
+
# Libraries
|
5 |
+
import streamlit as st
|
6 |
+
|
7 |
+
# Utility
|
8 |
+
import time
|
9 |
+
import io
|
10 |
+
import argparse
|
11 |
+
import sys
|
12 |
+
import os.path
|
13 |
+
import subprocess
|
14 |
+
import tempfile
|
15 |
+
import logging
|
16 |
+
|
17 |
+
# Viz
|
18 |
+
import altair as alt
|
19 |
+
import av
|
20 |
+
|
21 |
+
# ML
|
22 |
+
import numpy as np
|
23 |
+
import pandas as pd
|
24 |
+
import cv2 as cv
|
25 |
+
from PIL import Image, ImageOps
|
26 |
+
from tqdm import tqdm
|
27 |
+
|
28 |
+
# Custom
|
29 |
+
import inference
|
30 |
+
from app_utils import *
|
31 |
+
|
32 |
+
|
33 |
+
def run_app():
|
34 |
+
# Options
|
35 |
+
st.set_option("deprecation.showfileUploaderEncoding", False)
|
36 |
+
|
37 |
+
# App documentation
|
38 |
+
st.title("MIT Count Fish Counter")
|
39 |
+
st.text("Upload a video file to detect and count fish")
|
40 |
+
video_url = "yolo2_out_py.mp4" # Replace with the actual video URL or file path
|
41 |
+
video_bytes = open(video_url, "rb").read()
|
42 |
+
|
43 |
+
|
44 |
+
col1, col2 = st.columns(2)
|
45 |
+
|
46 |
+
## Col1 #########################################
|
47 |
+
with col1:
|
48 |
+
## Initial visualizations
|
49 |
+
# Historical values
|
50 |
+
st.altair_chart(
|
51 |
+
plot_historical_data(pd.read_csv("herring_count_all.csv")),
|
52 |
+
use_container_width=True,
|
53 |
+
)
|
54 |
+
|
55 |
+
# Locations
|
56 |
+
st.subheader("Map of Fishery Locations")
|
57 |
+
st.map(
|
58 |
+
pd.DataFrame(
|
59 |
+
np.random.randn(5, 2) / [50, 50] + [42.41, -71.38],
|
60 |
+
columns=["lat", "lon"],
|
61 |
+
)
|
62 |
+
)
|
63 |
+
|
64 |
+
## Col2 #########################################
|
65 |
+
with col2:
|
66 |
+
# Replace the loading message with the video
|
67 |
+
st.subheader("Example of processed video")
|
68 |
+
st.video(video_bytes)
|
69 |
+
st.subheader("Upload your own video...")
|
70 |
+
# Initialize
|
71 |
+
img_types = ["jpg", "png", "jpeg"]
|
72 |
+
video_types = ["mp4", "avi"]
|
73 |
+
uploaded_file = st.file_uploader(
|
74 |
+
"Select an image or video file...", type=img_types + video_types
|
75 |
+
)
|
76 |
+
|
77 |
+
# Display uploaded file
|
78 |
+
if uploaded_file is not None:
|
79 |
+
if str(uploaded_file.type).split("/")[-1] in img_types:
|
80 |
+
image = Image.open(uploaded_file)
|
81 |
+
st.image(image, caption="Uploaded image", use_column_width=True)
|
82 |
+
|
83 |
+
# TBD: Inference code to run and display for single image
|
84 |
+
|
85 |
+
elif str(uploaded_file.type).split("/")[-1] in video_types:
|
86 |
+
# Display uploaded file
|
87 |
+
st.video(uploaded_file)
|
88 |
+
|
89 |
+
# Convert streamlit video object to OpenCV format to run inferences
|
90 |
+
tfile = tempfile.NamedTemporaryFile(delete=False)
|
91 |
+
tfile.write(uploaded_file.read())
|
92 |
+
vf = cv.VideoCapture(tfile.name)
|
93 |
+
|
94 |
+
# Run inference
|
95 |
+
with st.spinner("Running inference..."):
|
96 |
+
frames, counts, timestamps = inference.main(vf)
|
97 |
+
logging.info("INFO: Completed running inference on frames")
|
98 |
+
st.balloons()
|
99 |
+
|
100 |
+
# Convert OpenCV Numpy frames in-memory to IO Bytes for streamlit
|
101 |
+
streamlit_video_file = frames_to_video(frames=frames, fps=11)
|
102 |
+
|
103 |
+
st.video(streamlit_video_file) # Show processed video\
|
104 |
+
st.download_button(
|
105 |
+
label="Download processed video",
|
106 |
+
data=streamlit_video_file,
|
107 |
+
mime="mp4",
|
108 |
+
file_name="processed_video.mp4",
|
109 |
+
)
|
110 |
+
df_counts_time = pd.DataFrame(
|
111 |
+
data={"fish_count": counts, "timestamps": timestamps[1:]}
|
112 |
+
)
|
113 |
+
st.altair_chart(
|
114 |
+
plot_count_date(dataframe=df_counts_time),
|
115 |
+
use_container_width=True,
|
116 |
+
)
|
117 |
+
|
118 |
+
else:
|
119 |
+
st.write("No file uploaded")
|
120 |
+
|
121 |
+
|
122 |
+
if __name__ == "__main__":
|
123 |
+
run_app()
|
app_utils.py
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Description: Functions that directly support the Streamlit app
|
3 |
+
"""
|
4 |
+
import pandas as pd
|
5 |
+
import altair as alt
|
6 |
+
import io
|
7 |
+
import av
|
8 |
+
from tqdm import tqdm
|
9 |
+
import numpy as np
|
10 |
+
import logging
|
11 |
+
|
12 |
+
|
13 |
+
def frames_to_video(frames=None, fps=12):
|
14 |
+
"""
|
15 |
+
Convert frames to video for Streamlit
|
16 |
+
|
17 |
+
Args:
|
18 |
+
frames: frame from cv2.VideoCapture as numpy. E.g. frame.astype(np.uint8)
|
19 |
+
fps: Frames per second. Usefull if inference video is compressed to slow down for analysis
|
20 |
+
"""
|
21 |
+
height, width, layers = frames[0].shape # grab info from first frame
|
22 |
+
output_memory_file = io.BytesIO() # Create BytesIO "in memory file".
|
23 |
+
|
24 |
+
output = av.open(
|
25 |
+
output_memory_file, "w", format="mp4"
|
26 |
+
) # Open "in memory file" as MP4 video output
|
27 |
+
stream = output.add_stream(
|
28 |
+
"h264", str(fps)
|
29 |
+
) # Add H.264 video stream to the MP4 container, with framerate = fps.
|
30 |
+
stream.width = width # Set frame width
|
31 |
+
stream.height = height # Set frame height
|
32 |
+
stream.pix_fmt = "yuv420p" # NOTE: yuv444p doesn't work on mac. Select yuv444p pixel format (better quality than default yuv420p).
|
33 |
+
stream.options = {
|
34 |
+
"crf": "17"
|
35 |
+
} # Select low crf for high quality (the price is larger file size).
|
36 |
+
|
37 |
+
# Iterate the created images, encode and write to MP4 memory file.
|
38 |
+
logging.info("INFO: Encoding frames and writing to MP4 format.")
|
39 |
+
for frame in tqdm(frames):
|
40 |
+
frame = av.VideoFrame.from_ndarray(frame.astype(np.uint8), format="bgr24")
|
41 |
+
packet = stream.encode(frame) # Encode video frame
|
42 |
+
output.mux(
|
43 |
+
packet
|
44 |
+
) # "Mux" the encoded frame (add the encoded frame to MP4 file).
|
45 |
+
|
46 |
+
packet = stream.encode(None) # Flush the encoder
|
47 |
+
output.mux(packet)
|
48 |
+
output.close()
|
49 |
+
|
50 |
+
output_memory_file.seek(0)
|
51 |
+
return output_memory_file
|
52 |
+
|
53 |
+
|
54 |
+
def plot_historical_data(dataframe):
|
55 |
+
"""Returns altair plot of historical counts to be rendered on main dashboard."""
|
56 |
+
dataframe["Date"] = pd.to_datetime(dataframe["Date"])
|
57 |
+
s = (
|
58 |
+
dataframe.resample(rule="D", on="Date")["Count"].sum().reset_index()
|
59 |
+
) # Resample on day
|
60 |
+
return (
|
61 |
+
alt.Chart(s, title="Historical Video Counts of Herring")
|
62 |
+
.mark_bar()
|
63 |
+
.transform_window(
|
64 |
+
# The field to average
|
65 |
+
rolling_mean="mean(Count)",
|
66 |
+
# The number of values before and after the current value to include.
|
67 |
+
frame=[-9, 0],
|
68 |
+
)
|
69 |
+
.encode(x="Date", y="Count", tooltip=["Count", "Date"])
|
70 |
+
.interactive()
|
71 |
+
)
|
72 |
+
|
73 |
+
|
74 |
+
def plot_count_date(dataframe):
|
75 |
+
"""Plots counts vs relative time for uploaded video."""
|
76 |
+
dataframe["seconds"] = dataframe["timestamps"] / 1000
|
77 |
+
dataframe["class"] = "Herring" # TBD: Hard-coded for now
|
78 |
+
return (
|
79 |
+
alt.Chart(dataframe, title="Processed video detected fish")
|
80 |
+
.mark_line()
|
81 |
+
.encode(x="seconds", y="fish_count", color="class")
|
82 |
+
.interactive()
|
83 |
+
)
|
centroidtracker.py
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import the necessary packages
|
2 |
+
from scipy.spatial import distance as dist
|
3 |
+
from collections import OrderedDict
|
4 |
+
import numpy as np
|
5 |
+
|
6 |
+
|
7 |
+
class CentroidTracker:
|
8 |
+
def __init__(self, maxDisappeared=50, maxDistance=50):
|
9 |
+
# initialize the next unique object ID along with two ordered
|
10 |
+
# dictionaries used to keep track of mapping a given object
|
11 |
+
# ID to its centroid and number of consecutive frames it has
|
12 |
+
# been marked as "disappeared", respectively
|
13 |
+
self.nextObjectID = 0
|
14 |
+
self.objects = OrderedDict()
|
15 |
+
self.disappeared = OrderedDict()
|
16 |
+
self.bbox = OrderedDict() # CHANGE
|
17 |
+
|
18 |
+
# store the number of maximum consecutive frames a given
|
19 |
+
# object is allowed to be marked as "disappeared" until we
|
20 |
+
# need to deregister the object from tracking
|
21 |
+
self.maxDisappeared = maxDisappeared
|
22 |
+
|
23 |
+
# store the maximum distance between centroids to associate
|
24 |
+
# an object -- if the distance is larger than this maximum
|
25 |
+
# distance we'll start to mark the object as "disappeared"
|
26 |
+
self.maxDistance = maxDistance
|
27 |
+
|
28 |
+
def register(self, centroid, inputRect):
|
29 |
+
# when registering an object we use the next available object
|
30 |
+
# ID to store the centroid
|
31 |
+
self.objects[self.nextObjectID] = centroid
|
32 |
+
self.bbox[self.nextObjectID] = inputRect # CHANGE
|
33 |
+
self.disappeared[self.nextObjectID] = 0
|
34 |
+
self.nextObjectID += 1
|
35 |
+
|
36 |
+
def deregister(self, objectID):
|
37 |
+
# to deregister an object ID we delete the object ID from
|
38 |
+
# both of our respective dictionaries
|
39 |
+
del self.objects[objectID]
|
40 |
+
del self.disappeared[objectID]
|
41 |
+
del self.bbox[objectID] # CHANGE
|
42 |
+
|
43 |
+
def update(self, rects):
|
44 |
+
# check to see if the list of input bounding box rectangles
|
45 |
+
# is empty
|
46 |
+
if len(rects) == 0:
|
47 |
+
# loop over any existing tracked objects and mark them
|
48 |
+
# as disappeared
|
49 |
+
for objectID in list(self.disappeared.keys()):
|
50 |
+
self.disappeared[objectID] += 1
|
51 |
+
|
52 |
+
# if we have reached a maximum number of consecutive
|
53 |
+
# frames where a given object has been marked as
|
54 |
+
# missing, deregister it
|
55 |
+
if self.disappeared[objectID] > self.maxDisappeared:
|
56 |
+
self.deregister(objectID)
|
57 |
+
|
58 |
+
# return early as there are no centroids or tracking info
|
59 |
+
# to update
|
60 |
+
# return self.objects
|
61 |
+
return self.bbox
|
62 |
+
|
63 |
+
# initialize an array of input centroids for the current frame
|
64 |
+
inputCentroids = np.zeros((len(rects), 2), dtype="int")
|
65 |
+
inputRects = []
|
66 |
+
# loop over the bounding box rectangles
|
67 |
+
for (i, (startX, startY, endX, endY)) in enumerate(rects):
|
68 |
+
# use the bounding box coordinates to derive the centroid
|
69 |
+
cX = int((startX + endX) / 2.0)
|
70 |
+
cY = int((startY + endY) / 2.0)
|
71 |
+
inputCentroids[i] = (cX, cY)
|
72 |
+
inputRects.append(rects[i]) # CHANGE
|
73 |
+
|
74 |
+
# if we are currently not tracking any objects take the input
|
75 |
+
# centroids and register each of them
|
76 |
+
if len(self.objects) == 0:
|
77 |
+
for i in range(0, len(inputCentroids)):
|
78 |
+
self.register(inputCentroids[i], inputRects[i]) # CHANGE
|
79 |
+
|
80 |
+
# otherwise, are are currently tracking objects so we need to
|
81 |
+
# try to match the input centroids to existing object
|
82 |
+
# centroids
|
83 |
+
else:
|
84 |
+
# grab the set of object IDs and corresponding centroids
|
85 |
+
objectIDs = list(self.objects.keys())
|
86 |
+
objectCentroids = list(self.objects.values())
|
87 |
+
|
88 |
+
# compute the distance between each pair of object
|
89 |
+
# centroids and input centroids, respectively -- our
|
90 |
+
# goal will be to match an input centroid to an existing
|
91 |
+
# object centroid
|
92 |
+
D = dist.cdist(np.array(objectCentroids), inputCentroids)
|
93 |
+
|
94 |
+
# in order to perform this matching we must (1) find the
|
95 |
+
# smallest value in each row and then (2) sort the row
|
96 |
+
# indexes based on their minimum values so that the row
|
97 |
+
# with the smallest value as at the *front* of the index
|
98 |
+
# list
|
99 |
+
rows = D.min(axis=1).argsort()
|
100 |
+
|
101 |
+
# next, we perform a similar process on the columns by
|
102 |
+
# finding the smallest value in each column and then
|
103 |
+
# sorting using the previously computed row index list
|
104 |
+
cols = D.argmin(axis=1)[rows]
|
105 |
+
|
106 |
+
# in order to determine if we need to update, register,
|
107 |
+
# or deregister an object we need to keep track of which
|
108 |
+
# of the rows and column indexes we have already examined
|
109 |
+
usedRows = set()
|
110 |
+
usedCols = set()
|
111 |
+
|
112 |
+
# loop over the combination of the (row, column) index
|
113 |
+
# tuples
|
114 |
+
for (row, col) in zip(rows, cols):
|
115 |
+
# if we have already examined either the row or
|
116 |
+
# column value before, ignore it
|
117 |
+
if row in usedRows or col in usedCols:
|
118 |
+
continue
|
119 |
+
|
120 |
+
# if the distance between centroids is greater than
|
121 |
+
# the maximum distance, do not associate the two
|
122 |
+
# centroids to the same object
|
123 |
+
if D[row, col] > self.maxDistance:
|
124 |
+
continue
|
125 |
+
|
126 |
+
# otherwise, grab the object ID for the current row,
|
127 |
+
# set its new centroid, and reset the disappeared
|
128 |
+
# counter
|
129 |
+
objectID = objectIDs[row]
|
130 |
+
self.objects[objectID] = inputCentroids[col]
|
131 |
+
self.bbox[objectID] = inputRects[col] # CHANGE
|
132 |
+
self.disappeared[objectID] = 0
|
133 |
+
|
134 |
+
# indicate that we have examined each of the row and
|
135 |
+
# column indexes, respectively
|
136 |
+
usedRows.add(row)
|
137 |
+
usedCols.add(col)
|
138 |
+
|
139 |
+
# compute both the row and column index we have NOT yet
|
140 |
+
# examined
|
141 |
+
unusedRows = set(range(0, D.shape[0])).difference(usedRows)
|
142 |
+
unusedCols = set(range(0, D.shape[1])).difference(usedCols)
|
143 |
+
|
144 |
+
# in the event that the number of object centroids is
|
145 |
+
# equal or greater than the number of input centroids
|
146 |
+
# we need to check and see if some of these objects have
|
147 |
+
# potentially disappeared
|
148 |
+
if D.shape[0] >= D.shape[1]:
|
149 |
+
# loop over the unused row indexes
|
150 |
+
for row in unusedRows:
|
151 |
+
# grab the object ID for the corresponding row
|
152 |
+
# index and increment the disappeared counter
|
153 |
+
objectID = objectIDs[row]
|
154 |
+
self.disappeared[objectID] += 1
|
155 |
+
|
156 |
+
# check to see if the number of consecutive
|
157 |
+
# frames the object has been marked "disappeared"
|
158 |
+
# for warrants deregistering the object
|
159 |
+
if self.disappeared[objectID] > self.maxDisappeared:
|
160 |
+
self.deregister(objectID)
|
161 |
+
|
162 |
+
# otherwise, if the number of input centroids is greater
|
163 |
+
# than the number of existing object centroids we need to
|
164 |
+
# register each new input centroid as a trackable object
|
165 |
+
else:
|
166 |
+
for col in unusedCols:
|
167 |
+
self.register(inputCentroids[col], inputRects[col])
|
168 |
+
|
169 |
+
# return the set of trackable objects
|
170 |
+
# return self.objects
|
171 |
+
return self.bbox
|
clipper.py
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import yaml
|
4 |
+
|
5 |
+
from contour import Contour
|
6 |
+
|
7 |
+
class Clipper():
|
8 |
+
def __init__(self): # TODO: put this in config
|
9 |
+
self.bg = None
|
10 |
+
self.seen_fish = False
|
11 |
+
self.vid_num = 1
|
12 |
+
self.load_config()
|
13 |
+
def load_config(self):
|
14 |
+
with open("config.yaml") as params:
|
15 |
+
config = yaml.safe_load(params)
|
16 |
+
self.MAX_CHUNK_SIZE = config.get("DST_VID_MAX_SECS") * config.get("DST_VID_FPS")
|
17 |
+
k_size = config.get("KERNEL_BLUR_PX")
|
18 |
+
self.BLUR_KERNEL = np.ones((k_size,k_size),np.uint8)
|
19 |
+
self.MIN_RAD = config.get("MIN_RADIUS_CONTOUR_PX")
|
20 |
+
self.cap = cv2.VideoCapture(config.get("SRC_VID_FP"))
|
21 |
+
self.dst_name = config.get("DST_VID_NAME")
|
22 |
+
self.dst_ftype = config.get("DST_VID_FILETYPE")
|
23 |
+
self.dst_vid_fp = config.get("DST_VID_FP")
|
24 |
+
self.dst_fps = config.get("DST_VID_FPS")
|
25 |
+
self.show_cnt = config.get("SHOW_CONTOUR")
|
26 |
+
def clip_vid(self):
|
27 |
+
""""
|
28 |
+
Truncates long video files into segments and saves them.
|
29 |
+
This prevents OutOfMemory exceptions caused by long videos.
|
30 |
+
"""
|
31 |
+
running = True
|
32 |
+
while running is True:
|
33 |
+
ret, frame = self.cap.read()
|
34 |
+
if not ret:
|
35 |
+
print(ret)
|
36 |
+
running = False
|
37 |
+
else:
|
38 |
+
if self.bg is None:
|
39 |
+
self.bg = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
40 |
+
cnt_list = Clipper.detect_contours(frame, self.bg, self.BLUR_KERNEL, self.MIN_RAD)
|
41 |
+
if len(cnt_list) > 0:
|
42 |
+
self.write_vid(cnt_list)
|
43 |
+
def write_vid(self, cnt_list):
|
44 |
+
fourcc = cv2.VideoWriter_fourcc('F', 'M', 'P', '4')
|
45 |
+
video = cv2.VideoWriter(self.dst_vid_fp + self.dst_name + str(self.vid_num) + self.dst_ftype, fourcc, self.dst_fps, (int(self.cap.get(3)), int(self.cap.get(4))))
|
46 |
+
frame_cnt = 0
|
47 |
+
while True:
|
48 |
+
ret, frame = self.cap.read()
|
49 |
+
if self.show_cnt:
|
50 |
+
for cnt in cnt_list:
|
51 |
+
frame = cv2.circle(frame, (cnt.x,cnt.y), cnt.rad, (0, 0, 255), 1)
|
52 |
+
video.write(frame)
|
53 |
+
frame_cnt += 1
|
54 |
+
cnt_list = Clipper.detect_contours(frame, self.bg, self.BLUR_KERNEL, self.MIN_RAD)
|
55 |
+
if (len(cnt_list) <= 0) or (frame_cnt > self.MAX_CHUNK_SIZE):
|
56 |
+
video.release()
|
57 |
+
self.vid_num += 1
|
58 |
+
break
|
59 |
+
@staticmethod
|
60 |
+
def detect_contours(frame, bg, kernel, min_rad):
|
61 |
+
# Use HSV colorspace to minimize lighting variance
|
62 |
+
img = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
63 |
+
|
64 |
+
# Take absolute value of difference and blur to denoise
|
65 |
+
difference = img - bg
|
66 |
+
greyscale = cv2.cvtColor(difference, cv2.COLOR_BGR2GRAY)
|
67 |
+
ret, thresh = cv2.threshold(greyscale, 150, 255, cv2.THRESH_BINARY)
|
68 |
+
erosion = cv2.erode(thresh, kernel, iterations = 1)
|
69 |
+
|
70 |
+
cnt_list = []
|
71 |
+
|
72 |
+
# Find contours > 15 px in diameter
|
73 |
+
contours, hierarchy = cv2.findContours(image=erosion, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)
|
74 |
+
for cnt in contours:
|
75 |
+
(x,y), radius = cv2.minEnclosingCircle(cnt)
|
76 |
+
if int(radius) > min_rad: # TODO Figure out smallest size of herring
|
77 |
+
cnt_list.append(Contour(int(x),int(y),int(radius)))
|
78 |
+
return cnt_list
|
79 |
+
|
80 |
+
if __name__ == "__main__":
|
81 |
+
# Script below to enable running pure inference from command line
|
82 |
+
c = Clipper()
|
83 |
+
c.clip_vid()
|
config.yaml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
DST_VID_NAME: "fish"
|
2 |
+
DST_VID_FILETYPE: ".mp4"
|
3 |
+
DST_VID_MAX_SECS: 10
|
4 |
+
DST_VID_FPS: 6
|
5 |
+
DST_VID_FP: "/home/lzuehsow/Downloads/"
|
6 |
+
SRC_VID_FP: "/home/lzuehsow/Downloads/2_2018-04-27_15-50-53.mp4"
|
7 |
+
SHOW_CONTOUR: True
|
8 |
+
MIN_RADIUS_CONTOUR_PX: 30
|
9 |
+
KERNEL_BLUR_PX: 5
|
contour.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
class Contour():
|
2 |
+
def __init__(self, x, y, rad):
|
3 |
+
self.x = x
|
4 |
+
self.y = y
|
5 |
+
self.rad = rad
|
counts.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
2
|
herring.cfg
ADDED
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[net]
|
2 |
+
# Testing
|
3 |
+
batch=64
|
4 |
+
subdivisions=8
|
5 |
+
# Training
|
6 |
+
# batch=64
|
7 |
+
# subdivisions=8
|
8 |
+
height=416
|
9 |
+
width=416
|
10 |
+
channels=3
|
11 |
+
momentum=0.9
|
12 |
+
decay=0.0005
|
13 |
+
angle=0
|
14 |
+
saturation = 1.5
|
15 |
+
exposure = 1.5
|
16 |
+
hue=.1
|
17 |
+
|
18 |
+
learning_rate=0.001
|
19 |
+
burn_in=1000
|
20 |
+
max_batches = 80200
|
21 |
+
policy=steps
|
22 |
+
steps=40000,60000
|
23 |
+
scales=.1,.1
|
24 |
+
|
25 |
+
[convolutional]
|
26 |
+
batch_normalize=1
|
27 |
+
filters=32
|
28 |
+
size=3
|
29 |
+
stride=1
|
30 |
+
pad=1
|
31 |
+
activation=leaky
|
32 |
+
|
33 |
+
[maxpool]
|
34 |
+
size=2
|
35 |
+
stride=2
|
36 |
+
|
37 |
+
[convolutional]
|
38 |
+
batch_normalize=1
|
39 |
+
filters=64
|
40 |
+
size=3
|
41 |
+
stride=1
|
42 |
+
pad=1
|
43 |
+
activation=leaky
|
44 |
+
|
45 |
+
[maxpool]
|
46 |
+
size=2
|
47 |
+
stride=2
|
48 |
+
|
49 |
+
[convolutional]
|
50 |
+
batch_normalize=1
|
51 |
+
filters=128
|
52 |
+
size=3
|
53 |
+
stride=1
|
54 |
+
pad=1
|
55 |
+
activation=leaky
|
56 |
+
|
57 |
+
[convolutional]
|
58 |
+
batch_normalize=1
|
59 |
+
filters=64
|
60 |
+
size=1
|
61 |
+
stride=1
|
62 |
+
pad=1
|
63 |
+
activation=leaky
|
64 |
+
|
65 |
+
[convolutional]
|
66 |
+
batch_normalize=1
|
67 |
+
filters=128
|
68 |
+
size=3
|
69 |
+
stride=1
|
70 |
+
pad=1
|
71 |
+
activation=leaky
|
72 |
+
|
73 |
+
[maxpool]
|
74 |
+
size=2
|
75 |
+
stride=2
|
76 |
+
|
77 |
+
[convolutional]
|
78 |
+
batch_normalize=1
|
79 |
+
filters=256
|
80 |
+
size=3
|
81 |
+
stride=1
|
82 |
+
pad=1
|
83 |
+
activation=leaky
|
84 |
+
|
85 |
+
[convolutional]
|
86 |
+
batch_normalize=1
|
87 |
+
filters=128
|
88 |
+
size=1
|
89 |
+
stride=1
|
90 |
+
pad=1
|
91 |
+
activation=leaky
|
92 |
+
|
93 |
+
[convolutional]
|
94 |
+
batch_normalize=1
|
95 |
+
filters=256
|
96 |
+
size=3
|
97 |
+
stride=1
|
98 |
+
pad=1
|
99 |
+
activation=leaky
|
100 |
+
|
101 |
+
[maxpool]
|
102 |
+
size=2
|
103 |
+
stride=2
|
104 |
+
|
105 |
+
[convolutional]
|
106 |
+
batch_normalize=1
|
107 |
+
filters=512
|
108 |
+
size=3
|
109 |
+
stride=1
|
110 |
+
pad=1
|
111 |
+
activation=leaky
|
112 |
+
|
113 |
+
[convolutional]
|
114 |
+
batch_normalize=1
|
115 |
+
filters=256
|
116 |
+
size=1
|
117 |
+
stride=1
|
118 |
+
pad=1
|
119 |
+
activation=leaky
|
120 |
+
|
121 |
+
[convolutional]
|
122 |
+
batch_normalize=1
|
123 |
+
filters=512
|
124 |
+
size=3
|
125 |
+
stride=1
|
126 |
+
pad=1
|
127 |
+
activation=leaky
|
128 |
+
|
129 |
+
[convolutional]
|
130 |
+
batch_normalize=1
|
131 |
+
filters=256
|
132 |
+
size=1
|
133 |
+
stride=1
|
134 |
+
pad=1
|
135 |
+
activation=leaky
|
136 |
+
|
137 |
+
[convolutional]
|
138 |
+
batch_normalize=1
|
139 |
+
filters=512
|
140 |
+
size=3
|
141 |
+
stride=1
|
142 |
+
pad=1
|
143 |
+
activation=leaky
|
144 |
+
|
145 |
+
[maxpool]
|
146 |
+
size=2
|
147 |
+
stride=2
|
148 |
+
|
149 |
+
[convolutional]
|
150 |
+
batch_normalize=1
|
151 |
+
filters=1024
|
152 |
+
size=3
|
153 |
+
stride=1
|
154 |
+
pad=1
|
155 |
+
activation=leaky
|
156 |
+
|
157 |
+
[convolutional]
|
158 |
+
batch_normalize=1
|
159 |
+
filters=512
|
160 |
+
size=1
|
161 |
+
stride=1
|
162 |
+
pad=1
|
163 |
+
activation=leaky
|
164 |
+
|
165 |
+
[convolutional]
|
166 |
+
batch_normalize=1
|
167 |
+
filters=1024
|
168 |
+
size=3
|
169 |
+
stride=1
|
170 |
+
pad=1
|
171 |
+
activation=leaky
|
172 |
+
|
173 |
+
[convolutional]
|
174 |
+
batch_normalize=1
|
175 |
+
filters=512
|
176 |
+
size=1
|
177 |
+
stride=1
|
178 |
+
pad=1
|
179 |
+
activation=leaky
|
180 |
+
|
181 |
+
[convolutional]
|
182 |
+
batch_normalize=1
|
183 |
+
filters=1024
|
184 |
+
size=3
|
185 |
+
stride=1
|
186 |
+
pad=1
|
187 |
+
activation=leaky
|
188 |
+
|
189 |
+
|
190 |
+
#######
|
191 |
+
|
192 |
+
[convolutional]
|
193 |
+
batch_normalize=1
|
194 |
+
size=3
|
195 |
+
stride=1
|
196 |
+
pad=1
|
197 |
+
filters=1024
|
198 |
+
activation=leaky
|
199 |
+
|
200 |
+
[convolutional]
|
201 |
+
batch_normalize=1
|
202 |
+
size=3
|
203 |
+
stride=1
|
204 |
+
pad=1
|
205 |
+
filters=1024
|
206 |
+
activation=leaky
|
207 |
+
|
208 |
+
[route]
|
209 |
+
layers=-9
|
210 |
+
|
211 |
+
[convolutional]
|
212 |
+
batch_normalize=1
|
213 |
+
size=1
|
214 |
+
stride=1
|
215 |
+
pad=1
|
216 |
+
filters=64
|
217 |
+
activation=leaky
|
218 |
+
|
219 |
+
[reorg]
|
220 |
+
stride=2
|
221 |
+
|
222 |
+
[route]
|
223 |
+
layers=-1,-4
|
224 |
+
|
225 |
+
[convolutional]
|
226 |
+
batch_normalize=1
|
227 |
+
size=3
|
228 |
+
stride=1
|
229 |
+
pad=1
|
230 |
+
filters=1024
|
231 |
+
activation=leaky
|
232 |
+
|
233 |
+
[convolutional]
|
234 |
+
size=1
|
235 |
+
stride=1
|
236 |
+
pad=1
|
237 |
+
filters=30
|
238 |
+
activation=linear
|
239 |
+
|
240 |
+
|
241 |
+
[region]
|
242 |
+
anchors = 1.3221, 1.73145, 3.19275, 4.00944, 5.05587, 8.09892, 9.47112, 4.84053, 11.2364, 10.0071
|
243 |
+
bias_match=1
|
244 |
+
classes=1
|
245 |
+
coords=4
|
246 |
+
num=5
|
247 |
+
softmax=1
|
248 |
+
jitter=.3
|
249 |
+
rescore=1
|
250 |
+
|
251 |
+
object_scale=5
|
252 |
+
noobject_scale=1
|
253 |
+
class_scale=1
|
254 |
+
coord_scale=1
|
255 |
+
|
256 |
+
absolute=1
|
257 |
+
thresh = .6
|
258 |
+
random=1
|
herring_count_all.csv
ADDED
@@ -0,0 +1,843 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Date,Time,Species,Count
|
2 |
+
4-11-17,12:02:00,herring,2.0
|
3 |
+
4-11-17,12:25:00,herring,1.0
|
4 |
+
4-13-17,18:01:00,herring,1.0
|
5 |
+
4-13-17,14:58:00,herring,1.0
|
6 |
+
4-13-17,14:48:00,herring,1.0
|
7 |
+
4-13-17,14:10:00,herring,3.0
|
8 |
+
4-13-17,13:39:00,herring,1.0
|
9 |
+
4-13-17,13:23:00,herring,1.0
|
10 |
+
4-13-17,15:13:00,herring,1.0
|
11 |
+
4-13-17,12:39:00,herring,3.0
|
12 |
+
4-13-17,12:26:00,herring,2.0
|
13 |
+
4-13-17,11:48:00,herring,1.0
|
14 |
+
4-13-17,11:40:00,herring,1.0
|
15 |
+
4-13-17,11:30:00,herring,1.0
|
16 |
+
4-13-17,10:39:00,herring,1.0
|
17 |
+
4-13-17,13:10:00,herring,1.0
|
18 |
+
4-14-17,18:41:00,herring,2.0
|
19 |
+
4-14-17,18:45:00,herring,1.0
|
20 |
+
4-15-17,12:04:00,herring,2.0
|
21 |
+
4-15-17,11:23:00,herring,1.0
|
22 |
+
4-15-17,8:20:00,herring,2.0
|
23 |
+
4-15-17,9:07:00,herring,1.0
|
24 |
+
4-15-17,11:00:00,herring,1.0
|
25 |
+
4-16-17,14:05:00,herring,1.0
|
26 |
+
4-16-17,15:18:00,herring,1.0
|
27 |
+
4-16-17,15:30:00,herring,1.0
|
28 |
+
4-17-17,17:55:00,herring,1.0
|
29 |
+
4-17-17,18:00:00,herring,2.0
|
30 |
+
4-17-17,17:45:00,herring,4.0
|
31 |
+
4-17-17,18:48:00,herring,1.0
|
32 |
+
4-17-17,10:34:00,herring,2.0
|
33 |
+
4-17-17,10:12:00,herring,1.0
|
34 |
+
4-17-17,10:12:00,herring,1.0
|
35 |
+
4-17-17,17:27:00,herring,1.0
|
36 |
+
4-18-17,7:55:00,herring,3.0
|
37 |
+
4-18-17,9:47:00,herring,2.0
|
38 |
+
4-18-17,9:59:00,herring,1.0
|
39 |
+
4-18-17,10:58:00,herring,1.0
|
40 |
+
4-18-17,12:43:00,herring,1.0
|
41 |
+
4-18-17,14:04:00,herring,1.0
|
42 |
+
4-18-17,14:20:00,herring,2.0
|
43 |
+
4-18-17,17:08:00,herring,1.0
|
44 |
+
4-18-17,17:15:00,herring,3.0
|
45 |
+
4-18-17,17:17:00,herring,1.0
|
46 |
+
4-18-17,18:02:00,herring,2.0
|
47 |
+
4-19-17,8:26:00,herring,1.0
|
48 |
+
4-19-17,19:00:00,herring,3.0
|
49 |
+
4-19-17,7:45:00,herring,1.0
|
50 |
+
4-19-17,8:11:00,herring,1.0
|
51 |
+
4-20-17,6:59:00,herring,1.0
|
52 |
+
4-20-17,11:51:00,herring,1.0
|
53 |
+
4-21-17,16:02:00,herring,1.0
|
54 |
+
4-22-17,1:13:00,herring,1.0
|
55 |
+
4-22-17,13:13:00,herring,1.0
|
56 |
+
4-22-17,14:15:00,herring,1.0
|
57 |
+
4-24-17,15:21:00,herring,1.0
|
58 |
+
4-24-17,17:39:00,herring,1.0
|
59 |
+
4-24-17,17:24:00,herring,1.0
|
60 |
+
4-24-17,15:32:00,herring,1.0
|
61 |
+
4-24-17,5:51:00,herring,1.0
|
62 |
+
4-24-17,15:21:00,herring,1.0
|
63 |
+
4-25-17,13:17:00,herring,2.0
|
64 |
+
4-25-17,17:52:00,herring,3.0
|
65 |
+
4-25-17,17:35:00,herring,2.0
|
66 |
+
4-25-17,15:36:00,herring,1.0
|
67 |
+
4-25-17,15:21:00,herring,3.0
|
68 |
+
4-25-17,13:24:00,herring,1.0
|
69 |
+
4-25-17,12:58:00,herring,2.0
|
70 |
+
4-25-17,10:53:00,herring,1.0
|
71 |
+
4-25-17,7:30:00,herring,1.0
|
72 |
+
4-25-17,7:07:00,herring,1.0
|
73 |
+
4-25-17,7:03:00,herring,1.0
|
74 |
+
4-25-17,7:02:00,herring,1.0
|
75 |
+
4-25-17,6:26:00,herring,2.0
|
76 |
+
4-25-17,6:19:00,herring,1.0
|
77 |
+
4-25-17,5:58:00,herring,1.0
|
78 |
+
4-25-17,10:37:00,herring,1.0
|
79 |
+
4-28-17,6:58:00,herring,3.0
|
80 |
+
4-29-17,17:37:00,herring,3.0
|
81 |
+
4-29-17,17:59:00,herring,2.0
|
82 |
+
4-29-17,17:43:00,herring,1.0
|
83 |
+
4-29-17,18:32:00,herring,2.0
|
84 |
+
4-29-17,19:20:00,herring,1.0
|
85 |
+
4-29-17,17:32:00,herring,1.0
|
86 |
+
4-29-17,18:28:00,herring,2.0
|
87 |
+
4-29-17,17:23:00,herring,3.0
|
88 |
+
4-29-17,15:28:00,herring,5.0
|
89 |
+
4-29-17,15:58:00,herring,1.0
|
90 |
+
4-29-17,12:50:00,herring,1.0
|
91 |
+
4-29-17,11:17:00,herring,1.0
|
92 |
+
4-29-17,9:09:00,herring,1.0
|
93 |
+
4-29-17,6:20:00,herring,1.0
|
94 |
+
4-29-17,6:19:00,herring,1.0
|
95 |
+
4-29-17,16:08:00,herring,1.0
|
96 |
+
4-30-17,16:35:00,herring,4.0
|
97 |
+
4-30-17,17:21:00,herring,1.0
|
98 |
+
4-30-17,16:41:00,herring,3.0
|
99 |
+
4-30-17,14:55:00,herring,2.0
|
100 |
+
4-30-17,7:36:00,herring,3.0
|
101 |
+
4-30-17,8:59:00,herring,2.0
|
102 |
+
4-30-17,8:18:00,herring,1.0
|
103 |
+
4-30-17,7:41:00,herring,2.0
|
104 |
+
4-30-17,13:14:00,herring,1.0
|
105 |
+
4/13/16,13:19:22,herring,1.0
|
106 |
+
4/13/16,13:19:0,herring,1.0
|
107 |
+
4/13/16,13:14:31,herring,1.0
|
108 |
+
4/13/16,13:18:3,herring,2.0
|
109 |
+
4/13/16,13:18:11,herring,1.0
|
110 |
+
4/13/16,13:16:3,herring,1.0
|
111 |
+
4/13/16,13:13:57,herring,1.0
|
112 |
+
4/13/18,11:00:03,Herring,1.0
|
113 |
+
4/14/16,14:19:12,herring,1.0
|
114 |
+
4/14/16,14:12:1,herring,5.0
|
115 |
+
4/14/16,14:18:41,herring,1.0
|
116 |
+
4/14/16,14:19:23,herring,1.0
|
117 |
+
4/14/18,17:33:33,Herring,1.0
|
118 |
+
4/14/18,17:12:42,Herring,1.0
|
119 |
+
4/14/18,13:18:51,Herring,1.0
|
120 |
+
4/14/18,17:45:05,Herring,1.0
|
121 |
+
4/14/18,10:06:19,Herring,1.0
|
122 |
+
4/14/18,17:45:05,Herring,1.0
|
123 |
+
4/14/18,9:57:26,Herring,1.0
|
124 |
+
4/15/16,15:14:36,herring,1.0
|
125 |
+
4/15/16,15:13:45,herring,1.0
|
126 |
+
4/21/15,17:22:29,Herring,1.0
|
127 |
+
4/21/15,17:13:33,Herring,1.0
|
128 |
+
4/21/15,18:51:1,Herring,1.0
|
129 |
+
4/22/15,22:41:53,Herring,1.0
|
130 |
+
4/22/16,22:10:49,herring,1.0
|
131 |
+
4/22/16,22:12:19,herring,2.0
|
132 |
+
4/22/16,22:12:33,herring,1.0
|
133 |
+
4/22/16,22:6:49,herring,4.0
|
134 |
+
4/22/16,22:15:56,herring,3.0
|
135 |
+
4/22/16,22:16:50,herring,3.0
|
136 |
+
4/22/16,22:16:51,herring,4.0
|
137 |
+
4/22/16,22:17:3,herring,2.0
|
138 |
+
4/22/16,22:6:44,herring,5.0
|
139 |
+
4/22/16,22:6:32,herring,2.0
|
140 |
+
4/22/16,22:9:14,herring,2.0
|
141 |
+
4/22/16,22:12:36,herring,2.0
|
142 |
+
4/22/16,22:1:10,herring,2.0
|
143 |
+
4/22/18,14:12:15,Herring,1.0
|
144 |
+
4/22/18,7:21:04,Herring,1.0
|
145 |
+
4/22/18,7:10:37,Herring,1.0
|
146 |
+
4/23/15,10:47:44,Herring,1.0
|
147 |
+
4/23/15,1:34:23,Herring,1.0
|
148 |
+
4/23/15,12:4:7,Herring,1.0
|
149 |
+
4/23/15,17:26:30,Herring,1.0
|
150 |
+
4/23/15,15:2:11,Herring,1.0
|
151 |
+
4/23/15,14:35:24,Herring,1.0
|
152 |
+
4/23/16,23:16:6,herring,3.0
|
153 |
+
4/23/16,23:16:30,herring,3.0
|
154 |
+
4/23/16,23:16:35,herring,5.0
|
155 |
+
4/23/16,23:17:26,herring,2.0
|
156 |
+
4/23/16,23:10:56,herring,5.0
|
157 |
+
4/23/16,23:11:10,herring,3.0
|
158 |
+
4/24/15,16:14:23,Herring,1.0
|
159 |
+
4/24/15,15:29:29,Herring,1.0
|
160 |
+
4/24/16,24:18:30,herring,1.0
|
161 |
+
4/24/16,24:16:20,herring,2.0
|
162 |
+
4/24/16,24:16:6,herring,1.0
|
163 |
+
4/24/16,24:15:38,herring,3.0
|
164 |
+
4/25/15,11:29:6,Herring,1.0
|
165 |
+
4/25/15,13:50:12,Herring,1.0
|
166 |
+
4/25/15,15:40:17,Herring,1.0
|
167 |
+
4/25/15,16:17:37,Herring,1.0
|
168 |
+
4/26/18,15:03:21,Herring,4.0
|
169 |
+
4/27/18,17:46:36,herring,3.0
|
170 |
+
4/27/18,17:32:07,Herring,1.0
|
171 |
+
4/27/18,17:13:16,Herring,1.0
|
172 |
+
4/27/18,17:12:57,Herring,1.0
|
173 |
+
4/27/18,16:48:38,Herring,3.0
|
174 |
+
4/27/18,13:53:06,Herring,1.0
|
175 |
+
4/27/18,16:31:05,Herring,3.0
|
176 |
+
4/27/18,16:02:17,Herring,2.0
|
177 |
+
4/27/18,15:50:53,Herring,4.0
|
178 |
+
4/27/18,15:41:54,Herring,1.0
|
179 |
+
4/27/18,12:31:53,Herring,2.0
|
180 |
+
4/27/18,18:31:15,Herring,1.0
|
181 |
+
4/27/18,12:19:34,Herring,1.0
|
182 |
+
4/27/18,16:36:08,Herring,3.0
|
183 |
+
4/27/18,19:23:06,herring,1.0
|
184 |
+
4/27/18,12:01:34,Herring,1.0
|
185 |
+
4/28/15,19:15:9,Herring,2.0
|
186 |
+
4/28/15,18:28:5,Herring,2.0
|
187 |
+
4/28/17,10:16:14,herring,2.0
|
188 |
+
4/28/18,10:16:14,Herring,2.0
|
189 |
+
4/28/18,13:11:51,Herring,1.0
|
190 |
+
4/28/18,11:25:56,Herring,2.0
|
191 |
+
4/28/18,11:25:56,Herring,2.0
|
192 |
+
4/28/18,10:54:38,Herring,3.0
|
193 |
+
4/28/18,10:36:04,Herring,2.0
|
194 |
+
4/29/15,13:30:50,Herring,1.0
|
195 |
+
4/29/15,7:44:18,Herring,1.0
|
196 |
+
4/29/15,19:46:30,Herring,1.0
|
197 |
+
4/29/18,18:31:06,Herring,1.0
|
198 |
+
4/29/18,18:33:45,Herring,1.0
|
199 |
+
4/29/18,9:34:24,Herring,1.0
|
200 |
+
4/29/18,19:08:39,Herring,1.0
|
201 |
+
4/29/18,18:27:20,Herring,1.0
|
202 |
+
4/29/18,18:51:11,Herring,1.0
|
203 |
+
4/29/18,17:59:40,Herring,5.0
|
204 |
+
4/29/18,17:12:32,herring,2.0
|
205 |
+
4/29/18,17:33:32,Herring,2.0
|
206 |
+
4/29/18,17:16:10,Herring,1.0
|
207 |
+
4/29/18,10:25:43,Herring,1.0
|
208 |
+
4/29/18,17:05:28,herring,1.0
|
209 |
+
4/29/18,16:54:05,Herring,1.0
|
210 |
+
4/29/18,16:17:14,Herring,1.0
|
211 |
+
4/29/18,15:55:24,herring,2.0
|
212 |
+
4/29/18,14:26:34,herring,2.0
|
213 |
+
4/29/18,7:46:46,Herring,1.0
|
214 |
+
4/29/18,8:28:10,Herring,1.0
|
215 |
+
4/29/18,9:14:03,Herring,1.0
|
216 |
+
4/29/18,17:36:58,Herring,1.0
|
217 |
+
4/29/18,16:28:35,Herring,2.0
|
218 |
+
4/30/15,21:28:38,Herring,1.0
|
219 |
+
4/30/16,30:11:50,herring,1.0
|
220 |
+
4/30/18,11:38:38,Herring,2.0
|
221 |
+
4/30/18,11:49:17,Herring,1.0
|
222 |
+
4/30/18,12:31:35,Herring,1.0
|
223 |
+
4/30/18,14:34:01,Herring,1.0
|
224 |
+
4/30/18,11:27:13,Herring,1.0
|
225 |
+
5-1-17,10:23:00,herring,1.0
|
226 |
+
5-1-17,11:53:00,herring,1.0
|
227 |
+
5-1-17,12:57:00,herring,1.0
|
228 |
+
5-10-17,14:10:00,herring,1.0
|
229 |
+
5-10-17,13:19:00,herring,4.0
|
230 |
+
5-10-17,18:43:00,herring,1.0
|
231 |
+
5-10-17,6:43:00,herring,1.0
|
232 |
+
5-10-17,13:29:00,herring,2.0
|
233 |
+
5-11-17,18:56:00,herring,1.0
|
234 |
+
5-11-17,14:16:00,herring,2.0
|
235 |
+
5-11-17,16:27:00,herring,1.0
|
236 |
+
5-11-17,16:54:00,herring,2.0
|
237 |
+
5-11-17,16:27:00,herring,2.0
|
238 |
+
5-11-17,15:49:00,herring,1.0
|
239 |
+
5-11-17,14:58:00,herring,2.0
|
240 |
+
5-11-17,7:42:00,herring,1.0
|
241 |
+
5-11-17,9:20:00,herring,1.0
|
242 |
+
5-11-17,9:54:00,herring,1.0
|
243 |
+
5-11-17,14:45:00,herring,1.0
|
244 |
+
5-11-17,14:28:00,herring,2.0
|
245 |
+
5-12-17,11:49:00,herring,1.0
|
246 |
+
5-12-17,17:04:00,herring,1.0
|
247 |
+
5-12-17,17:49:00,herring,1.0
|
248 |
+
5-12-17,9:07:00,herring,2.0
|
249 |
+
5-12-17,9:25:00,herring,1.0
|
250 |
+
5-12-17,8:53:00,herring,1.0
|
251 |
+
5-12-17,7:06:00,herring,1.0
|
252 |
+
5-12-17,9:57:00,herring,3.0
|
253 |
+
5-13-17,12:07:00,herring,1.0
|
254 |
+
5-13-17,6:45:00,herring,2.0
|
255 |
+
5-13-17,7:02:00,herring,1.0
|
256 |
+
5-13-17,7:10:00,herring,1.0
|
257 |
+
5-13-17,9:39:00,herring,2.0
|
258 |
+
5-13-17,10:54:00,herring,1.0
|
259 |
+
5-13-17,18:28:00,herring,1.0
|
260 |
+
5-17-17,9:35:00,herring,3.0
|
261 |
+
5-17-17,10:11:00,herring,3.0
|
262 |
+
5-17-17,10:51:00,herring,1.0
|
263 |
+
5-17-17,12:17:00,herring,1.0
|
264 |
+
5-17-17,23:18:00,herring,1.0
|
265 |
+
5-17-17,13:21:00,herring,1.0
|
266 |
+
5-17-17,15:30:00,herring,2.0
|
267 |
+
5-18-17,8:17:00,herring,1.0
|
268 |
+
5-18-17,13:31:00,herring,1.0
|
269 |
+
5-18-17,8:01:00,herring,2.0
|
270 |
+
5-18-17,13:55:00,herring,1.0
|
271 |
+
5-18-17,14:05:00,herring,2.0
|
272 |
+
5-18-17,14:33:00,herring,1.0
|
273 |
+
5-18-17,15:04:00,herring,1.0
|
274 |
+
5-18-17,19:13:00,herring,1.0
|
275 |
+
5-18-17,21:22:00,herring,1.0
|
276 |
+
5-18-17,7:46:00,herring,2.0
|
277 |
+
5-18-17,13:12:00,herring,1.0
|
278 |
+
5-18-17,13:18:00,herring,1.0
|
279 |
+
5-19-17,8:45:00,herring,1.0
|
280 |
+
5-19-17,9:48:00,herring,2.0
|
281 |
+
5-19-17,14:04:00,herring,1.0
|
282 |
+
5-19-17,14:32:00,herring,2.0
|
283 |
+
5-19-17,15:57:00,herring,1.0
|
284 |
+
5-20-17,6:27:00,herring,1.0
|
285 |
+
5-20-17,15:20:00,herring,3.0
|
286 |
+
5-20-17,15:26:00,herring,3.0
|
287 |
+
5-20-17,8:43:00,herring,2.0
|
288 |
+
5-20-17,16:38:00,herring,3.0
|
289 |
+
5-21-17,14:19:00,herring,1.0
|
290 |
+
5-22-17,16:40:00,herring,1.0
|
291 |
+
5-22-17,7:57:00,herring,2.0
|
292 |
+
5-22-17,16:37:00,herring,1.0
|
293 |
+
5-29-17,8:33:00,herring,1.0
|
294 |
+
5-4-17,17:16:00,herring,2.0
|
295 |
+
5-4-17,15:17:00,herring,1.0
|
296 |
+
5-5-17,13:39:00,herring,1.0
|
297 |
+
5-5-17,13:46:00,herring,3.0
|
298 |
+
5-5-17,15:16:00,herring,1.0
|
299 |
+
5-5-17,16:26:00,herring,1.0
|
300 |
+
5-6-17,17:21:00,herring,1.0
|
301 |
+
5-6-17,16:11:00,herring,1.0
|
302 |
+
5-6-17,15:54:00,herring,1.0
|
303 |
+
5-6-17,15:50:00,herring,2.0
|
304 |
+
5-6-17,15:04:00,herring,1.0
|
305 |
+
5-6-17,14:54:00,herring,1.0
|
306 |
+
5-6-17,17:37:00,herring,1.0
|
307 |
+
5-6-17,18:29:00,herring,1.0
|
308 |
+
5-7-17,19:40:00,herring,1.0
|
309 |
+
5-8-17,9:07:00,herring,1.0
|
310 |
+
5-8-17,9:58:00,herring,1.0
|
311 |
+
5-8-17,10:06:00,herring,1.0
|
312 |
+
5-8-17,10:15:00,herring,1.0
|
313 |
+
5-8-17,10:22:00,herring,1.0
|
314 |
+
5-8-17,11:37:00,herring,1.0
|
315 |
+
5-8-17,15:24:00,herring,2.0
|
316 |
+
5-8-17,17:51:00,herring,2.0
|
317 |
+
5-8-17,10:20:00,herring,1.0
|
318 |
+
5/1/15,16:20:26,Herring,1.0
|
319 |
+
5/1/15,7:36:1,Herring,1.0
|
320 |
+
5/1/15,16:53:23,Herring,1.0
|
321 |
+
5/1/15,17:31:1,Herring,1.0
|
322 |
+
5/1/18,8:37:04,Herring,1.0
|
323 |
+
5/1/18,8:54:14,Herring,1.0
|
324 |
+
5/1/18,18:11:56,Herring,1.0
|
325 |
+
5/1/18,6:05:06,Herring,1.0
|
326 |
+
5/10/15,13:11:35,Herring,1.0
|
327 |
+
5/10/15,12:57:30,Herring,1.0
|
328 |
+
5/10/15,22:1:25,Herring,1.0
|
329 |
+
5/10/15,12:53:45,Herring,1.0
|
330 |
+
5/10/15,5:58:13,Herring,2.0
|
331 |
+
5/10/15,5:49:40,Herring,4.0
|
332 |
+
5/10/15,13:16:0,Herring,2.0
|
333 |
+
5/10/15,13:30:44,Herring,1.0
|
334 |
+
5/10/15,13:31:21,Herring,2.0
|
335 |
+
5/10/15,4:4:25,Herring,1.0
|
336 |
+
5/10/15,14:19:31,Herring,3.0
|
337 |
+
5/10/15,14:43:27,Herring,3.0
|
338 |
+
5/10/15,15:52:57,Herring,3.0
|
339 |
+
5/10/15,17:39:4,Herring,1.0
|
340 |
+
5/10/15,20:3:47,Herring,2.0
|
341 |
+
5/10/15,13:44:16,Herring,2.0
|
342 |
+
5/10/16,10:20:5,herring,2.0
|
343 |
+
5/10/16,10:15:16,herring,1.0
|
344 |
+
5/10/16,10:19:44,herring,2.0
|
345 |
+
5/10/16,10:19:53,herring,13.0
|
346 |
+
5/10/16,10:19:54,herring,10.0
|
347 |
+
5/10/16,10:19:58,herring,3.0
|
348 |
+
5/10/16,10:19:59,herring,1.0
|
349 |
+
5/10/16,10:20:9,herring,1.0
|
350 |
+
5/10/16,10:19:52,herring,4.0
|
351 |
+
5/10/16,10:19:18,herring,15.0
|
352 |
+
5/10/18,17:50:04,Herring,2.0
|
353 |
+
5/10/18,11:30:08,Herring,2.0
|
354 |
+
5/10/18,10:23:05,Herring,1.0
|
355 |
+
5/10/18,10:20:15,Herring,3.0
|
356 |
+
5/10/18,6:39:30,Herring,4.0
|
357 |
+
5/10/18,13:35:12,Herring,1.0
|
358 |
+
5/10/18,14:59:27,Herring,1.0
|
359 |
+
5/10/18,17:24:24,Herring,3.0
|
360 |
+
5/10/18,17:43:39,Herring,1.0
|
361 |
+
5/10/18,13:22:03,Herring,1.0
|
362 |
+
5/10/18,12:05:08,Herring,1.0
|
363 |
+
5/11/15,20:3:16,Herring,1.0
|
364 |
+
5/11/15,19:7:57,Herring,2.0
|
365 |
+
5/11/15,19:7:37,Herring,2.0
|
366 |
+
5/11/15,19:3:18,Herring,1.0
|
367 |
+
5/11/15,18:51:24,Herring,2.0
|
368 |
+
5/11/15,16:11:2,Herring,1.0
|
369 |
+
5/11/15,2:10:7,Herring,1.0
|
370 |
+
5/11/15,18:41:49,Herring,2.0
|
371 |
+
5/11/16,11:19:56,herring,1.0
|
372 |
+
5/11/16,11:19:44,herring,3.0
|
373 |
+
5/11/16,11:19:8,herring,1.0
|
374 |
+
5/11/16,11:19:26,herring,1.0
|
375 |
+
5/11/16,11:19:36,herring,2.0
|
376 |
+
5/11/16,11:19:38,herring,4.0
|
377 |
+
5/11/16,11:19:5,herring,9.0
|
378 |
+
5/11/18,6:44:05,Herring,1.0
|
379 |
+
5/11/18,10:06:20,Herring,2.0
|
380 |
+
5/11/18,10:44:39,Herring,1.0
|
381 |
+
5/11/18,19:06:07,Herring,2.0
|
382 |
+
5/12/15,14:52:1,Herring,4.0
|
383 |
+
5/12/15,5:46:1,Herring,2.0
|
384 |
+
5/12/15,11:18:7,Herring,1.0
|
385 |
+
5/12/15,19:19:15,Herring,2.0
|
386 |
+
5/12/15,20:13:15,Herring,2.0
|
387 |
+
5/12/15,18:4:34,Herring,1.0
|
388 |
+
5/12/15,20:26:51,Herring,1.0
|
389 |
+
5/12/15,0:3:16,Herring,1.0
|
390 |
+
5/12/15,4:55:33,Herring,1.0
|
391 |
+
5/12/15,0:20:2,Herring,1.0
|
392 |
+
5/12/15,5:42:19,Herring,1.0
|
393 |
+
5/12/15,20:11:31,Herring,1.0
|
394 |
+
5/12/15,5:38:53,Herring,1.0
|
395 |
+
5/12/15,0:42:31,Herring,1.0
|
396 |
+
5/12/15,5:54:49,Herring,1.0
|
397 |
+
5/12/15,5:50:58,Herring,2.0
|
398 |
+
5/12/15,13:28:49,Herring,1.0
|
399 |
+
5/12/16,12:12:34,herring,1.0
|
400 |
+
5/12/16,12:18:38,herring,2.0
|
401 |
+
5/12/16,12:18:21,herring,1.0
|
402 |
+
5/12/16,12:18:10,herring,1.0
|
403 |
+
5/12/16,12:18:36,herring,3.0
|
404 |
+
5/12/16,12:11:42,herring,1.0
|
405 |
+
5/12/16,12:5:52,herring,3.0
|
406 |
+
5/12/16,12:18:26,herring,4.0
|
407 |
+
5/12/16,12:15:34,herring,5.0
|
408 |
+
5/12/16,12:18:22,herring,7.0
|
409 |
+
5/12/18,14:13:19,herring,1.0
|
410 |
+
5/12/18,17:49:34,herring,3.0
|
411 |
+
5/12/18,17:56:58,Herring,2.0
|
412 |
+
5/12/18,19:02:42,Herring,1.0
|
413 |
+
5/12/18,11:22:30,Herring,4.0
|
414 |
+
5/12/18,5:50:10,Herring,1.0
|
415 |
+
5/13/16,13:16:42,herring,1.0
|
416 |
+
5/13/16,13:15:42,herring,5.0
|
417 |
+
5/13/16,13:19:37,herring,4.0
|
418 |
+
5/13/18,10:35:48,Herring,1.0
|
419 |
+
5/13/18,5:05:35,Herring,1.0
|
420 |
+
5/13/18,14:27:53,Herring,1.0
|
421 |
+
5/13/18,11:44:28,Herring,1.0
|
422 |
+
5/13/18,8:07:12,Herring,2.0
|
423 |
+
5/13/18,7:46:27,Herring,1.0
|
424 |
+
5/14/16,14:15:5,herring,1.0
|
425 |
+
5/14/16,14:18:25,herring,2.0
|
426 |
+
5/14/16,14:12:42,herring,2.0
|
427 |
+
5/14/16,14:14:43,herring,1.0
|
428 |
+
5/14/16,14:12:54,herring,2.0
|
429 |
+
5/14/16,14:6:44,herring,2.0
|
430 |
+
5/15/16,15:18:55,herring,1.0
|
431 |
+
5/15/16,15:12:21,herring,1.0
|
432 |
+
5/15/16,15:13:36,herring,1.0
|
433 |
+
5/15/16,15:14:42,herring,1.0
|
434 |
+
5/15/16,15:13:50,herring,1.0
|
435 |
+
5/16/16,16:24:1,herring,-1.0
|
436 |
+
5/16/16,16:6:13,herring,2.0
|
437 |
+
5/16/16,16:17:25,herring,1.0
|
438 |
+
5/16/18,3:59:07,Herring,1.0
|
439 |
+
5/16/18,16:30:17,Herring,1.0
|
440 |
+
5/16/18,14:24:23,Herring,2.0
|
441 |
+
5/16/18,18:06:02,Herring,3.0
|
442 |
+
5/16/18,16:37:10,Herring,9.0
|
443 |
+
5/17/15,7:46:41,Herring,3.0
|
444 |
+
5/17/15,5:16:10,Herring,9.0
|
445 |
+
5/17/15,20:44:38,Herring,1.0
|
446 |
+
5/17/18,5:35:42,Herring,2.0
|
447 |
+
5/17/18,17:06:01,Herring,1.0
|
448 |
+
5/18/15,22:33:39,Herring,1.0
|
449 |
+
5/18/15,22:28:59,Herring,1.0
|
450 |
+
5/18/15,22:7:21,Herring,1.0
|
451 |
+
5/18/15,17:21:4,Herring,1.0
|
452 |
+
5/18/15,12:52:15,Herring,1.0
|
453 |
+
5/18/15,5:49:59,Herring,1.0
|
454 |
+
5/18/15,4:44:33,Herring,1.0
|
455 |
+
5/18/18,14:14:21,herring,2.0
|
456 |
+
5/18/18,14:10:08,herring,2.0
|
457 |
+
5/18/18,12:44:18,Herring,1.0
|
458 |
+
5/18/18,11:12:45,herring,1.0
|
459 |
+
5/19/15,21:9:40,Herring,1.0
|
460 |
+
5/19/15,4:6:50,Herring,1.0
|
461 |
+
5/19/15,6:9:16,Herring,3.0
|
462 |
+
5/19/15,9:54:20,Herring,1.0
|
463 |
+
5/19/15,18:45:26,Herring,2.0
|
464 |
+
5/19/15,20:54:6,Herring,1.0
|
465 |
+
5/19/15,23:52:23,Herring,1.0
|
466 |
+
5/2/15,11:32:29,Herring,1.0
|
467 |
+
5/2/18,12:57:01,Herring,1.0
|
468 |
+
5/2/18,5:59:06,Herring,1.0
|
469 |
+
5/2/18,10:09:38,Herring,2.0
|
470 |
+
5/2/18,7:15:39,herring,1.0
|
471 |
+
5/2/18,6:33:18,Herring,2.0
|
472 |
+
5/2/18,6:19:22,herring,1.0
|
473 |
+
5/2/18,6:02:07,Herring,3.0
|
474 |
+
5/2/18,10:47:40,Herring,1.0
|
475 |
+
5/20/15,22:1:43,Herring,1.0
|
476 |
+
5/20/15,23:54:49,Herring,1.0
|
477 |
+
5/20/15,23:54:37,Herring,1.0
|
478 |
+
5/20/15,21:37:55,Herring,1.0
|
479 |
+
5/20/15,0:36:34,Herring,1.0
|
480 |
+
5/20/15,20:25:30,Herring,2.0
|
481 |
+
5/20/15,10:39:50,Herring,1.0
|
482 |
+
5/20/15,2:15:44,Herring,1.0
|
483 |
+
5/20/15,0:2:32,Herring,1.0
|
484 |
+
5/20/15,0:3:47,Herring,1.0
|
485 |
+
5/20/15,0:11:22,Herring,1.0
|
486 |
+
5/20/15,0:43:30,Herring,1.0
|
487 |
+
5/20/15,0:46:35,Herring,1.0
|
488 |
+
5/20/15,1:40:6,Herring,1.0
|
489 |
+
5/20/15,21:14:53,Herring,1.0
|
490 |
+
5/21/15,23:2:5,Herring,1.0
|
491 |
+
5/21/15,21:34:53,Herring,1.0
|
492 |
+
5/21/15,4:7:38,Herring,1.0
|
493 |
+
5/21/15,23:3:41,Herring,1.0
|
494 |
+
5/21/15,23:2:19,Herring,1.0
|
495 |
+
5/21/15,22:20:21,Herring,1.0
|
496 |
+
5/21/15,22:18:16,Herring,1.0
|
497 |
+
5/22/15,23:55:11,Herring,1.0
|
498 |
+
5/22/15,23:6:53,Herring,1.0
|
499 |
+
5/22/15,22:32:5,Herring,1.0
|
500 |
+
5/22/15,2:19:52,Herring,3.0
|
501 |
+
5/22/15,20:23:53,Herring,1.0
|
502 |
+
5/22/15,21:25:42,Herring,1.0
|
503 |
+
5/22/15,21:13:40,Herring,1.0
|
504 |
+
5/22/15,20:50:6,Herring,1.0
|
505 |
+
5/22/15,20:26:15,Herring,1.0
|
506 |
+
5/22/15,22:25:16,Herring,1.0
|
507 |
+
5/23/15,20:37:40,Herring,1.0
|
508 |
+
5/23/15,20:37:19,Herring,1.0
|
509 |
+
5/23/15,21:1:56,Herring,1.0
|
510 |
+
5/23/15,23:38:7,Herring,1.0
|
511 |
+
5/23/15,18:0:22,Herring,1.0
|
512 |
+
5/23/15,20:45:46,Herring,1.0
|
513 |
+
5/23/15,23:34:0,Herring,1.0
|
514 |
+
5/23/15,22:23:47,Herring,1.0
|
515 |
+
5/23/15,0:5:50,Herring,1.0
|
516 |
+
5/23/15,3:23:38,Herring,1.0
|
517 |
+
5/23/15,3:54:20,Herring,1.0
|
518 |
+
5/24/15,5:0:43,Herring,1.0
|
519 |
+
5/24/15,0:2:31,Herring,1.0
|
520 |
+
5/24/15,1:51:7,Herring,1.0
|
521 |
+
5/24/15,20:5:52,Herring,1.0
|
522 |
+
5/24/15,20:21:53,Herring,1.0
|
523 |
+
5/24/15,20:47:44,Herring,1.0
|
524 |
+
5/24/15,20:48:11,Herring,1.0
|
525 |
+
5/24/15,21:51:29,Herring,1.0
|
526 |
+
5/24/18,0:11:38,Herring,1.0
|
527 |
+
5/25/15,22:41:4,Herring,1.0
|
528 |
+
5/25/15,22:13:39,Herring,1.0
|
529 |
+
5/25/15,22:1:35,Herring,1.0
|
530 |
+
5/25/15,1:44:13,Herring,1.0
|
531 |
+
5/25/15,4:5:17,Herring,1.0
|
532 |
+
5/25/15,4:6:36,Herring,1.0
|
533 |
+
5/25/15,4:7:45,Herring,1.0
|
534 |
+
5/25/15,4:15:9,Herring,1.0
|
535 |
+
5/25/15,4:17:53,Herring,2.0
|
536 |
+
5/25/15,5:2:16,Herring,1.0
|
537 |
+
5/25/15,20:5:44,Herring,1.0
|
538 |
+
5/25/15,20:7:10,Herring,1.0
|
539 |
+
5/25/15,20:14:40,Herring,1.0
|
540 |
+
5/25/15,20:36:1,Herring,1.0
|
541 |
+
5/25/15,20:40:42,Herring,1.0
|
542 |
+
5/25/15,21:44:18,Herring,1.0
|
543 |
+
5/25/15,21:44:32,Herring,1.0
|
544 |
+
5/25/15,22:3:41,Herring,1.0
|
545 |
+
5/25/15,1:2:43,Herring,1.0
|
546 |
+
5/25/18,1:52:36,Herring,1.0
|
547 |
+
5/26/15,21:19:50,Herring,1.0
|
548 |
+
5/26/15,0:36:44,Herring,1.0
|
549 |
+
5/26/15,0:39:42,Herring,1.0
|
550 |
+
5/26/15,1:9:47,Herring,1.0
|
551 |
+
5/26/15,1:46:10,Herring,1.0
|
552 |
+
5/26/15,1:52:24,Herring,1.0
|
553 |
+
5/26/15,3:10:8,Herring,1.0
|
554 |
+
5/26/15,4:58:43,Herring,1.0
|
555 |
+
5/26/15,20:54:16,Herring,1.0
|
556 |
+
5/26/15,21:13:29,Herring,1.0
|
557 |
+
5/26/15,22:48:40,Herring,1.0
|
558 |
+
5/27/15,23:0:41,Herring,1.0
|
559 |
+
5/27/15,1:45:23,Herring,1.0
|
560 |
+
5/27/15,3:18:10,Herring,1.0
|
561 |
+
5/27/15,3:42:21,Herring,1.0
|
562 |
+
5/27/15,4:52:1,Herring,1.0
|
563 |
+
5/27/15,10:56:21,Herring,1.0
|
564 |
+
5/27/15,18:50:23,Herring,1.0
|
565 |
+
5/27/15,21:6:41,Herring,1.0
|
566 |
+
5/27/15,21:13:15,Herring,1.0
|
567 |
+
5/27/15,21:35:27,Herring,1.0
|
568 |
+
5/27/15,23:5:27,Herring,1.0
|
569 |
+
5/27/15,22:21:19,Herring,1.0
|
570 |
+
5/27/15,23:21:10,Herring,1.0
|
571 |
+
5/27/15,22:23:13,Herring,1.0
|
572 |
+
5/28/15,0:35:34,Herring,1.0
|
573 |
+
5/28/15,22:43:59,Herring,1.0
|
574 |
+
5/28/15,22:43:37,Herring,1.0
|
575 |
+
5/28/15,21:9:15,Herring,1.0
|
576 |
+
5/28/15,20:42:36,Herring,2.0
|
577 |
+
5/28/15,0:35:44,Herring,1.0
|
578 |
+
5/28/15,4:3:34,Herring,1.0
|
579 |
+
5/28/15,2:51:41,Herring,1.0
|
580 |
+
5/28/15,2:27:3,Herring,1.0
|
581 |
+
5/28/15,2:12:58,Herring,1.0
|
582 |
+
5/28/15,20:29:42,Herring,1.0
|
583 |
+
5/29/15,0:24:59,Herring,1.0
|
584 |
+
5/29/15,0:36:1,Herring,1.0
|
585 |
+
5/29/15,0:37:29,Herring,1.0
|
586 |
+
5/29/15,1:38:32,Herring,1.0
|
587 |
+
5/29/15,2:4:2,Herring,1.0
|
588 |
+
5/29/15,2:7:59,Herring,1.0
|
589 |
+
5/29/15,18:10:49,Herring,1.0
|
590 |
+
5/29/15,19:45:52,Herring,1.0
|
591 |
+
5/29/15,20:30:23,Herring,1.0
|
592 |
+
5/29/15,21:43:17,Herring,1.0
|
593 |
+
5/29/15,0:32:31,Herring,1.0
|
594 |
+
5/3/15,18:54:33,Herring,2.0
|
595 |
+
5/3/15,19:49:37,Herring,1.0
|
596 |
+
5/3/15,1:36:0,Herring,1.0
|
597 |
+
5/3/15,15:48:2,Herring,2.0
|
598 |
+
5/3/15,16:13:51,Herring,2.0
|
599 |
+
5/3/15,16:25:9,Herring,2.0
|
600 |
+
5/3/15,16:26:57,Herring,1.0
|
601 |
+
5/3/15,17:3:56,Herring,1.0
|
602 |
+
5/3/15,18:48:13,Herring,6.0
|
603 |
+
5/3/18,18:47:15,Herring,1.0
|
604 |
+
5/3/18,17:04:58,Herring,4.0
|
605 |
+
5/3/18,16:57:34,Herring,5.0
|
606 |
+
5/3/18,16:42:31,Herring,1.0
|
607 |
+
5/3/18,16:40:27,Herring,2.0
|
608 |
+
5/3/18,16:25:15,Herring,2.0
|
609 |
+
5/3/18,16:21:00,Herring,2.0
|
610 |
+
5/3/18,16:03:30,Herring,1.0
|
611 |
+
5/3/18,17:05:38,Herring,1.0
|
612 |
+
5/3/18,17:27:31,Herring,1.0
|
613 |
+
5/30/15,23:39:49,Herring,2.0
|
614 |
+
5/30/15,2:29:14,Herring,1.0
|
615 |
+
5/30/15,4:22:58,Herring,1.0
|
616 |
+
5/30/15,18:4:29,Herring,1.0
|
617 |
+
5/30/15,21:5:4,Herring,1.0
|
618 |
+
5/30/15,21:32:13,Herring,1.0
|
619 |
+
5/30/15,21:41:57,Herring,1.0
|
620 |
+
5/31/15,21:7:25,Herring,1.0
|
621 |
+
5/31/15,20:30:43,Herring,1.0
|
622 |
+
5/31/15,18:45:47,Herring,1.0
|
623 |
+
5/31/15,3:37:43,Herring,1.0
|
624 |
+
5/31/15,2:19:50,Herring,1.0
|
625 |
+
5/31/15,2:4:40,Herring,1.0
|
626 |
+
5/4/15,13:44:7,Herring,1.0
|
627 |
+
5/4/15,0:9:30,Herring,1.0
|
628 |
+
5/4/15,6:20:57,Herring,1.0
|
629 |
+
5/4/15,9:57:35,Herring,1.0
|
630 |
+
5/4/15,9:57:52,Herring,1.0
|
631 |
+
5/4/15,10:47:41,Herring,2.0
|
632 |
+
5/4/15,16:52:37,Herring,2.0
|
633 |
+
5/4/15,17:21:38,Herring,1.0
|
634 |
+
5/4/15,17:34:14,Herring,1.0
|
635 |
+
5/4/15,18:35:15,Herring,1.0
|
636 |
+
5/4/15,19:29:40,Herring,3.0
|
637 |
+
5/4/15,19:52:3,Herring,1.0
|
638 |
+
5/4/15,20:6:21,Herring,1.0
|
639 |
+
5/4/15,21:3:4,Herring,1.0
|
640 |
+
5/4/15,14:59:38,Herring,1.0
|
641 |
+
5/4/15,11:38:6,Herring,1.0
|
642 |
+
5/4/18,11:21:10,Herring,2.0
|
643 |
+
5/4/18,9:55:38,Herring,2.0
|
644 |
+
5/4/18,9:24:42,Herring,2.0
|
645 |
+
5/4/18,19:26:46,Herring,5.0
|
646 |
+
5/4/18,14:47:10,Herring,1.0
|
647 |
+
5/4/18,14:20:18,Herring,2.0
|
648 |
+
5/4/18,13:59:40,Herring,1.0
|
649 |
+
5/4/18,13:41:57,Herring,1.0
|
650 |
+
5/4/18,18:57:00,Herring,3.0
|
651 |
+
5/4/18,12:47:09,Herring,1.0
|
652 |
+
5/4/18,11:47:20,Herring,1.0
|
653 |
+
5/4/18,11:42:03,Herring,3.0
|
654 |
+
5/4/18,11:32:10,Herring,1.0
|
655 |
+
5/4/18,13:28:43,Herring,1.0
|
656 |
+
5/5/15,4:1:57,Herring,1.0
|
657 |
+
5/5/15,17:53:59,Herring,1.0
|
658 |
+
5/5/15,16:59:19,Herring,1.0
|
659 |
+
5/5/15,15:7:5,Herring,1.0
|
660 |
+
5/5/15,19:57:53,Herring,1.0
|
661 |
+
5/5/15,12:12:5,Herring,1.0
|
662 |
+
5/5/15,11:48:12,Herring,1.0
|
663 |
+
5/5/15,9:50:2,Herring,2.0
|
664 |
+
5/5/15,8:53:12,Herring,1.0
|
665 |
+
5/5/15,4:57:22,Herring,4.0
|
666 |
+
5/5/15,20:1:28,Herring,1.0
|
667 |
+
5/5/15,20:8:50,Herring,3.0
|
668 |
+
5/5/18,13:31:05,Herring,1.0
|
669 |
+
5/5/18,18:47:03,Herring,2.0
|
670 |
+
5/5/18,18:10:49,herring,1.0
|
671 |
+
5/5/18,17:56:24,herring,4.0
|
672 |
+
5/5/18,17:44:05,herring,1.0
|
673 |
+
5/5/18,15:21:27,Herring,1.0
|
674 |
+
5/5/18,14:57:03,Herring,2.0
|
675 |
+
5/5/18,14:34:07,Herring,2.0
|
676 |
+
5/5/18,14:02:54,Herring,1.0
|
677 |
+
5/5/18,13:49:52,Herring,2.0
|
678 |
+
5/5/18,13:49:11,Herring,1.0
|
679 |
+
5/5/18,10:50:59,Herring,2.0
|
680 |
+
5/5/18,11:18:01,Herring,2.0
|
681 |
+
5/5/18,11:21:15,herring,2.0
|
682 |
+
5/5/18,11:45:13,herring,2.0
|
683 |
+
5/5/18,12:04:58,Herring,3.0
|
684 |
+
5/5/18,12:16:03,Herring,1.0
|
685 |
+
5/5/18,12:20:04,Herring,1.0
|
686 |
+
5/5/18,12:38:47,Herring,3.0
|
687 |
+
5/5/18,12:39:09,Herring,2.0
|
688 |
+
5/5/18,13:00:52,Herring,4.0
|
689 |
+
5/5/18,13:15:07,Herring,1.0
|
690 |
+
5/5/18,13:36:08,Herring,2.0
|
691 |
+
5/5/18,13:34:34,Herring,4.0
|
692 |
+
5/5/18,15:32:09,herring,1.0
|
693 |
+
5/5/18,9:32:37,Herring,2.0
|
694 |
+
5/5/18,5:25:38,Herring,1.0
|
695 |
+
5/6/15,0:12:1,Herring,1.0
|
696 |
+
5/6/15,0:18:39,Herring,1.0
|
697 |
+
5/6/15,8:16:28,Herring,3.0
|
698 |
+
5/6/15,9:43:52,Herring,1.0
|
699 |
+
5/6/15,16:31:36,Herring,1.0
|
700 |
+
5/6/15,16:42:0,Herring,1.0
|
701 |
+
5/6/15,16:51:59,Herring,1.0
|
702 |
+
5/6/15,9:55:45,Herring,2.0
|
703 |
+
5/6/15,17:5:41,Herring,1.0
|
704 |
+
5/6/15,17:52:41,Herring,4.0
|
705 |
+
5/6/15,20:0:5,Herring,2.0
|
706 |
+
5/6/15,20:4:48,Herring,1.0
|
707 |
+
5/6/15,20:47:1,Herring,1.0
|
708 |
+
5/6/15,16:54:29,Herring,1.0
|
709 |
+
5/6/18,12:58:11,Herring,5.0
|
710 |
+
5/6/18,12:54:02,Herring,1.0
|
711 |
+
5/6/18,8:43:44,Herring,1.0
|
712 |
+
5/6/18,8:25:36,Herring,2.0
|
713 |
+
5/6/18,6:51:48,Herring,3.0
|
714 |
+
5/6/18,7:23:52,Herring,1.0
|
715 |
+
5/6/18,6:09:19,herring,3.0
|
716 |
+
5/6/18,6:22:32,herring,3.0
|
717 |
+
5/6/18,13:12:31,Herring,7.0
|
718 |
+
5/6/18,6:03:44,Herring,2.0
|
719 |
+
5/6/18,13:27:59,Herring,1.0
|
720 |
+
5/6/18,17:28:19,Herring,4.0
|
721 |
+
5/6/18,14:57:56,Herring,1.0
|
722 |
+
5/6/18,15:32:18,Herring,2.0
|
723 |
+
5/6/18,16:35:26,Herring,2.0
|
724 |
+
5/6/18,16:41:42,Herring,2.0
|
725 |
+
5/6/18,17:00:56,Herring,1.0
|
726 |
+
5/6/18,17:08:27,Herring,1.0
|
727 |
+
5/6/18,17:32:24,Herring,1.0
|
728 |
+
5/6/18,17:33:56,Herring,1.0
|
729 |
+
5/6/18,18:04:13,Herring,2.0
|
730 |
+
5/6/18,18:09:56,Herring,5.0
|
731 |
+
5/6/18,18:21:24,Herring,3.0
|
732 |
+
5/6/18,13:34:48,Herring,2.0
|
733 |
+
5/7/15,6:6:44,Herring,2.0
|
734 |
+
5/7/15,5:52:13,Herring,5.0
|
735 |
+
5/7/15,17:1:3,Herring,1.0
|
736 |
+
5/7/15,16:25:48,Herring,2.0
|
737 |
+
5/7/15,16:27:53,Herring,3.0
|
738 |
+
5/7/15,16:52:55,Herring,1.0
|
739 |
+
5/7/15,6:44:52,Herring,1.0
|
740 |
+
5/7/15,17:2:27,Herring,1.0
|
741 |
+
5/7/15,17:11:49,Herring,3.0
|
742 |
+
5/7/15,17:15:19,Herring,1.0
|
743 |
+
5/7/15,20:4:54,Herring,2.0
|
744 |
+
5/7/15,20:46:10,Herring,1.0
|
745 |
+
5/7/15,21:33:14,Herring,1.0
|
746 |
+
5/7/15,22:17:15,Herring,1.0
|
747 |
+
5/7/15,23:3:36,Herring,1.0
|
748 |
+
5/7/15,0:22:51,Herring,1.0
|
749 |
+
5/7/15,4:16:3,Herring,1.0
|
750 |
+
5/7/15,16:23:47,Herring,3.0
|
751 |
+
5/7/15,10:29:24,Herring,1.0
|
752 |
+
5/7/15,5:41:22,Herring,2.0
|
753 |
+
5/7/16,7:17:36,herring,3.0
|
754 |
+
5/7/16,7:19:26,herring,1.0
|
755 |
+
5/7/16,7:18:41,herring,5.0
|
756 |
+
5/7/16,7:5:38,herring,1.0
|
757 |
+
5/7/16,7:6:36,herring,1.0
|
758 |
+
5/7/16,7:7:40,herring,2.0
|
759 |
+
5/7/16,7:7:45,herring,3.0
|
760 |
+
5/7/16,7:8:58,herring,4.0
|
761 |
+
5/7/16,7:11:21,herring,2.0
|
762 |
+
5/7/16,7:11:40,herring,3.0
|
763 |
+
5/7/16,7:18:37,herring,2.0
|
764 |
+
5/7/16,7:12:50,herring,4.0
|
765 |
+
5/7/16,7:18:36,herring,5.0
|
766 |
+
5/7/16,7:18:17,herring,3.0
|
767 |
+
5/7/16,7:13:7,herring,3.0
|
768 |
+
5/7/16,7:16:9,herring,4.0
|
769 |
+
5/7/16,7:15:36,herring,4.0
|
770 |
+
5/7/18,6:10:46,herring,1.0
|
771 |
+
5/7/18,5:34:47,herring,1.0
|
772 |
+
5/7/18,11:25:08,Herring,3.0
|
773 |
+
5/7/18,6:09:11,herring,5.0
|
774 |
+
5/7/18,5:50:14,herring,3.0
|
775 |
+
5/8/15,17:48:47,Herring,2.0
|
776 |
+
5/8/15,17:51:39,Herring,3.0
|
777 |
+
5/8/15,5:53:28,Herring,1.0
|
778 |
+
5/8/15,17:21:12,Herring,3.0
|
779 |
+
5/8/15,17:16:12,Herring,2.0
|
780 |
+
5/8/15,15:22:40,Herring,2.0
|
781 |
+
5/8/15,13:31:5,Herring,1.0
|
782 |
+
5/8/15,13:4:11,Herring,1.0
|
783 |
+
5/8/15,13:41:59,Herring,1.0
|
784 |
+
5/8/15,10:4:0,Herring,3.0
|
785 |
+
5/8/16,8:17:42,herring,3.0
|
786 |
+
5/8/16,8:18:7,herring,1.0
|
787 |
+
5/8/16,8:18:12,herring,3.0
|
788 |
+
5/8/16,8:17:33,herring,1.0
|
789 |
+
5/8/18,8:41:52,Herring,1.0
|
790 |
+
5/8/18,8:19:45,Herring,1.0
|
791 |
+
5/8/18,7:53:42,Herring,3.0
|
792 |
+
5/9/15,23:24:3,Herring,1.0
|
793 |
+
5/9/15,21:55:30,Herring,1.0
|
794 |
+
5/9/16,9:12:31,herring,1.0
|
795 |
+
5/9/16,9:15:58,herring,2.0
|
796 |
+
5/9/16,9:18:59,herring,1.0
|
797 |
+
5/9/16,9:17:19,herring,2.0
|
798 |
+
5/9/16,9:11:55,herring,4.0
|
799 |
+
5/9/18,19:04:26,Herring,1.0
|
800 |
+
5/9/18,15:10:00,Herring,1.0
|
801 |
+
5/9/18,14:30:36,Herring,1.0
|
802 |
+
5/9/18,14:13:44,Herring,1.0
|
803 |
+
5/9/18,10:45:59,Herring,2.0
|
804 |
+
6-12-17,17:20:00,herring,1.0
|
805 |
+
6-2-17,6:27:00,herring,2.0
|
806 |
+
6-2-17,9:41:00,herring,1.0
|
807 |
+
6-2-17,6:35:00,herring,4.0
|
808 |
+
6-2-17,9:42:00,herring,1.0
|
809 |
+
6-2-17,17:58:00,herring,1.0
|
810 |
+
6-2-17,9:42:00,herring,1.0
|
811 |
+
6/1/15,1:5:22,Herring,1.0
|
812 |
+
6/1/15,3:43:41,Herring,1.0
|
813 |
+
6/1/15,4:55:2,Herring,1.0
|
814 |
+
6/1/15,20:58:41,Herring,1.0
|
815 |
+
6/10/15,18:45:48,Herring,1.0
|
816 |
+
6/10/15,20:42:56,Herring,1.0
|
817 |
+
6/10/15,21:0:2,Herring,1.0
|
818 |
+
6/10/15,22:31:51,Herring,1.0
|
819 |
+
6/10/15,22:26:15,Herring,1.0
|
820 |
+
6/10/15,23:18:14,Herring,1.0
|
821 |
+
6/10/15,17:30:35,Herring,1.0
|
822 |
+
6/10/15,21:1:57,Herring,1.0
|
823 |
+
6/10/15,0:14:51,Herring,1.0
|
824 |
+
6/11/15,2:21:9,Herring,1.0
|
825 |
+
6/11/15,4:10:43,Herring,1.0
|
826 |
+
6/11/15,2:43:29,Herring,1.0
|
827 |
+
6/2/15,0:45:32,Herring,1.0
|
828 |
+
6/2/15,19:43:59,Herring,1.0
|
829 |
+
6/5/15,22:50:37,Herring,1.0
|
830 |
+
6/5/15,4:9:43,Herring,1.0
|
831 |
+
6/5/15,5:39:14,Herring,1.0
|
832 |
+
6/7/15,3:46:22,Herring,1.0
|
833 |
+
6/7/15,20:54:25,Herring,1.0
|
834 |
+
6/7/15,21:3:31,Herring,1.0
|
835 |
+
6/7/15,22:42:28,Herring,1.0
|
836 |
+
6/8/15,13:9:39,Herring,1.0
|
837 |
+
6/8/15,20:26:15,Herring,1.0
|
838 |
+
6/8/15,20:56:45,Herring,2.0
|
839 |
+
6/9/15,22:13:32,Herring,1.0
|
840 |
+
6/9/15,20:40:58,Herring,1.0
|
841 |
+
6/9/15,20:32:37,Herring,1.0
|
842 |
+
6/9/15,2:26:5,Herring,1.0
|
843 |
+
6/9/15,0:16:55,Herring,1.0
|
herring_final.weights
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:44d55c5b96d245acd25011719ed328b0156048e57bdf26c0b0f9d8369933afc7
|
3 |
+
size 202314764
|
inference.py
ADDED
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This code is written at BigVision LLC. It is based on the OpenCV project. It is subject to the license terms in the LICENSE file found in this distribution and at http://opencv.org/license.html
|
2 |
+
|
3 |
+
# Usage example: python3 object_detection_yolo.py --video=run.mp4 --device 'cpu'
|
4 |
+
# python3 object_detection_yolo.py --video=run.mp4 --device 'gpu'
|
5 |
+
# python3 object_detection_yolo.py --image=bird.jpg --device 'cpu'
|
6 |
+
# python3 object_detection_yolo.py --image=bird.jpg --device 'gpu'
|
7 |
+
# python3 test2.py --image=/Users/apowell/Downloads/HerringInTrap.JPG --device 'cpu'
|
8 |
+
# python3 test2.py --video=/Users/apowell/Downloads/sampleFull.avi --device 'cpu'
|
9 |
+
# sampleFull.avi
|
10 |
+
|
11 |
+
import cv2 as cv
|
12 |
+
import argparse
|
13 |
+
import sys
|
14 |
+
import numpy as np
|
15 |
+
import os.path
|
16 |
+
import os
|
17 |
+
import matplotlib
|
18 |
+
import streamlit as st
|
19 |
+
|
20 |
+
matplotlib.use("Agg")
|
21 |
+
from inference_utils import *
|
22 |
+
from PIL import Image, ImageOps
|
23 |
+
import logging
|
24 |
+
|
25 |
+
# Custom
|
26 |
+
from centroidtracker import CentroidTracker
|
27 |
+
|
28 |
+
# Set default static images for testing while working locally
|
29 |
+
DEFAULT_IMAGE = "/Users/apowell/Downloads/HerringInTrap.JPG"
|
30 |
+
DEFAULT_VIDEO = "/Users/apowell/Downloads/sampleFull.avi"
|
31 |
+
YOUTUBE = "https://www.youtube.com/watch?v=CbB7vl_HUbU&ab_channel=AustinPowell"
|
32 |
+
|
33 |
+
|
34 |
+
def main(input_file=None, is_image=False, device="cpu"):
|
35 |
+
"""
|
36 |
+
Run main inference script. Returns annotated frames from inference and counts of fish.
|
37 |
+
|
38 |
+
Args:
|
39 |
+
- input_file: image or video file input from OpenCV
|
40 |
+
- is_image: Binary denoting single image
|
41 |
+
- device: CPU or GPU processing
|
42 |
+
"""
|
43 |
+
## Initialize the parameters
|
44 |
+
# Confidence threshold
|
45 |
+
conf_threshold = 0.5
|
46 |
+
# Non-maximum suppression threshold (maximum bounding box)
|
47 |
+
nms_threshold = 0.05
|
48 |
+
input_width = 416 # Width of network's input image
|
49 |
+
input_height = 416 # Height of network's input image
|
50 |
+
|
51 |
+
# Generic name assignment for output file
|
52 |
+
outputFile = "yolo2_out_py.mp4"
|
53 |
+
# Load class name
|
54 |
+
classes = "Herring"
|
55 |
+
# Give the configuration and weight files for the model and load the network using them.
|
56 |
+
modelConfiguration = "herring.cfg"
|
57 |
+
modelWeights = "herring_final.weights"
|
58 |
+
|
59 |
+
# Centroid tracker to Id specific objects (NOTE: This is temporary and not fully tested)
|
60 |
+
tracker = CentroidTracker(maxDisappeared=80, maxDistance=90)
|
61 |
+
|
62 |
+
# Process inputs
|
63 |
+
if (
|
64 |
+
type(input_file) == cv.VideoCapture
|
65 |
+
): # Video objects passed from something like Streamlit
|
66 |
+
cap = input_file
|
67 |
+
elif type(input_file) == str: # For local uploads
|
68 |
+
cap = cv.VideoCapture(input_file)
|
69 |
+
logging.info("INFO: Loading file locally: {}".format(input_file))
|
70 |
+
else:
|
71 |
+
sys.exit(
|
72 |
+
"Input file is of type {} and not solved for.".format(type(input_file))
|
73 |
+
)
|
74 |
+
|
75 |
+
net = cv.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
|
76 |
+
|
77 |
+
# Get the video writer initialized to save the output video
|
78 |
+
vid_writer = cv.VideoWriter(
|
79 |
+
outputFile,
|
80 |
+
cv.VideoWriter_fourcc("M", "J", "P", "G"),
|
81 |
+
30,
|
82 |
+
(
|
83 |
+
round(cap.get(cv.CAP_PROP_FRAME_WIDTH)),
|
84 |
+
round(cap.get(cv.CAP_PROP_FRAME_HEIGHT)),
|
85 |
+
),
|
86 |
+
)
|
87 |
+
|
88 |
+
total_frames = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
|
89 |
+
video_fps = cap.get(cv.CAP_PROP_FPS)
|
90 |
+
logging.info(
|
91 |
+
"INFO: Starting inference process on video frames. Total: {}, fps: {}".format(
|
92 |
+
total_frames, video_fps
|
93 |
+
)
|
94 |
+
)
|
95 |
+
timestamps = [cap.get(cv.CAP_PROP_POS_MSEC)] # Timestamp for frame
|
96 |
+
calc_timestamps = [0.0] # Relative timestamps to first timestamp
|
97 |
+
saved_frames = [] # Save CV2 frames
|
98 |
+
count_list = []
|
99 |
+
while cap.isOpened():
|
100 |
+
|
101 |
+
# Get frame from the video
|
102 |
+
hasFrame, frame = cap.read()
|
103 |
+
|
104 |
+
# Stop the program if reached end of video
|
105 |
+
if not hasFrame:
|
106 |
+
print("Done processing !!!")
|
107 |
+
print("Output file is stored as ", outputFile)
|
108 |
+
# Release device
|
109 |
+
cap.release()
|
110 |
+
break
|
111 |
+
|
112 |
+
# Create a 4D blob from a frame.
|
113 |
+
blob = cv.dnn.blobFromImage(
|
114 |
+
frame, 1 / 255, (input_width, input_height), [0, 0, 0], 1, crop=False
|
115 |
+
)
|
116 |
+
|
117 |
+
# Sets the input to the network
|
118 |
+
net.setInput(blob)
|
119 |
+
|
120 |
+
# Runs the forward pass to get output of the output layers
|
121 |
+
outs = net.forward(get_outputs_names(net=net))
|
122 |
+
|
123 |
+
# Remove the bounding boxes with low confidence
|
124 |
+
counts = postprocess(
|
125 |
+
frame=frame,
|
126 |
+
outs=outs,
|
127 |
+
tracker=tracker,
|
128 |
+
conf_threshold=conf_threshold,
|
129 |
+
nms_threshold=nms_threshold,
|
130 |
+
classes=classes,
|
131 |
+
)
|
132 |
+
count_list.append(counts)
|
133 |
+
|
134 |
+
# Put efficiency information. The function getPerfProfile returns the overall time for inference(t) and the timings for each of the layers(in layersTimes)
|
135 |
+
t, _ = net.getPerfProfile()
|
136 |
+
label = "Inference time: %.2f ms" % (t * 1000.0 / cv.getTickFrequency())
|
137 |
+
cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))
|
138 |
+
|
139 |
+
# Save frame
|
140 |
+
saved_frames.append(frame.astype(np.uint8)) # )
|
141 |
+
|
142 |
+
# Write the frame with the detection boxes
|
143 |
+
if is_image:
|
144 |
+
cv.imwrite(outputFile, frame.astype(np.uint8))
|
145 |
+
else:
|
146 |
+
vid_writer.write(frame.astype(np.uint8))
|
147 |
+
|
148 |
+
timestamps.append(cap.get(cv.CAP_PROP_POS_MSEC))
|
149 |
+
calc_timestamps.append(calc_timestamps[-1] + 1000 / video_fps)
|
150 |
+
# Calculate time difference for different timestamps
|
151 |
+
time_diffs = [
|
152 |
+
abs(ts - cts) for i, (ts, cts) in enumerate(zip(timestamps, calc_timestamps))
|
153 |
+
]
|
154 |
+
|
155 |
+
with open("your_file.csv", "w") as f:
|
156 |
+
for i in range(len(count_list)):
|
157 |
+
f.write(
|
158 |
+
f"{count_list[i]}, {time_diffs[i+1]}, {timestamps[i]}, {calc_timestamps[i]}\n"
|
159 |
+
)
|
160 |
+
|
161 |
+
return saved_frames, count_list, timestamps
|
162 |
+
|
163 |
+
|
164 |
+
if __name__ == "__main__":
|
165 |
+
|
166 |
+
# Script below to enable running pure inference from command line
|
167 |
+
file_path = "/Users/apowell/Downloads/2_2018-04-27_15-50-53.mp4"
|
168 |
+
saved_frames, counts, timestamps = main(input_file=file_path)
|
inference_utils.py
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Description:
|
3 |
+
|
4 |
+
"""
|
5 |
+
import cv2 as cv
|
6 |
+
import argparse
|
7 |
+
import sys
|
8 |
+
import numpy as np
|
9 |
+
import os.path
|
10 |
+
import matplotlib.pyplot as plt
|
11 |
+
|
12 |
+
|
13 |
+
def get_outputs_names(net):
|
14 |
+
"""Get the names of the output layers.
|
15 |
+
|
16 |
+
Args:
|
17 |
+
net: convolution object detection NN
|
18 |
+
"""
|
19 |
+
# Get the names of all the layers in the network
|
20 |
+
layersNames = net.getLayerNames()
|
21 |
+
# Get the names of the output layers, i.e. the layers with unconnected outputs
|
22 |
+
return [layersNames[i - 1] for i in net.getUnconnectedOutLayers()]
|
23 |
+
|
24 |
+
|
25 |
+
def draw_pred_box(class_id, conf, left, top, right, bottom, frame, classes, count=None):
|
26 |
+
"""Draw the predicted bounding box. Used in postProcess script.
|
27 |
+
|
28 |
+
Args:
|
29 |
+
- class_id: Indices for each of the object classes (e.g. herring)
|
30 |
+
- conf: confidence score for box
|
31 |
+
- left, top, right, bottom: frame indexes for corners of box
|
32 |
+
- frame: frame object
|
33 |
+
- classes: different class names
|
34 |
+
- count: current count of objects detected
|
35 |
+
"""
|
36 |
+
# Draw a bounding box.
|
37 |
+
cv.rectangle(frame, (left, top), (right, bottom), (255, 178, 50), 3)
|
38 |
+
|
39 |
+
label = "%.2f" % conf
|
40 |
+
count_label = "{}".format(count)
|
41 |
+
|
42 |
+
# Get the label for the class name and its confidence
|
43 |
+
if classes:
|
44 |
+
assert class_id < len(classes)
|
45 |
+
label = "%s:%s" % (classes[class_id], label)
|
46 |
+
|
47 |
+
# Display the label at the top of the bounding box
|
48 |
+
label_size, base_line = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
49 |
+
top = max(top, label_size[1])
|
50 |
+
cv.rectangle(
|
51 |
+
frame,
|
52 |
+
(left, top - round(1.5 * label_size[1])),
|
53 |
+
(left + round(1.5 * label_size[0]), top + base_line),
|
54 |
+
(255, 255, 255),
|
55 |
+
cv.FILLED,
|
56 |
+
)
|
57 |
+
cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 0), 1)
|
58 |
+
# Draw count in box
|
59 |
+
cv.putText(
|
60 |
+
img=frame,
|
61 |
+
text=count_label,
|
62 |
+
org=(right + 20, top + 50),
|
63 |
+
fontFace=cv.FONT_HERSHEY_SIMPLEX,
|
64 |
+
fontScale=1.75,
|
65 |
+
color=(255, 255, 255),
|
66 |
+
thickness=1,
|
67 |
+
)
|
68 |
+
|
69 |
+
|
70 |
+
def postprocess(frame, outs, conf_threshold, tracker, nms_threshold, classes):
|
71 |
+
"""Remove the bounding boxes with low confidence using non-maxima suppression.
|
72 |
+
|
73 |
+
Args:
|
74 |
+
- frame (frame object from cv2.VideoCapture): Image from video
|
75 |
+
- outs (nn layers): Output of the output layers from forward pass
|
76 |
+
|
77 |
+
"""
|
78 |
+
frame_height = frame.shape[0]
|
79 |
+
frame_width = frame.shape[1]
|
80 |
+
|
81 |
+
# Scan through all the bounding boxes output from the network and keep only the
|
82 |
+
# ones with high confidence scores. Assign the box's class label as the class with the highest score.
|
83 |
+
class_ids = []
|
84 |
+
confidences = []
|
85 |
+
boxes = []
|
86 |
+
counts = 0
|
87 |
+
for out in outs: # Scan through bounding boxes
|
88 |
+
for detection in out: # Scan through
|
89 |
+
scores = detection[5:]
|
90 |
+
|
91 |
+
class_id = np.argmax(scores) # class with highest score
|
92 |
+
confidence = scores[class_id] # confidence score for class
|
93 |
+
if confidence > conf_threshold:
|
94 |
+
print(detection)
|
95 |
+
center_x = int(detection[0] * frame_width)
|
96 |
+
center_y = int(detection[1] * frame_height)
|
97 |
+
width = int(detection[2] * frame_width)
|
98 |
+
height = int(detection[3] * frame_height)
|
99 |
+
left = int(center_x - width / 2)
|
100 |
+
top = int(center_y - height / 2)
|
101 |
+
class_ids.append(class_id)
|
102 |
+
confidences.append(float(confidence))
|
103 |
+
boxes.append([left, top, width, height])
|
104 |
+
counts += 1
|
105 |
+
|
106 |
+
# Perform non maximum suppression to eliminate redundant overlapping boxes with
|
107 |
+
# lower confidences.
|
108 |
+
indices = cv.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
|
109 |
+
print("BOXES", boxes, indices, class_ids)
|
110 |
+
|
111 |
+
max_counts = 0
|
112 |
+
for i in indices:
|
113 |
+
left, top, width, height = boxes[i][0], boxes[i][1], boxes[i][2], boxes[i][3]
|
114 |
+
# temporary logic for counting all fish from detected boxes
|
115 |
+
if counts > max_counts:
|
116 |
+
max_counts = counts
|
117 |
+
|
118 |
+
draw_pred_box(
|
119 |
+
class_ids[i],
|
120 |
+
confidences[i],
|
121 |
+
left,
|
122 |
+
top,
|
123 |
+
left + width,
|
124 |
+
top + height,
|
125 |
+
frame=frame,
|
126 |
+
classes=classes,
|
127 |
+
count=counts,
|
128 |
+
)
|
129 |
+
|
130 |
+
print("counts", max_counts)
|
131 |
+
return max_counts
|
notebooks/masking.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|
requirements.txt
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
altair==4.2.0
|
2 |
+
attrs==22.1.0
|
3 |
+
av==10.0.0
|
4 |
+
bashplotlib==0.6.5
|
5 |
+
blinker==1.5
|
6 |
+
cachetools==5.2.0
|
7 |
+
certifi==2022.9.24
|
8 |
+
charset-normalizer==2.1.1
|
9 |
+
click==8.1.3
|
10 |
+
commonmark==0.9.1
|
11 |
+
contourpy==1.0.6
|
12 |
+
cycler==0.11.0
|
13 |
+
decorator==5.1.1
|
14 |
+
entrypoints==0.4
|
15 |
+
fonttools==4.38.0
|
16 |
+
gitdb==4.0.9
|
17 |
+
GitPython==3.1.29
|
18 |
+
google-api-core==2.10.2
|
19 |
+
google-api-python-client==2.65.0
|
20 |
+
google-auth==2.14.0
|
21 |
+
google-auth-httplib2==0.1.0
|
22 |
+
googleapis-common-protos==1.56.4
|
23 |
+
httplib2==0.21.0
|
24 |
+
idna==3.4
|
25 |
+
importlib-metadata==5.0.0
|
26 |
+
imutils==0.5.4
|
27 |
+
Jinja2==3.1.2
|
28 |
+
jsonschema==4.16.0
|
29 |
+
kiwisolver==1.4.4
|
30 |
+
MarkupSafe==2.1.1
|
31 |
+
matplotlib==3.6.1
|
32 |
+
numpy==1.23.4
|
33 |
+
oauth2client==4.1.3
|
34 |
+
opencv-python-headless==4.6.0.66
|
35 |
+
packaging==21.3
|
36 |
+
pandas==1.5.1
|
37 |
+
Pillow==9.3.0
|
38 |
+
progressbar2==4.2.0
|
39 |
+
protobuf==3.20.3
|
40 |
+
pyarrow==10.0.0
|
41 |
+
pyasn1==0.4.8
|
42 |
+
pyasn1-modules==0.2.8
|
43 |
+
pydeck==0.8.0b4
|
44 |
+
Pygments==2.13.0
|
45 |
+
Pympler==1.0.1
|
46 |
+
pyparsing==3.0.9
|
47 |
+
pyrsistent==0.19.1
|
48 |
+
pyser==0.1.5
|
49 |
+
python-dateutil==2.8.2
|
50 |
+
python-utils==3.4.5
|
51 |
+
pytz==2022.6
|
52 |
+
pytz-deprecation-shim==0.1.0.post0
|
53 |
+
requests==2.28.1
|
54 |
+
rich==12.6.0
|
55 |
+
rsa==4.9
|
56 |
+
scipy==1.9.3
|
57 |
+
semver==2.13.0
|
58 |
+
simple-youtube-api==0.2.8
|
59 |
+
six==1.16.0
|
60 |
+
smmap==5.0.0
|
61 |
+
streamlit==1.14.0
|
62 |
+
toml==0.10.2
|
63 |
+
toolz==0.12.0
|
64 |
+
tornado==6.2
|
65 |
+
tqdm==4.64.1
|
66 |
+
typing_extensions==4.4.0
|
67 |
+
tzdata==2022.6
|
68 |
+
tzlocal==4.2
|
69 |
+
uritemplate==4.1.1
|
70 |
+
urllib3==1.26.12
|
71 |
+
validators==0.20.0
|
72 |
+
watchdog==2.1.9
|
73 |
+
zipp==3.10.0
|
setup.sh
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
mkdir -p ~/.streamlit/
|
2 |
+
|
3 |
+
echo "\
|
4 |
+
[server]\n\
|
5 |
+
headless = true\n\
|
6 |
+
port = $PORT\n\
|
7 |
+
enableCORS = false\n\
|
8 |
+
\n\
|
9 |
+
" > ~/.streamlit/config.toml
|
static/test_images/1_2016-04-09_15-54-17_large.jpg
ADDED
static/test_images/1_2016-04-13_13-57-11_large.jpg
ADDED
static/test_images/1_2016-04-13_14-31-23_large.jpg
ADDED
static/test_images/1_2016-04-13_18-03-24_large.jpg
ADDED
static/test_images/1_2016-04-13_18-57-31_large.jpg
ADDED
static/test_images/1_2016-04-13_19-00-23_large.jpg
ADDED
static/test_images/1_2016-04-13_19-22-43_large.jpg
ADDED
static/test_images/1_2016-04-14_12-01-34_large.jpg
ADDED
static/test_images/herring_test_image.jpg
ADDED
tests/__pycache__/test_streamlit.cpython-38-pytest-7.2.0.pyc
ADDED
Binary file (1.48 kB). View file
|
|
tests/__pycache__/test_streamlit.cpython-39-pytest-7.1.1.pyc
ADDED
Binary file (1.48 kB). View file
|
|
tests/__pycache__/test_streamlit.cpython-39-pytest-7.2.0.pyc
ADDED
Binary file (1.52 kB). View file
|
|
tests/test_streamlit.py
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Tests ability to load video in streamlit under the following conditions:
|
3 |
+
- In-memory
|
4 |
+
- From OpenCV object
|
5 |
+
"""
|
6 |
+
import numpy as np
|
7 |
+
import cv2
|
8 |
+
import av
|
9 |
+
import io
|
10 |
+
import streamlit as st
|
11 |
+
|
12 |
+
import pandas as pd
|
13 |
+
import numpy as np
|
14 |
+
from tqdm import tqdm
|
15 |
+
|
16 |
+
|
17 |
+
def make_sample_image(i):
|
18 |
+
"""Build synthetic "raw BGR" image for testing"""
|
19 |
+
p = width // 60
|
20 |
+
img = np.full((height, width, 3), 60, np.uint8)
|
21 |
+
cv2.putText(
|
22 |
+
img,
|
23 |
+
str(i + 1),
|
24 |
+
(width // 2 - p * 10 * len(str(i + 1)), height // 2 + p * 10),
|
25 |
+
cv2.FONT_HERSHEY_DUPLEX,
|
26 |
+
p,
|
27 |
+
(255, 30, 30),
|
28 |
+
p * 2,
|
29 |
+
) # Blue number
|
30 |
+
return img
|
31 |
+
|
32 |
+
|
33 |
+
n_frames = 100 # Select number of frames (for testing).
|
34 |
+
|
35 |
+
width, height, fps = 192, 108, 10 # Select video resolution and framerate.
|
36 |
+
|
37 |
+
output_memory_file = io.BytesIO() # Create BytesIO "in memory file".
|
38 |
+
|
39 |
+
output = av.open(
|
40 |
+
output_memory_file, "w", format="mp4"
|
41 |
+
) # Open "in memory file" as MP4 video output
|
42 |
+
stream = output.add_stream(
|
43 |
+
"h264", str(fps)
|
44 |
+
) # Add H.264 video stream to the MP4 container, with framerate = fps.
|
45 |
+
stream.width = width # Set frame width
|
46 |
+
stream.height = height # Set frame height
|
47 |
+
stream.pix_fmt = "yuv420p" # NOTE: yuv444p doesn't work on mac. Select yuv444p pixel format (better quality than default yuv420p).
|
48 |
+
stream.options = {
|
49 |
+
"crf": "17"
|
50 |
+
} # Select low crf for high quality (the price is larger file size).
|
51 |
+
|
52 |
+
# Iterate the created images, encode and write to MP4 memory file.
|
53 |
+
for i in tqdm(range(n_frames)):
|
54 |
+
img = make_sample_image(
|
55 |
+
i
|
56 |
+
) # Create OpenCV image for testing (resolution 192x108, pixel format BGR).
|
57 |
+
frame = av.VideoFrame.from_ndarray(
|
58 |
+
img, format="bgr24"
|
59 |
+
) # # Convert image from NumPy Array to frame.
|
60 |
+
packet = stream.encode(frame) # Encode video frame
|
61 |
+
output.mux(packet) # "Mux" the encoded frame (add the encoded frame to MP4 file).
|
62 |
+
|
63 |
+
|
64 |
+
print("OUTPUT TYPE", type(output))
|
65 |
+
# Flush the encoder
|
66 |
+
packet = stream.encode(None)
|
67 |
+
output.mux(packet)
|
68 |
+
output.close()
|
69 |
+
|
70 |
+
output_memory_file.seek(0)
|
71 |
+
# video_bytes = output_memory_file.read() # Convert BytesIO to bytes array
|
72 |
+
|
73 |
+
st.video(output_memory_file)
|
yolo2_out_py.mp4
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:81057a2a75dac98475042450fd8b061aba996a0c4bedfa048bc7b40a995fb7bc
|
3 |
+
size 6626277
|
your_file.csv
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
0, 33.333333333333336, 0.0, 0.0
|
2 |
+
0, 33.333333333333336, 0.0, 33.333333333333336
|
3 |
+
0, 33.33333333333333, 33.333333333333336, 66.66666666666667
|
4 |
+
0, 33.33333333333334, 66.66666666666667, 100.0
|
5 |
+
0, 33.33333333333334, 100.0, 133.33333333333334
|
6 |
+
0, 33.33333333333337, 133.33333333333334, 166.66666666666669
|
7 |
+
0, 33.33333333333337, 166.66666666666666, 200.00000000000003
|
8 |
+
0, 33.33333333333334, 200.0, 233.33333333333337
|
9 |
+
0, 33.333333333333314, 233.33333333333334, 266.6666666666667
|
10 |
+
0, 33.333333333333314, 266.6666666666667, 300.0
|
11 |
+
0, 33.333333333333314, 300.0, 333.3333333333333
|
12 |
+
0, 33.333333333333314, 333.3333333333333, 366.66666666666663
|
13 |
+
0, 33.33333333333326, 366.66666666666663, 399.99999999999994
|
14 |
+
0, 33.3333333333332, 400.0, 433.33333333333326
|
15 |
+
0, 33.3333333333332, 433.33333333333337, 466.6666666666666
|
16 |
+
0, 33.33333333333326, 466.6666666666667, 499.9999999999999
|
17 |
+
0, 33.33333333333326, 500.0, 533.3333333333333
|
18 |
+
0, 33.33333333333337, 533.3333333333334, 566.6666666666666
|
19 |
+
0, 33.33333333333337, 566.6666666666666, 600.0
|
20 |
+
0, 33.333333333333485, 600.0, 633.3333333333334
|
21 |
+
1, 33.333333333333485, 633.3333333333333, 666.6666666666667
|
22 |
+
1, 33.333333333333485, 666.6666666666666, 700.0000000000001
|
23 |
+
1, 33.3333333333336, 700.0, 733.3333333333335
|
24 |
+
1, 33.3333333333336, 733.3333333333333, 766.6666666666669
|
25 |
+
2, 33.3333333333336, 766.6666666666666, 800.0000000000002
|
26 |
+
1, 33.3333333333336, 800.0, 833.3333333333336
|
27 |
+
2, 33.3333333333336, 833.3333333333334, 866.666666666667
|
28 |
+
2, 33.33333333333371, 866.6666666666667, 900.0000000000003
|
29 |
+
1, 33.33333333333371, 900.0, 933.3333333333337
|
30 |
+
2, 33.333333333333826, 933.3333333333334, 966.6666666666671
|
31 |
+
2, 33.33333333333371, 966.6666666666666, 1000.0000000000005
|
32 |
+
2, 33.33333333333371, 1000.0, 1033.3333333333337
|
33 |
+
1, 33.333333333333485, 1033.3333333333333, 1066.666666666667
|
34 |
+
1, 33.333333333333485, 1066.6666666666667, 1100.0000000000002
|
35 |
+
1, 33.333333333333485, 1100.0, 1133.3333333333335
|
36 |
+
1, 33.33333333333326, 1133.3333333333333, 1166.6666666666667
|
37 |
+
1, 33.33333333333326, 1166.6666666666667, 1200.0
|
38 |
+
1, 33.33333333333303, 1200.0, 1233.3333333333333
|
39 |
+
1, 33.33333333333326, 1233.3333333333335, 1266.6666666666665
|
40 |
+
0, 33.33333333333303, 1266.6666666666665, 1299.9999999999998
|
41 |
+
1, 33.33333333333303, 1300.0, 1333.333333333333
|
42 |
+
0, 33.3333333333328, 1333.3333333333333, 1366.6666666666663
|
43 |
+
1, 33.3333333333328, 1366.6666666666667, 1399.9999999999995
|
44 |
+
1, 33.3333333333328, 1400.0, 1433.3333333333328
|
45 |
+
2, 33.3333333333328, 1433.3333333333333, 1466.666666666666
|
46 |
+
1, 33.333333333332575, 1466.6666666666665, 1499.9999999999993
|
47 |
+
1, 33.333333333332575, 1500.0, 1533.3333333333326
|
48 |
+
0, 33.33333333333235, 1533.3333333333333, 1566.6666666666658
|
49 |
+
0, 33.33333333333235, 1566.6666666666667, 1599.999999999999
|
50 |
+
0, 33.33333333333235, 1600.0, 1633.3333333333323
|
51 |
+
0, 33.33333333333212, 1633.3333333333333, 1666.6666666666656
|
52 |
+
0, 33.33333333333212, 1666.6666666666667, 1699.9999999999989
|
53 |
+
0, 33.33333333333189, 1700.0, 1733.3333333333321
|
54 |
+
0, 33.33333333333212, 1733.3333333333335, 1766.6666666666654
|
55 |
+
0, 33.33333333333189, 1766.6666666666665, 1799.9999999999986
|
56 |
+
0, 33.33333333333189, 1800.0, 1833.333333333332
|
57 |
+
0, 33.333333333331666, 1833.3333333333333, 1866.6666666666652
|
58 |
+
0, 33.333333333331666, 1866.6666666666667, 1899.9999999999984
|
59 |
+
0, 33.333333333331666, 1900.0, 1933.3333333333317
|
60 |
+
0, 33.333333333331666, 1933.3333333333333, 1966.666666666665
|
61 |
+
0, 33.33333333333144, 1966.6666666666665, 1999.9999999999982
|
62 |
+
0, 33.33333333333144, 2000.0, 2033.3333333333314
|
63 |
+
0, 33.333333333331666, 2033.3333333333333, 2066.6666666666647
|
64 |
+
0, 33.333333333331666, 2066.6666666666665, 2099.999999999998
|
65 |
+
0, 33.333333333331666, 2100.0, 2133.3333333333317
|
66 |
+
0, 33.33333333333212, 2133.3333333333335, 2166.666666666665
|
67 |
+
0, 33.33333333333212, 2166.6666666666665, 2199.9999999999986
|
68 |
+
0, 33.33333333333212, 2200.0, 2233.333333333332
|
69 |
+
0, 33.333333333332575, 2233.3333333333335, 2266.6666666666656
|
70 |
+
0, 33.333333333332575, 2266.6666666666665, 2299.999999999999
|
71 |
+
0, 33.333333333332575, 2300.0, 2333.3333333333326
|
72 |
+
0, 33.33333333333303, 2333.3333333333335, 2366.666666666666
|
73 |
+
0, 33.33333333333303, 2366.6666666666665, 2399.9999999999995
|
74 |
+
0, 33.333333333333485, 2400.0, 2433.333333333333
|
75 |
+
0, 33.33333333333303, 2433.333333333333, 2466.6666666666665
|
76 |
+
0, 33.333333333333485, 2466.666666666667, 2500.0
|
77 |
+
0, 33.33333333333394, 2500.0, 2533.3333333333335
|
78 |
+
0, 33.33333333333394, 2533.333333333333, 2566.666666666667
|
79 |
+
0, 33.33333333333394, 2566.6666666666665, 2600.0000000000005
|
80 |
+
0, 33.33333333333394, 2600.0, 2633.333333333334
|
81 |
+
0, 33.333333333334394, 2633.3333333333335, 2666.6666666666674
|
82 |
+
0, 33.333333333334394, 2666.6666666666665, 2700.000000000001
|
83 |
+
0, 33.333333333334394, 2700.0, 2733.3333333333344
|
84 |
+
0, 33.33333333333485, 2733.3333333333335, 2766.666666666668
|
85 |
+
0, 33.33333333333485, 2766.6666666666665, 2800.0000000000014
|
86 |
+
0, 33.33333333333485, 2800.0, 2833.333333333335
|
87 |
+
0, 33.333333333335304, 2833.3333333333335, 2866.6666666666683
|
88 |
+
0, 33.333333333335304, 2866.6666666666665, 2900.000000000002
|
89 |
+
0, 33.33333333333576, 2900.0, 2933.3333333333353
|
90 |
+
0, 33.333333333335304, 2933.333333333333, 2966.666666666669
|
91 |
+
0, 33.33333333333576, 2966.666666666667, 3000.0000000000023
|
92 |
+
0, 33.33333333333621, 3000.0, 3033.3333333333358
|
93 |
+
0, 33.33333333333621, 3033.333333333333, 3066.6666666666692
|
94 |
+
0, 33.33333333333621, 3066.6666666666665, 3100.0000000000027
|
95 |
+
0, 33.33333333333621, 3100.0, 3133.333333333336
|
96 |
+
0, 33.33333333333667, 3133.3333333333335, 3166.6666666666697
|
97 |
+
0, 33.33333333333667, 3166.6666666666665, 3200.000000000003
|
98 |
+
0, 33.33333333333667, 3200.0, 3233.3333333333367
|
99 |
+
0, 33.33333333333712, 3233.3333333333335, 3266.66666666667
|
100 |
+
0, 33.33333333333712, 3266.6666666666665, 3300.0000000000036
|
101 |
+
0, 33.33333333333712, 3300.0, 3333.333333333337
|
102 |
+
0, 33.33333333333758, 3333.3333333333335, 3366.6666666666706
|
103 |
+
0, 33.33333333333758, 3366.6666666666665, 3400.000000000004
|
104 |
+
0, 33.33333333333803, 3400.0, 3433.3333333333376
|
105 |
+
0, 33.33333333333758, 3433.333333333333, 3466.666666666671
|
106 |
+
0, 33.33333333333803, 3466.666666666667, 3500.0000000000045
|
107 |
+
0, 33.33333333333849, 3500.0, 3533.333333333338
|
108 |
+
0, 33.33333333333849, 3533.333333333333, 3566.6666666666715
|
109 |
+
0, 33.33333333333849, 3566.6666666666665, 3600.000000000005
|
110 |
+
0, 33.33333333333849, 3600.0, 3633.3333333333385
|
111 |
+
0, 33.33333333333894, 3633.3333333333335, 3666.666666666672
|
112 |
+
0, 33.3333333333394, 3666.6666666666665, 3700.0000000000055
|
113 |
+
0, 33.33333333333894, 3699.9999999999995, 3733.333333333339
|
114 |
+
0, 33.3333333333394, 3733.3333333333335, 3766.6666666666724
|
115 |
+
0, 33.3333333333394, 3766.6666666666665, 3800.000000000006
|
116 |
+
0, 33.3333333333394, 3800.0, 3833.3333333333394
|
117 |
+
0, 33.33333333333985, 3833.3333333333335, 3866.666666666673
|
118 |
+
0, 33.33333333333985, 3866.6666666666665, 3900.0000000000064
|
119 |
+
0, 33.333333333340306, 3900.0, 3933.33333333334
|
120 |
+
0, 33.33333333333985, 3933.333333333333, 3966.6666666666733
|
121 |
+
0, 33.333333333340306, 3966.666666666667, 4000.000000000007
|
122 |
+
0, 33.33333333334076, 4000.0, 4033.3333333333403
|
123 |
+
0, 33.33333333334076, 4033.333333333333, 4066.666666666674
|
124 |
+
0, 33.333333333340306, 4066.6666666666665, 4100.000000000007
|
125 |
+
0, 33.333333333340306, 4100.0, 4133.33333333334
|
126 |
+
0, 33.3333333333394, 4133.333333333333, 4166.666666666673
|
127 |
+
0, 33.3333333333394, 4166.666666666667, 4200.000000000006
|
128 |
+
0, 33.3333333333394, 4200.0, 4233.333333333339
|
129 |
+
0, 33.33333333333849, 4233.333333333333, 4266.666666666672
|
130 |
+
0, 33.33333333333849, 4266.666666666667, 4300.0000000000055
|