Timmyafolami commited on
Commit
ffee029
·
verified ·
1 Parent(s): ae3b317

New update.

Browse files

Enabled detecting a full map image.

Files changed (1) hide show
  1. Weed_Detector.py +183 -108
Weed_Detector.py CHANGED
@@ -1,108 +1,183 @@
1
- import os
2
- import cv2
3
- import zipfile
4
- import numpy as np
5
- import streamlit as st
6
- from io import BytesIO
7
- from PIL import Image
8
- from ultralytics import YOLO
9
- from utils import create_shapefile_with_latlon
10
-
11
-
12
- # Define paths
13
- path_to_store_bounding_boxes = 'detect/'
14
- path_to_save_shapefile = 'weed_detections.shp'
15
-
16
- # Ensure the output directories exist
17
- os.makedirs(path_to_store_bounding_boxes, exist_ok=True)
18
-
19
- # loading a custom model
20
- model = YOLO('new_yolov8_best.pt')
21
-
22
- # Mapping of class labels to readable names (assuming 'weeds' is class 1)
23
- class_names = ["citrus area", "trees", "weeds", "weeds and trees" ]
24
-
25
-
26
- # Streamlit UI
27
- st.title("Weed Detection and Shapefile Creation")
28
-
29
- # Input coordinates for image corners
30
- st.sidebar.header("Image Coordinates")
31
- top_left = st.sidebar.text_input("Top Left (lon, lat)", value="-48.8864783, -20.5906375")
32
- top_right = st.sidebar.text_input("Top Right (lon, lat)", value="-48.8855653, -20.5906264")
33
- bottom_right = st.sidebar.text_input("Bottom Right (lon, lat)", value="-48.8855534, -20.5914861")
34
- bottom_left = st.sidebar.text_input("Bottom Left (lon, lat)", value="-48.8864664, -20.5914973")
35
-
36
- # Convert input coordinates to tuples
37
- image_coords = [
38
- tuple(map(float, top_left.split(','))),
39
- tuple(map(float, top_right.split(','))),
40
- tuple(map(float, bottom_right.split(','))),
41
- tuple(map(float, bottom_left.split(',')))
42
- ]
43
-
44
- # Upload image
45
- uploaded_image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
46
-
47
- if uploaded_image is not None:
48
- # Display uploaded image
49
- st.image(uploaded_image, caption="Uploaded Image", use_column_width=True)
50
- img = Image.open(uploaded_image)
51
- img_array = np.array(img)
52
- image_height, image_width, _ = img_array.shape
53
- temp_image_path = "temp_uploaded_image.png"
54
- image = Image.open(uploaded_image)
55
- image.save(temp_image_path)
56
-
57
- # Perform weed detection on button click
58
- if st.button("Detect Weeds"):
59
- # Perform model prediction
60
- results = model.predict(temp_image_path, imgsz=640, conf=0.2, iou=0.4)
61
- results = results[0]
62
-
63
- weed_bboxes = []
64
-
65
- for i, box in enumerate(results.boxes):
66
- tensor = box.xyxy[0]
67
- x1 = int(tensor[0].item())
68
- y1 = int(tensor[1].item())
69
- x2 = int(tensor[2].item())
70
- y2 = int(tensor[3].item())
71
- conf = box.conf[0].item() # Confidence score
72
- label = box.cls[0].item() # Class label
73
-
74
- # Debugging output to ensure boxes are detected
75
- print(f"Box {i}: ({x1}, {y1}), ({x2}, {y2}), label: {label}, confidence: {conf}")
76
-
77
- # Only process if the detected class is "weeds"
78
- if class_names[int(label)] == "weeds":
79
- print("weed detected")
80
- # Draw bounding box on the image
81
- cv2.rectangle(img_array, (x1, y1), (x2, y2), (255, 0, 255), 3)
82
- # Save the bounding box coordinates
83
- weed_bboxes.append((x1, y1, x2, y2))
84
-
85
- # Save the image with bounding boxes
86
- detected_image_path = os.path.join(path_to_store_bounding_boxes, "detected_image.png")
87
- cv2.imwrite(detected_image_path, cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR))
88
-
89
- # Display the image with bounding boxes
90
- st.image(img_array, caption="Detected Weeds", use_column_width=True)
91
-
92
- # Create shapefile with bounding boxes
93
- create_shapefile_with_latlon(weed_bboxes, (image_width, image_height), image_coords, path_to_save_shapefile)
94
-
95
- # Create ZIP file of the shapefile components
96
- zip_buffer = BytesIO()
97
- with zipfile.ZipFile(zip_buffer, 'w') as zip_file:
98
- for filename in ['weed_detections.shp', 'weed_detections.shx', 'weed_detections.dbf']:
99
- zip_file.write(filename, os.path.basename(filename))
100
- zip_buffer.seek(0)
101
-
102
- # Download ZIP file
103
- st.download_button(
104
- label="Download Shapefile ZIP",
105
- data=zip_buffer,
106
- file_name="weed_detections.zip",
107
- mime="application/zip"
108
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import zipfile
4
+ import numpy as np
5
+ import streamlit as st
6
+ from io import BytesIO
7
+ from PIL import Image
8
+ from ultralytics import YOLO
9
+ from shapely.geometry import Polygon
10
+ import shapefile
11
+ import json
12
+ import math
13
+ from utils import create_shapefile_with_latlon
14
+
15
+ # Increase the limit for PIL's decompression bomb protection
16
+ Image.MAX_IMAGE_PIXELS = None
17
+
18
+ # Define paths
19
+ path_to_store_bounding_boxes = 'detect/'
20
+ path_to_save_shapefile = 'weed_detections.shp'
21
+ slice_folder = 'slices/'
22
+ shapefile_folder = 'shapes/'
23
+
24
+ # Ensure the output directories exist
25
+ os.makedirs(path_to_store_bounding_boxes, exist_ok=True)
26
+ os.makedirs(slice_folder, exist_ok=True)
27
+ os.makedirs(shapefile_folder, exist_ok=True)
28
+
29
+ # Loading a custom model
30
+ model = YOLO('new_yolov8_best.pt')
31
+
32
+ # Mapping of class labels to readable names (assuming 'weeds' is class 1)
33
+ class_names = ["citrus area", "trees", "weeds", "weeds and trees"]
34
+
35
+ # Streamlit UI
36
+ st.title("Weed Detection and Shapefile Creation")
37
+
38
+ # Input coordinates for image corners
39
+ st.sidebar.header("Image Coordinates")
40
+ top_left = st.sidebar.text_input("Top Left (lon, lat)", value="-48.8877415, -20.585013")
41
+ top_right = st.sidebar.text_input("Top Right (lon, lat)", value="-48.8819718, -20.585013")
42
+ bottom_right = st.sidebar.text_input("Bottom Right (lon, lat)", value="-48.8819718, -20.5968754")
43
+ bottom_left = st.sidebar.text_input("Bottom Left (lon, lat)", value="-48.8877415, -20.5968754")
44
+
45
+ # Convert input coordinates to tuples
46
+ image_coords = [
47
+ tuple(map(float, top_left.split(','))),
48
+ tuple(map(float, top_right.split(','))),
49
+ tuple(map(float, bottom_right.split(','))),
50
+ tuple(map(float, bottom_left.split(',')))
51
+ ]
52
+
53
+ # Upload image
54
+ uploaded_image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
55
+
56
+ def calculate_new_coordinates(original_coords, start_x, start_y, end_x, end_y, img_width, img_height):
57
+ lon_step = (original_coords[1][0] - original_coords[0][0]) / img_width
58
+ lat_step = (original_coords[0][1] - original_coords[3][1]) / img_height
59
+
60
+ new_top_left = (original_coords[0][0] + start_x * lon_step, original_coords[0][1] - start_y * lat_step)
61
+ new_top_right = (original_coords[0][0] + end_x * lon_step, original_coords[0][1] - start_y * lat_step)
62
+ new_bottom_right = (original_coords[0][0] + end_x * lon_step, original_coords[0][1] - end_y * lat_step)
63
+ new_bottom_left = (original_coords[0][0] + start_x * lon_step, original_coords[0][1] - end_y * lat_step)
64
+
65
+ return [new_top_left, new_top_right, new_bottom_right, new_bottom_left]
66
+
67
+ def slice_image_and_coordinates(image_path, original_coords, slice_width=3000, slice_height=3000, output_folder='slices'):
68
+ os.makedirs(output_folder, exist_ok=True)
69
+ img = Image.open(image_path)
70
+ img_width, img_height = img.size
71
+
72
+ slice_coords = {}
73
+ slice_id = 0
74
+
75
+ num_slices_x = math.ceil(img_width / slice_width)
76
+ num_slices_y = math.ceil(img_height / slice_height)
77
+
78
+ for i in range(num_slices_y):
79
+ for j in range(num_slices_x):
80
+ start_x = j * slice_width
81
+ end_x = min(start_x + slice_width, img_width)
82
+ start_y = i * slice_height
83
+ end_y = min(start_y + slice_height, img_height)
84
+
85
+ box = (start_x, start_y, end_x, end_y)
86
+ cut_img = img.crop(box)
87
+
88
+ slice_filename = f'slice_{slice_id}.png'
89
+ cut_img.save(os.path.join(output_folder, slice_filename))
90
+
91
+ new_coords = calculate_new_coordinates(original_coords, start_x, start_y, end_x, end_y, img_width, img_height)
92
+ slice_coords[slice_filename] = new_coords
93
+
94
+ slice_id += 1
95
+
96
+ with open(os.path.join(output_folder, 'coordinates.json'), 'w') as json_file:
97
+ json.dump(slice_coords, json_file, indent=4)
98
+
99
+ return slice_coords
100
+
101
+ def convert_pixel_to_latlon(x, y, image_width, image_height, image_coords):
102
+ top_left, top_right, bottom_right, bottom_left = image_coords
103
+
104
+ lon_top = top_left[0] + (top_right[0] - top_left[0]) * (x / image_width)
105
+ lon_bottom = bottom_left[0] + (bottom_right[0] - bottom_left[0]) * (x / image_width)
106
+ lat_left = top_left[1] + (bottom_left[1] - top_left[1]) * (y / image_height)
107
+ lat_right = top_right[1] + (bottom_right[1] - top_right[1]) * (y / image_height)
108
+
109
+ lon = lon_top + (lon_bottom - lon_top) * (y / image_height)
110
+ lat = lat_left + (lat_right - lat_left) * (x / image_width)
111
+
112
+ return lon, lat
113
+
114
+ if uploaded_image is not None:
115
+ st.image(uploaded_image, caption="Uploaded Image", use_column_width=True)
116
+ temp_image_path = "temp_uploaded_image.png"
117
+ image = Image.open(uploaded_image)
118
+ image.save(temp_image_path)
119
+
120
+ # Slice the image and save slices with their coordinates
121
+ slice_coords = slice_image_and_coordinates(temp_image_path, image_coords, slice_width=3000, slice_height=3000, output_folder=slice_folder)
122
+
123
+ if st.button("Detect Weeds"):
124
+ all_weed_bboxes = []
125
+
126
+ for slice_filename, coords in slice_coords.items():
127
+ slice_path = os.path.join(slice_folder, slice_filename)
128
+ image = cv2.imread(slice_path)
129
+ image_height, image_width, _ = image.shape
130
+
131
+ results = model.predict(slice_path, imgsz=640, conf=0.2, iou=0.4)
132
+ results = results[0]
133
+
134
+ weed_bboxes = []
135
+
136
+ for i, box in enumerate(results.boxes):
137
+ tensor = box.xyxy[0]
138
+ x1 = int(tensor[0].item())
139
+ y1 = int(tensor[1].item())
140
+ x2 = int(tensor[2].item())
141
+ y2 = int(tensor[3].item())
142
+ conf = box.conf[0].item()
143
+ label = box.cls[0].item()
144
+
145
+ if class_names[int(label)] == "weeds":
146
+ cv2.rectangle(image, (x1, y1), (x2, y2), (255, 0, 255), 3)
147
+ weed_bboxes.append((x1, y1, x2, y2))
148
+
149
+ if weed_bboxes:
150
+ create_shapefile_with_latlon(weed_bboxes, (image_width, image_height), coords, f'shapes/{slice_filename.replace(".png", ".shp")}')
151
+ all_weed_bboxes.extend(weed_bboxes)
152
+
153
+ cv2.imwrite(os.path.join(path_to_store_bounding_boxes, slice_filename), image)
154
+
155
+ final_shapefile_path = path_to_save_shapefile
156
+ w = shapefile.Writer(final_shapefile_path)
157
+ w.field('id', 'C')
158
+
159
+ for slice_filename, coords in slice_coords.items():
160
+ shape_path = os.path.join(shapefile_folder, slice_filename.replace('.png', '.shp'))
161
+ if os.path.exists(shape_path):
162
+ r = shapefile.Reader(shape_path)
163
+ for shape_rec in r.iterShapeRecords():
164
+ w.shape(shape_rec.shape)
165
+ w.record(shape_rec.record[0])
166
+
167
+ w.close()
168
+
169
+ zip_buffer = BytesIO()
170
+ with zipfile.ZipFile(zip_buffer, 'w') as zip_file:
171
+ for filename in ['weed_detections.shp', 'weed_detections.shx', 'weed_detections.dbf']:
172
+ zip_file.write(filename, os.path.basename(filename))
173
+ zip_buffer.seek(0)
174
+
175
+ st.download_button(
176
+ label="Download Shapefile ZIP",
177
+ data=zip_buffer,
178
+ file_name="weed_detections.zip",
179
+ mime="application/zip"
180
+ )
181
+
182
+ st.success("Weed detection completed and shapefile created successfully!")
183
+