babypoby commited on
Commit
3f65192
·
1 Parent(s): 835a2b0

IM DONE BITCH

Browse files
detectree2model/predictions/predict.py CHANGED
@@ -66,4 +66,6 @@ def predict(tile_path, overlap_threshold, confidence_threshold, simplify_value,
66
 
67
  def run_detectree2(tif_input_path, store_path, tile_width=20, tile_height=20, tile_buffer=20, overlap_threshold=0.35, confidence_threshold=0.2, simplify_value=0.2):
68
  tile_path = create_tiles(input_path=tif_input_path, tile_width=tile_width, tile_height=tile_height, tile_buffer=tile_buffer)
 
69
  predict(tile_path=tile_path, overlap_threshold=overlap_threshold, confidence_threshold=confidence_threshold, simplify_value=simplify_value, store_path=store_path)
 
 
66
 
67
  def run_detectree2(tif_input_path, store_path, tile_width=20, tile_height=20, tile_buffer=20, overlap_threshold=0.35, confidence_threshold=0.2, simplify_value=0.2):
68
  tile_path = create_tiles(input_path=tif_input_path, tile_width=tile_width, tile_height=tile_height, tile_buffer=tile_buffer)
69
+ print(tile_path)
70
  predict(tile_path=tile_path, overlap_threshold=overlap_threshold, confidence_threshold=confidence_threshold, simplify_value=simplify_value, store_path=store_path)
71
+
generate_tree_images/generate_tree_images.py CHANGED
@@ -4,6 +4,7 @@ import geopandas as gpd
4
  from shapely.geometry import box
5
  from rasterio.mask import mask
6
  from PIL import Image
 
7
  import numpy as np
8
  import warnings
9
  from rasterio.errors import NodataShadowWarning
@@ -16,26 +17,33 @@ def cut_trees(output_dir, geojson_path, tif_path):
16
  if not os.path.exists(output_dir):
17
  os.makedirs(output_dir)
18
 
 
19
  # Load the GeoDataFrame
 
20
  gdf = gpd.read_file(geojson_path)
21
 
 
22
  # Clear the terminal screen
23
- os.system('cls' if os.name == 'nt' else 'clear')
24
 
25
  # Open the .tif file
26
  with rasterio.open(tif_path) as src:
27
  # Get the bounds of the .tif image
28
  tif_bounds = box(*src.bounds)
29
-
 
30
  # Get the CRS (Coordinate Reference System) of the .tif image
31
- tif_crs = src.crs
32
 
33
  # Reproject the GeoDataFrame to the CRS of the .tif file
34
- gdf = gdf.to_crs(tif_crs)
 
 
35
 
36
  # Loop through each polygon in the GeoDataFrame
37
  N = len(gdf)
38
  n = int(N/10)
 
39
  image_counter = 0
40
  for idx, row in gdf.iterrows():
41
  if idx % n == 0:
@@ -46,6 +54,8 @@ def cut_trees(output_dir, geojson_path, tif_path):
46
  # Extract the geometry (polygon)
47
  geom = row['geometry']
48
  name = row['id']
 
 
49
 
50
  # Check if the polygon intersects the image bounds
51
  if geom.intersects(tif_bounds):
@@ -57,6 +67,8 @@ def cut_trees(output_dir, geojson_path, tif_path):
57
 
58
  # Ensure the array is not empty
59
  if out_image.size == 0:
 
 
60
  message = f"{round(idx/N*100)} % complete --> {idx}/{N} | Polygon {idx} resulted in an empty image and will be skipped."
61
  sys.stdout.write('\r' + message)
62
  sys.stdout.flush()
@@ -69,6 +81,8 @@ def cut_trees(output_dir, geojson_path, tif_path):
69
 
70
  # Ensure there are non-zero rows and columns
71
  if not np.any(non_zero_rows) or not np.any(non_zero_cols):
 
 
72
  message = f"{round(idx/N*100)} % complete --> {idx}/{N} | Polygon {idx} resulted in an invalid image area and will be skipped."
73
  sys.stdout.write('\r' + message)
74
  sys.stdout.flush()
@@ -82,10 +96,13 @@ def cut_trees(output_dir, geojson_path, tif_path):
82
  out_image.save(output_path)
83
  image_counter += 1
84
  else:
 
 
85
  message = f"{round(idx/N*100)} % complete --> {idx}/{N} | Polygon {idx} is outside the image bounds and will be skipped."
86
  sys.stdout.write('\r' + message)
87
  sys.stdout.flush()
88
-
 
89
  print(f'\n {image_counter}/{N} Tree images have been successfully saved in the "detected_trees" folder.')
90
 
91
 
@@ -101,11 +118,31 @@ def resize_images(input_folder, output_folder, target_size):
101
  # Open image
102
  with Image.open(os.path.join(input_folder, filename)) as img:
103
  # Resize image while preserving aspect ratio
 
 
104
  img.thumbnail(target_size, Image.LANCZOS)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # Calculate paste position to center image in canvas
106
  paste_pos = ((target_size[0] - img.size[0]) // 2, (target_size[1] - img.size[1]) // 2)
 
107
  # Create a new blank canvas with the target size and black background
108
  new_img = Image.new("RGBA", target_size, (0, 0, 0, 255))
 
109
  # Paste resized image onto the canvas
110
  new_img.paste(img, paste_pos, img)
111
  # Convert to RGB to remove transparency by merging with black background
@@ -115,7 +152,7 @@ def resize_images(input_folder, output_folder, target_size):
115
 
116
  counter += 1
117
  # Display the counter
118
- if counter % 50 == 0:
119
  message = f"Processed {counter} images"
120
  print(message, end='\r')
121
 
 
4
  from shapely.geometry import box
5
  from rasterio.mask import mask
6
  from PIL import Image
7
+ from PIL import ImageOps
8
  import numpy as np
9
  import warnings
10
  from rasterio.errors import NodataShadowWarning
 
17
  if not os.path.exists(output_dir):
18
  os.makedirs(output_dir)
19
 
20
+
21
  # Load the GeoDataFrame
22
+
23
  gdf = gpd.read_file(geojson_path)
24
 
25
+
26
  # Clear the terminal screen
27
+ # os.system('cls' if os.name == 'nt' else 'clear')
28
 
29
  # Open the .tif file
30
  with rasterio.open(tif_path) as src:
31
  # Get the bounds of the .tif image
32
  tif_bounds = box(*src.bounds)
33
+ tif_bounds = gpd.GeoDataFrame(geometry=[tif_bounds], crs=gdf.crs)
34
+ tif_bounds = tif_bounds['geometry'].iloc[0]
35
  # Get the CRS (Coordinate Reference System) of the .tif image
36
+ #tif_crs = src.crs
37
 
38
  # Reproject the GeoDataFrame to the CRS of the .tif file
39
+ # gdf = gdf.to_crs(tif_crs)
40
+ #print(tif_bounds.crs.to_epsg())
41
+ #print(gdf.crs.to_epsg())
42
 
43
  # Loop through each polygon in the GeoDataFrame
44
  N = len(gdf)
45
  n = int(N/10)
46
+ print(f"Processing {N} polygons...")
47
  image_counter = 0
48
  for idx, row in gdf.iterrows():
49
  if idx % n == 0:
 
54
  # Extract the geometry (polygon)
55
  geom = row['geometry']
56
  name = row['id']
57
+
58
+
59
 
60
  # Check if the polygon intersects the image bounds
61
  if geom.intersects(tif_bounds):
 
67
 
68
  # Ensure the array is not empty
69
  if out_image.size == 0:
70
+ print("Empty image")
71
+ gdf.drop(idx, inplace=True)
72
  message = f"{round(idx/N*100)} % complete --> {idx}/{N} | Polygon {idx} resulted in an empty image and will be skipped."
73
  sys.stdout.write('\r' + message)
74
  sys.stdout.flush()
 
81
 
82
  # Ensure there are non-zero rows and columns
83
  if not np.any(non_zero_rows) or not np.any(non_zero_cols):
84
+ print("Non zero rows or columns")
85
+ gdf.drop(idx, inplace=True)
86
  message = f"{round(idx/N*100)} % complete --> {idx}/{N} | Polygon {idx} resulted in an invalid image area and will be skipped."
87
  sys.stdout.write('\r' + message)
88
  sys.stdout.flush()
 
96
  out_image.save(output_path)
97
  image_counter += 1
98
  else:
99
+ gdf.drop(idx, inplace=True)
100
+ print("Does not intersect")
101
  message = f"{round(idx/N*100)} % complete --> {idx}/{N} | Polygon {idx} is outside the image bounds and will be skipped."
102
  sys.stdout.write('\r' + message)
103
  sys.stdout.flush()
104
+ print(len(gdf))
105
+ gdf.to_file(geojson_path, driver='GeoJSON')
106
  print(f'\n {image_counter}/{N} Tree images have been successfully saved in the "detected_trees" folder.')
107
 
108
 
 
118
  # Open image
119
  with Image.open(os.path.join(input_folder, filename)) as img:
120
  # Resize image while preserving aspect ratio
121
+ #print("Original image size: ", img.size)
122
+
123
  img.thumbnail(target_size, Image.LANCZOS)
124
+
125
+ if img.size[0] < target_size[0] or img.size[1] < target_size[1]:
126
+
127
+ # Calculate padding dimensions
128
+ pad_width = target_size[0] - img.size[0]
129
+ pad_height = target_size[1] - img.size[1]
130
+
131
+ # Calculate padding
132
+ padding = (pad_width // 2, pad_height // 2, pad_width - (pad_width // 2), pad_height - (pad_height // 2))
133
+
134
+ # Pad the image
135
+ img = ImageOps.expand(img, padding, fill=(0, 0, 0))
136
+
137
+ #print ("Resized image size: ", img.size)
138
+
139
+
140
  # Calculate paste position to center image in canvas
141
  paste_pos = ((target_size[0] - img.size[0]) // 2, (target_size[1] - img.size[1]) // 2)
142
+ #print("Paste position: ", paste_pos)
143
  # Create a new blank canvas with the target size and black background
144
  new_img = Image.new("RGBA", target_size, (0, 0, 0, 255))
145
+ img = img.convert("RGBA")
146
  # Paste resized image onto the canvas
147
  new_img.paste(img, paste_pos, img)
148
  # Convert to RGB to remove transparency by merging with black background
 
152
 
153
  counter += 1
154
  # Display the counter
155
+ if counter % 100 == 0:
156
  message = f"Processed {counter} images"
157
  print(message, end='\r')
158
 
main.py CHANGED
@@ -12,22 +12,29 @@ import numpy as np
12
  import ast
13
 
14
  def row_to_feature(row):
15
- feature = {
 
 
 
16
  "id": row["id"],
17
  "type": "Feature",
18
  "properties": {"Confidence_score": row["Confidence_score"], "species": row['species']},
19
- "geometry": {"type": "Polygon", "coordinates": [row["coordinates"]]},
20
- }
21
- return feature
 
 
 
22
 
23
  def export_geojson(df, filename):
 
24
  features = [row_to_feature(row) for idx, row in df.iterrows()]
25
 
26
  feature_collection = {
27
  "type": "FeatureCollection",
28
  "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::32720"}},
29
  "features": features,
30
- }
31
 
32
  output_geojson = json.dumps(feature_collection)
33
 
@@ -35,6 +42,23 @@ def export_geojson(df, filename):
35
  f.write(output_geojson)
36
 
37
  print(f"GeoJSON data exported to '{filename}.geojson' file.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  def process_image(image_path: str):
40
  current_directory = os.getcwd()
@@ -43,9 +67,17 @@ def process_image(image_path: str):
43
  if not os.path.exists(output_directory):
44
  os.makedirs(output_directory)
45
 
 
 
 
 
 
 
 
 
46
  run_detectree2(image_path, store_path=output_directory)
47
 
48
- processed_output_df = postprocess(output_directory + '/detectree2_delin.geojson', output_directory + '/processed_delin')
49
 
50
  processed_geojson = output_directory + '/processed_delin.geojson'
51
 
@@ -53,11 +85,13 @@ def process_image(image_path: str):
53
 
54
  output_folder = './tree_images'
55
 
 
 
56
  all_top_3_list = [] # Initialize an empty list to accumulate all top_3 lists
57
 
58
  for file_name in os.listdir(output_folder):
59
  file_path = os.path.join(output_folder, file_name)
60
- print(file_path)
61
  probs = classify(file_path)
62
  top_3 = probs.head(3)
63
  top_3_list = [[cls, prob] for cls, prob in top_3.items()]
@@ -68,6 +102,9 @@ def process_image(image_path: str):
68
  # Assign the accumulated top_3_list to the 'species' column of the dataframe
69
  processed_output_df['species'] = all_top_3_list
70
 
 
 
 
71
  final_output_path = 'result'
72
  export_geojson(processed_output_df, final_output_path)
73
 
@@ -128,7 +165,7 @@ def plot_results(geojson_path, image_path):
128
 
129
  def greet(image_path: str):
130
  geojson_path, image_path = process_image(image_path)
131
- fig = plot_results(geojson_path, image_path)
132
 
133
  return fig
134
 
 
12
  import ast
13
 
14
  def row_to_feature(row):
15
+ if (row['geometry'].geom_type == 'Polygon'):
16
+ coordinates = row['geometry'].exterior.coords.xy
17
+ coordinate_list = [[x, y] for x, y in zip(coordinates[0], coordinates[1])]
18
+ feature = {
19
  "id": row["id"],
20
  "type": "Feature",
21
  "properties": {"Confidence_score": row["Confidence_score"], "species": row['species']},
22
+ "geometry": {"type": "Polygon", "coordinates": [coordinate_list]},
23
+ }
24
+ return feature
25
+
26
+
27
+
28
 
29
  def export_geojson(df, filename):
30
+
31
  features = [row_to_feature(row) for idx, row in df.iterrows()]
32
 
33
  feature_collection = {
34
  "type": "FeatureCollection",
35
  "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::32720"}},
36
  "features": features,
37
+ }
38
 
39
  output_geojson = json.dumps(feature_collection)
40
 
 
42
  f.write(output_geojson)
43
 
44
  print(f"GeoJSON data exported to '{filename}.geojson' file.")
45
+
46
+ def delete_files_in_directory(directory_path: str) -> None:
47
+ """
48
+ Delete all files in the given directory.
49
+
50
+ :param directory_path: Path to the directory
51
+ """
52
+ if not os.path.isdir(directory_path):
53
+ raise ValueError(f"The provided path '{directory_path}' is not a valid directory.")
54
+
55
+ for filename in os.listdir(directory_path):
56
+ file_path = os.path.join(directory_path, filename)
57
+ if os.path.isfile(file_path):
58
+ os.remove(file_path)
59
+ print(f"Deleted file: {file_path}")
60
+ else:
61
+ print(f"Skipped non-file: {file_path}")
62
 
63
  def process_image(image_path: str):
64
  current_directory = os.getcwd()
 
67
  if not os.path.exists(output_directory):
68
  os.makedirs(output_directory)
69
 
70
+ delete_files_in_directory("tiles")
71
+ delete_files_in_directory("tiles/predictions")
72
+ delete_files_in_directory("tiles/predictions_geo")
73
+ delete_files_in_directory("tree_images")
74
+ delete_files_in_directory("detected_trees")
75
+
76
+
77
+
78
  run_detectree2(image_path, store_path=output_directory)
79
 
80
+ processed_output_df = postprocess(output_directory + '/detectree2_delin.geojson', output_directory + '/processed_delin.geojson')
81
 
82
  processed_geojson = output_directory + '/processed_delin.geojson'
83
 
 
85
 
86
  output_folder = './tree_images'
87
 
88
+ processed_output_df = gpd.read_file(processed_geojson)
89
+
90
  all_top_3_list = [] # Initialize an empty list to accumulate all top_3 lists
91
 
92
  for file_name in os.listdir(output_folder):
93
  file_path = os.path.join(output_folder, file_name)
94
+
95
  probs = classify(file_path)
96
  top_3 = probs.head(3)
97
  top_3_list = [[cls, prob] for cls, prob in top_3.items()]
 
102
  # Assign the accumulated top_3_list to the 'species' column of the dataframe
103
  processed_output_df['species'] = all_top_3_list
104
 
105
+ print(processed_output_df.head())
106
+ print(processed_output_df.columns)
107
+
108
  final_output_path = 'result'
109
  export_geojson(processed_output_df, final_output_path)
110
 
 
165
 
166
  def greet(image_path: str):
167
  geojson_path, image_path = process_image(image_path)
168
+ fig = plot_results (geojson_path, image_path)
169
 
170
  return fig
171
 
polygons_processing/postpprocess_detectree2.py CHANGED
@@ -315,7 +315,7 @@ def row_to_feature(row):
315
  return feature
316
 
317
 
318
- def export_df_as_geojson(df, filename="output"):
319
  features = [row_to_feature(row) for idx, row in df.iterrows()]
320
 
321
  feature_collection = {
@@ -326,10 +326,10 @@ def export_df_as_geojson(df, filename="output"):
326
 
327
  output_geojson = json.dumps(feature_collection)
328
 
329
- with open(f"{filename}.geojson", "w") as f:
330
  f.write(output_geojson)
331
 
332
- print(f"GeoJSON data exported to '{filename}.geojson' file.")
333
 
334
  def convert_id_to_string(prefix, x):
335
  return prefix + str(x)
@@ -348,9 +348,12 @@ def postprocess(prediction_geojson_path, store_path):
348
 
349
  df["to_drop"] = False
350
  df["to_merge"] = False
 
351
 
352
  df_res = process([df])
353
 
 
 
354
  export_df_as_geojson(df=df_res, filename=store_path)
355
 
356
  return df_res
 
315
  return feature
316
 
317
 
318
+ def export_df_as_geojson(df, filename):
319
  features = [row_to_feature(row) for idx, row in df.iterrows()]
320
 
321
  feature_collection = {
 
326
 
327
  output_geojson = json.dumps(feature_collection)
328
 
329
+ with open(f"{filename}", "w") as f:
330
  f.write(output_geojson)
331
 
332
+ print(f"GeoJSON data exported to '{filename}' file.")
333
 
334
  def convert_id_to_string(prefix, x):
335
  return prefix + str(x)
 
348
 
349
  df["to_drop"] = False
350
  df["to_merge"] = False
351
+ print(f"Number of polygons before postprocessing: {len(df)}")
352
 
353
  df_res = process([df])
354
 
355
+ print(f"Number of polygons after postprocessing: {len(df_res)}")
356
+
357
  export_df_as_geojson(df=df_res, filename=store_path)
358
 
359
  return df_res