charlesollion commited on
Commit
54c4dfe
1 Parent(s): 4bc04ea

adding icons and small tracking update

Browse files
app.py CHANGED
@@ -2,7 +2,7 @@ from webbrowser import get
2
  import gradio as gr
3
  import os
4
  import os.path as op
5
- from tools.files import download_from_url, create_unique_folder
6
 
7
  import json
8
  from typing import Dict, List, Tuple
@@ -62,8 +62,11 @@ id_categories = {
62
 
63
 
64
  config_track = DotDict({
65
- "confidence_threshold": 0.5,
66
- "detection_threshold": 0.3,
 
 
 
67
  "downsampling_factor": 4,
68
  "noise_covariances_path": "data/tracking_parameters",
69
  "output_shape": (960,544),
@@ -86,7 +89,7 @@ os.environ["VERBOSE"] = "False"
86
  URL_MODEL = "https://github.com/surfriderfoundationeurope/IA_Pau/releases/download/v0.1/yolov5.pt"
87
  FILE_MODEL = "yolov5.pt"
88
  model_path = download_from_url(URL_MODEL, FILE_MODEL, logger, "./models")
89
- model_yolo = load_model(model_path, config_track.device)
90
 
91
 
92
  logger.info('---Centernet model...')
@@ -113,6 +116,8 @@ video3_path = op.join("./data", FILE_DEMO3)
113
  JSON_FILE_PATH = "data/"
114
 
115
 
 
 
116
  def track(args):
117
  device = torch.device("cpu")
118
 
@@ -206,14 +211,15 @@ def run_model(video_path, model_type, seconds, skip, tau, kappa, gps_file):
206
  progress_bar=True,
207
  preload=False,
208
  max_frame=config_track.max_length)
209
-
210
  # Get GPS Data
211
  gps_data = get_filled_gps(gps_file,video_path)
212
 
213
  # Generate new video
214
  generate_video_with_annotations(reader, output_json, output_path,
215
  config_track.skip_frames, config_track.max_length,
216
- config_track.downscale_output, logger,gps_data)
 
217
  output_label = count_objects(output_json, id_categories)
218
 
219
 
@@ -225,7 +231,7 @@ def run_model(video_path, model_type, seconds, skip, tau, kappa, gps_file):
225
  with open(output_json_path) as json_file:
226
  predictions = json.load(json_file)
227
  trash_df = get_df_prediction(predictions, reader.fps)
228
- if len(trash_df) != 0 :
229
  # Get Trash prediction alongside GPS data
230
  trash_gps_df = get_trash_gps_df(trash_df,gps_data)
231
  trash_gps_geo_df = get_trash_gps_geo_df(trash_gps_df)
@@ -235,10 +241,10 @@ def run_model(video_path, model_type, seconds, skip, tau, kappa, gps_file):
235
  map_path = get_plastic_map(center_lat,center_long,trash_gps_geo_df,out_folder)
236
  html_content = codecs.open(map_path, 'r')
237
  map_html = html_content.read()
238
- map_frame = f"""<iframe style="width: 100%; height: 480px" name="result" allow="midi; geolocation; microphone; camera;
239
- display-capture; encrypted-media;" sandbox="allow-modals allow-forms
240
- allow-scripts allow-same-origin allow-popups
241
- allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
242
  allowpaymentrequest="" frameborder="0" srcdoc='{map_html}'></iframe>"""
243
 
244
  logger.info('---Surfnet End processing...')
@@ -275,7 +281,7 @@ def get_plastic_map(center_lat,center_long,trash_gps_gdf,out_folder)->str:
275
  Returns:
276
  map_html_path (str): full path to html map
277
  """
278
-
279
  m = folium.Map([center_lat, center_long], zoom_start=16)
280
  locs = zip(trash_gps_gdf.geometry.y,trash_gps_gdf.geometry.x)
281
  labels = list(trash_gps_gdf['label'])
 
2
  import gradio as gr
3
  import os
4
  import os.path as op
5
+ from tools.files import download_from_url, create_unique_folder, load_trash_icons
6
 
7
  import json
8
  from typing import Dict, List, Tuple
 
62
 
63
 
64
  config_track = DotDict({
65
+ "yolo_conf_thrld": 0.35,
66
+ "yolo_iou_thrld": 0.5,
67
+
68
+ "confidence_threshold": 0.004, # for the tracking part
69
+ "detection_threshold": 0.3, # for centernet
70
  "downsampling_factor": 4,
71
  "noise_covariances_path": "data/tracking_parameters",
72
  "output_shape": (960,544),
 
89
  URL_MODEL = "https://github.com/surfriderfoundationeurope/IA_Pau/releases/download/v0.1/yolov5.pt"
90
  FILE_MODEL = "yolov5.pt"
91
  model_path = download_from_url(URL_MODEL, FILE_MODEL, logger, "./models")
92
+ model_yolo = load_model(model_path, config_track.device, config_track.yolo_conf_thrld, config_track.yolo_iou_thrld)
93
 
94
 
95
  logger.info('---Centernet model...')
 
116
  JSON_FILE_PATH = "data/"
117
 
118
 
119
+ labels2icons = load_trash_icons("./data/icons/")
120
+
121
  def track(args):
122
  device = torch.device("cpu")
123
 
 
211
  progress_bar=True,
212
  preload=False,
213
  max_frame=config_track.max_length)
214
+
215
  # Get GPS Data
216
  gps_data = get_filled_gps(gps_file,video_path)
217
 
218
  # Generate new video
219
  generate_video_with_annotations(reader, output_json, output_path,
220
  config_track.skip_frames, config_track.max_length,
221
+ config_track.downscale_output, logger, gps_data=gps_data,
222
+ labels2icons=labels2icons)
223
  output_label = count_objects(output_json, id_categories)
224
 
225
 
 
231
  with open(output_json_path) as json_file:
232
  predictions = json.load(json_file)
233
  trash_df = get_df_prediction(predictions, reader.fps)
234
+ if len(trash_df) != 0 :
235
  # Get Trash prediction alongside GPS data
236
  trash_gps_df = get_trash_gps_df(trash_df,gps_data)
237
  trash_gps_geo_df = get_trash_gps_geo_df(trash_gps_df)
 
241
  map_path = get_plastic_map(center_lat,center_long,trash_gps_geo_df,out_folder)
242
  html_content = codecs.open(map_path, 'r')
243
  map_html = html_content.read()
244
+ map_frame = f"""<iframe style="width: 100%; height: 480px" name="result" allow="midi; geolocation; microphone; camera;
245
+ display-capture; encrypted-media;" sandbox="allow-modals allow-forms
246
+ allow-scripts allow-same-origin allow-popups
247
+ allow-top-navigation-by-user-activation allow-downloads" allowfullscreen=""
248
  allowpaymentrequest="" frameborder="0" srcdoc='{map_html}'></iframe>"""
249
 
250
  logger.info('---Surfnet End processing...')
 
281
  Returns:
282
  map_html_path (str): full path to html map
283
  """
284
+
285
  m = folium.Map([center_lat, center_long], zoom_start=16)
286
  locs = zip(trash_gps_gdf.geometry.y,trash_gps_gdf.geometry.x)
287
  labels = list(trash_gps_gdf['label'])
data/icons/bouteille.png ADDED
data/icons/briquet.png ADDED
data/icons/chaussure.png ADDED
data/icons/contenant.png ADDED
data/icons/dechet.png ADDED
data/icons/emballage.png ADDED
data/icons/fragment.png ADDED
data/icons/hamecon.png ADDED
data/icons/mousse.png ADDED
data/icons/pneu.png ADDED
tools/files.py CHANGED
@@ -1,11 +1,13 @@
1
  import os
2
  import os.path as op
 
3
  from urllib.request import urlretrieve
4
  import datetime
 
5
 
6
 
7
  def create_unique_folder(base_folder, filename):
8
- """Creates a unique folder based on the filename and timestamp
9
  """
10
  folder_name = op.splitext(op.basename(filename))[0] + "_out_"
11
  folder_name += datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
@@ -14,9 +16,9 @@ def create_unique_folder(base_folder, filename):
14
  os.mkdir(output_dir)
15
  return output_dir
16
 
 
17
  def download_from_url(url, filename, logger, folder="./data/"):
18
- """
19
- Download a file and place it in the corresponding folder if it does
20
  not already exists
21
  """
22
  filepath = op.realpath(op.join(folder, filename))
@@ -26,3 +28,27 @@ def download_from_url(url, filename, logger, folder="./data/"):
26
  else:
27
  logger.info('---File already downloaded.')
28
  return filepath
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import os.path as op
3
+ from pathlib import Path
4
  from urllib.request import urlretrieve
5
  import datetime
6
+ import cv2
7
 
8
 
9
  def create_unique_folder(base_folder, filename):
10
+ """ Creates a unique folder based on the filename and timestamp
11
  """
12
  folder_name = op.splitext(op.basename(filename))[0] + "_out_"
13
  folder_name += datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
 
16
  os.mkdir(output_dir)
17
  return output_dir
18
 
19
+
20
  def download_from_url(url, filename, logger, folder="./data/"):
21
+ """ Download a file and place it in the corresponding folder if it does
 
22
  not already exists
23
  """
24
  filepath = op.realpath(op.join(folder, filename))
 
28
  else:
29
  logger.info('---File already downloaded.')
30
  return filepath
31
+
32
+
33
+ def load_trash_icons(folder_path):
34
+ """ loads all icons using cv2 format and returns a dict class -> opened icon
35
+ """
36
+ folder_path = Path(folder_path)
37
+ id_path = {
38
+ 'Fragment': folder_path / "fragment.png",#'Fragment', #'Sheet / tarp / plastic bag / fragment',
39
+ 'Insulating': folder_path / "mousse.png",#'Insulating', #'Insulating material',
40
+ 'Bottle': folder_path / "bouteille.png",#'Bottle', #'Bottle-shaped',
41
+ 'Can': folder_path / "briquet.png",#'Can', #'Can-shaped',
42
+ 'Drum': folder_path / "contenant.png",#'Drum',
43
+ 'Packaging': folder_path / "emballage.png",#'Packaging', #'Other packaging',
44
+ 'Tire': folder_path / "pneu.png",#'Tire',
45
+ 'Fishing net': folder_path / "hamecon.png",#'Fishing net', #'Fishing net / cord',
46
+ 'Easily namable': folder_path / "chaussure.png",#'Easily namable',
47
+ 'Unclear': folder_path / "dechet.png"#'Unclear'
48
+ }
49
+ out_dict = {}
50
+ for idx, path in id_path.items():
51
+ img = cv2.imread(path.resolve().as_posix(), cv2.IMREAD_UNCHANGED)
52
+ resized_img = cv2.resize(img, (100,60), interpolation = cv2.INTER_AREA)
53
+ out_dict[idx] = resized_img
54
+ return out_dict
tracking/track_video.py CHANGED
@@ -109,7 +109,7 @@ def track_video(reader, detections, args, engine, transition_variance, observati
109
  detections_for_frame, confs, labels = interpret_detection(detections_for_frame, args.downsampling_factor, is_yolo)
110
 
111
  max_distance = euclidean(reader.output_shape, np.array([0,0]))
112
- delta = 0.05*max_distance
113
 
114
  if display is not None and display.on:
115
 
 
109
  detections_for_frame, confs, labels = interpret_detection(detections_for_frame, args.downsampling_factor, is_yolo)
110
 
111
  max_distance = euclidean(reader.output_shape, np.array([0,0]))
112
+ delta = 0.005*max_distance
113
 
114
  if display is not None and display.on:
115
 
tracking/utils.py CHANGED
@@ -83,7 +83,45 @@ def get_detections_for_video(reader, detector, batch_size=16, device=None):
83
  return detections
84
 
85
 
86
- def generate_video_with_annotations(reader, output_detected, output_filename, skip_frames, maxframes, downscale, logger,gps_data=None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  fps = 24
88
  logger.info("---Intepreting json")
89
  results = defaultdict(list)
@@ -113,11 +151,17 @@ def generate_video_with_annotations(reader, output_detected, output_filename, sk
113
  '-vcodec': 'libx264',
114
  '-b': '5000000'})
115
 
116
- font = cv2.FONT_HERSHEY_COMPLEX
117
  for frame_nb, frame in enumerate(reader):
118
  detections_for_frame = results[frame_nb]
119
  for detection in detections_for_frame:
120
- cv2.putText(frame, f'{detection[0]}/{detection[3]}', (int(detection[1]), int(detection[2])+5), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
 
 
 
 
 
 
121
 
122
  if gps_data is not None:
123
  latitude = gps_data[frame_nb//fps]['Latitude']
@@ -126,21 +170,10 @@ def generate_video_with_annotations(reader, output_detected, output_filename, sk
126
 
127
  frame = downscale_local_mean(frame, (downscale,downscale,1)).astype(np.uint8)
128
  writer.writeFrame(frame[:,:,::-1])
129
- # moviepy version
130
- # frames.append(frame[:,:,::-1])
131
-
132
- #ret, frame, frame_nb = video.read()
133
- #if frame_nb > maxframes:
134
- # break
135
 
136
  writer.close()
137
  reader.video.release()
138
 
139
- # version with moviepy
140
- #clip = ImageSequenceClip(sequence=frames, fps=fps)
141
- #clip.write_videofile(output_filename, fps=fps)
142
- #del frames
143
-
144
  logger.info("---finished writing video")
145
 
146
 
 
83
  return detections
84
 
85
 
86
+ def overlay_transparent(background, overlay, x, y):
87
+ """ Overlays a transparent image over a background at topleft corner (x,y)
88
+ """
89
+ background_width = background.shape[1]
90
+ background_height = background.shape[0]
91
+
92
+ if x >= background_width or y >= background_height:
93
+ return background
94
+
95
+ h, w = overlay.shape[0], overlay.shape[1]
96
+
97
+ if x + w > background_width:
98
+ w = background_width - x
99
+ overlay = overlay[:, :w]
100
+
101
+ if y + h > background_height:
102
+ h = background_height - y
103
+ overlay = overlay[:h]
104
+
105
+ if overlay.shape[2] < 4:
106
+ overlay = np.concatenate(
107
+ [
108
+ overlay,
109
+ np.ones((overlay.shape[0], overlay.shape[1], 1), dtype = overlay.dtype) * 255
110
+ ],
111
+ axis = 2,
112
+ )
113
+
114
+ overlay_image = overlay[..., :3]
115
+ mask = overlay[..., 3:] / 255.0
116
+
117
+ background[y:y+h, x:x+w] = (1.0 - mask) * background[y:y+h, x:x+w] + mask * overlay_image
118
+ return background
119
+
120
+
121
+ def generate_video_with_annotations(reader, output_detected, output_filename, skip_frames,
122
+ maxframes, downscale, logger, gps_data=None, labels2icons=None):
123
+ """ Generates output video at 24 fps, with optional gps_data
124
+ """
125
  fps = 24
126
  logger.info("---Intepreting json")
127
  results = defaultdict(list)
 
151
  '-vcodec': 'libx264',
152
  '-b': '5000000'})
153
 
154
+ font = cv2.FONT_HERSHEY_TRIPLEX
155
  for frame_nb, frame in enumerate(reader):
156
  detections_for_frame = results[frame_nb]
157
  for detection in detections_for_frame:
158
+ if labels2icons is None:
159
+ # write name of class
160
+ cv2.putText(frame, f'{detection[0]}/{detection[3]}', (int(detection[1]), int(detection[2])+5), font, 2, (0, 0, 255), 3, cv2.LINE_AA)
161
+ else:
162
+ # icons
163
+ overlay_transparent(frame, labels2icons[detection[3]], int(detection[1])+5, int(detection[2]))
164
+ cv2.putText(frame, f'{detection[0]}', (int(detection[1]+46+5), int(detection[2])+42), font, 1.2, (0, 0, 0), 2, cv2.LINE_AA)
165
 
166
  if gps_data is not None:
167
  latitude = gps_data[frame_nb//fps]['Latitude']
 
170
 
171
  frame = downscale_local_mean(frame, (downscale,downscale,1)).astype(np.uint8)
172
  writer.writeFrame(frame[:,:,::-1])
 
 
 
 
 
 
173
 
174
  writer.close()
175
  reader.video.release()
176
 
 
 
 
 
 
177
  logger.info("---finished writing video")
178
 
179