|
import os |
|
import cv2 |
|
import zipfile |
|
import numpy as np |
|
import streamlit as st |
|
from io import BytesIO |
|
from PIL import Image |
|
from ultralytics import YOLO |
|
from shapely.geometry import Polygon |
|
import shapefile |
|
import json |
|
import math |
|
from utils import create_shapefile_with_latlon |
|
|
|
|
|
Image.MAX_IMAGE_PIXELS = None |
|
|
|
|
|
path_to_store_bounding_boxes = 'detect/' |
|
path_to_save_shapefile = 'weed_detections.shp' |
|
slice_folder = 'slices/' |
|
shapefile_folder = 'shapes/' |
|
|
|
|
|
os.makedirs(path_to_store_bounding_boxes, exist_ok=True) |
|
os.makedirs(slice_folder, exist_ok=True) |
|
os.makedirs(shapefile_folder, exist_ok=True) |
|
|
|
|
|
model = YOLO('new_yolov8_best.pt') |
|
|
|
|
|
class_names = ["citrus area", "trees", "weeds", "weeds and trees"] |
|
|
|
|
|
st.title("Weed Detection and Shapefile Creation") |
|
|
|
|
|
st.sidebar.header("Image Coordinates") |
|
top_left = st.sidebar.text_input("Top Left (lon, lat)", value="-48.8877415, -20.585013") |
|
top_right = st.sidebar.text_input("Top Right (lon, lat)", value="-48.8819718, -20.585013") |
|
bottom_right = st.sidebar.text_input("Bottom Right (lon, lat)", value="-48.8819718, -20.5968754") |
|
bottom_left = st.sidebar.text_input("Bottom Left (lon, lat)", value="-48.8877415, -20.5968754") |
|
|
|
|
|
image_coords = [ |
|
tuple(map(float, top_left.split(','))), |
|
tuple(map(float, top_right.split(','))), |
|
tuple(map(float, bottom_right.split(','))), |
|
tuple(map(float, bottom_left.split(','))) |
|
] |
|
|
|
|
|
uploaded_image = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"]) |
|
|
|
def calculate_new_coordinates(original_coords, start_x, start_y, end_x, end_y, img_width, img_height): |
|
lon_step = (original_coords[1][0] - original_coords[0][0]) / img_width |
|
lat_step = (original_coords[0][1] - original_coords[3][1]) / img_height |
|
|
|
new_top_left = (original_coords[0][0] + start_x * lon_step, original_coords[0][1] - start_y * lat_step) |
|
new_top_right = (original_coords[0][0] + end_x * lon_step, original_coords[0][1] - start_y * lat_step) |
|
new_bottom_right = (original_coords[0][0] + end_x * lon_step, original_coords[0][1] - end_y * lat_step) |
|
new_bottom_left = (original_coords[0][0] + start_x * lon_step, original_coords[0][1] - end_y * lat_step) |
|
|
|
return [new_top_left, new_top_right, new_bottom_right, new_bottom_left] |
|
|
|
def slice_image_and_coordinates(image_path, original_coords, slice_width=3000, slice_height=3000, output_folder='slices'): |
|
os.makedirs(output_folder, exist_ok=True) |
|
img = Image.open(image_path) |
|
img_width, img_height = img.size |
|
|
|
slice_coords = {} |
|
slice_id = 0 |
|
|
|
num_slices_x = math.ceil(img_width / slice_width) |
|
num_slices_y = math.ceil(img_height / slice_height) |
|
|
|
for i in range(num_slices_y): |
|
for j in range(num_slices_x): |
|
start_x = j * slice_width |
|
end_x = min(start_x + slice_width, img_width) |
|
start_y = i * slice_height |
|
end_y = min(start_y + slice_height, img_height) |
|
|
|
box = (start_x, start_y, end_x, end_y) |
|
cut_img = img.crop(box) |
|
|
|
slice_filename = f'slice_{slice_id}.png' |
|
cut_img.save(os.path.join(output_folder, slice_filename)) |
|
|
|
new_coords = calculate_new_coordinates(original_coords, start_x, start_y, end_x, end_y, img_width, img_height) |
|
slice_coords[slice_filename] = new_coords |
|
|
|
slice_id += 1 |
|
|
|
with open(os.path.join(output_folder, 'coordinates.json'), 'w') as json_file: |
|
json.dump(slice_coords, json_file, indent=4) |
|
|
|
return slice_coords |
|
|
|
def convert_pixel_to_latlon(x, y, image_width, image_height, image_coords): |
|
top_left, top_right, bottom_right, bottom_left = image_coords |
|
|
|
lon_top = top_left[0] + (top_right[0] - top_left[0]) * (x / image_width) |
|
lon_bottom = bottom_left[0] + (bottom_right[0] - bottom_left[0]) * (x / image_width) |
|
lat_left = top_left[1] + (bottom_left[1] - top_left[1]) * (y / image_height) |
|
lat_right = top_right[1] + (bottom_right[1] - top_right[1]) * (y / image_height) |
|
|
|
lon = lon_top + (lon_bottom - lon_top) * (y / image_height) |
|
lat = lat_left + (lat_right - lat_left) * (x / image_width) |
|
|
|
return lon, lat |
|
|
|
if uploaded_image is not None: |
|
st.image(uploaded_image, caption="Uploaded Image", use_column_width=True) |
|
temp_image_path = "temp_uploaded_image.png" |
|
image = Image.open(uploaded_image) |
|
image.save(temp_image_path) |
|
|
|
|
|
slice_coords = slice_image_and_coordinates(temp_image_path, image_coords, slice_width=3000, slice_height=3000, output_folder=slice_folder) |
|
|
|
if st.button("Detect Weeds"): |
|
all_weed_bboxes = [] |
|
|
|
for slice_filename, coords in slice_coords.items(): |
|
slice_path = os.path.join(slice_folder, slice_filename) |
|
image = cv2.imread(slice_path) |
|
image_height, image_width, _ = image.shape |
|
|
|
results = model.predict(slice_path, imgsz=640, conf=0.2, iou=0.4) |
|
results = results[0] |
|
|
|
weed_bboxes = [] |
|
|
|
for i, box in enumerate(results.boxes): |
|
tensor = box.xyxy[0] |
|
x1 = int(tensor[0].item()) |
|
y1 = int(tensor[1].item()) |
|
x2 = int(tensor[2].item()) |
|
y2 = int(tensor[3].item()) |
|
conf = box.conf[0].item() |
|
label = box.cls[0].item() |
|
|
|
if class_names[int(label)] == "weeds": |
|
cv2.rectangle(image, (x1, y1), (x2, y2), (255, 0, 255), 3) |
|
weed_bboxes.append((x1, y1, x2, y2)) |
|
|
|
if weed_bboxes: |
|
create_shapefile_with_latlon(weed_bboxes, (image_width, image_height), coords, f'shapes/{slice_filename.replace(".png", ".shp")}') |
|
all_weed_bboxes.extend(weed_bboxes) |
|
|
|
cv2.imwrite(os.path.join(path_to_store_bounding_boxes, slice_filename), image) |
|
|
|
final_shapefile_path = path_to_save_shapefile |
|
w = shapefile.Writer(final_shapefile_path) |
|
w.field('id', 'C') |
|
|
|
for slice_filename, coords in slice_coords.items(): |
|
shape_path = os.path.join(shapefile_folder, slice_filename.replace('.png', '.shp')) |
|
if os.path.exists(shape_path): |
|
r = shapefile.Reader(shape_path) |
|
for shape_rec in r.iterShapeRecords(): |
|
w.shape(shape_rec.shape) |
|
w.record(shape_rec.record[0]) |
|
|
|
w.close() |
|
|
|
zip_buffer = BytesIO() |
|
with zipfile.ZipFile(zip_buffer, 'w') as zip_file: |
|
for filename in ['weed_detections.shp', 'weed_detections.shx', 'weed_detections.dbf']: |
|
zip_file.write(filename, os.path.basename(filename)) |
|
zip_buffer.seek(0) |
|
|
|
st.download_button( |
|
label="Download Shapefile ZIP", |
|
data=zip_buffer, |
|
file_name="weed_detections.zip", |
|
mime="application/zip" |
|
) |
|
|
|
st.success("Weed detection completed and shapefile created successfully!") |
|
|
|
|