Intern-4 commited on
Commit
f564c07
·
1 Parent(s): 2baa551

uploading project files

Browse files
Files changed (6) hide show
  1. .DS_Store +0 -0
  2. .gitattributes +1 -0
  3. README.md +1 -1
  4. gradio_with_map.py +220 -0
  5. requirements.txt +114 -0
  6. weights/best.pt +3 -0
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ weights/best.pt filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -5,7 +5,7 @@ colorFrom: yellow
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 4.40.0
8
- app_file: app.py
9
  pinned: false
10
  license: apache-2.0
11
  ---
 
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 4.40.0
8
+ app_file: gradio_with_map.py
9
  pinned: false
10
  license: apache-2.0
11
  ---
gradio_with_map.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as ET
2
+ import gradio as gr
3
+ import PIL.Image as Image
4
+ import numpy as np
5
+ import cv2
6
+ from ultralytics import YOLOv10
7
+ from exiftool import ExifToolHelper
8
+ from geopy.distance import geodesic
9
+ import folium
10
+ import base64
11
+ import supervision as sv
12
+ import os
13
+
14
+ # Constants for image dimensions
15
+ IMAGE_WIDTH = 4000
16
+ IMAGE_HEIGHT = 3000
17
+
18
+ # Load YOLO model
19
+ model = YOLOv10("weights/best.pt")
20
+
21
+ # Define the directory for saving uploaded images
22
+ UPLOAD_DIR = './uploads/' # Or any other directory within your project
23
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
24
+
25
+
26
+ # Function to calculate ground distance from pixel distance
27
+ def calculate_ground_distance(altitude, fov_deg, image_dimension, pixel_distance):
28
+ fov_rad = np.radians(fov_deg)
29
+ ground_distance = (2 * altitude * np.tan(fov_rad / 2)) * (pixel_distance / image_dimension)
30
+ return ground_distance
31
+
32
+ # Function to get GPS coordinates from offsets
33
+ def get_gps_coordinates(lat, lon, north_offset, east_offset):
34
+ new_location = geodesic(meters=north_offset).destination((lat, lon), 0)
35
+ new_location = geodesic(meters=east_offset).destination(new_location, 90)
36
+ return new_location.latitude, new_location.longitude
37
+
38
+ def extract_xmp_metadata(xmp_data):
39
+ # Parse the XMP data as an XML tree
40
+ root = ET.fromstring(xmp_data)
41
+
42
+ # Define the namespace to use for querying elements
43
+ ns = {
44
+ 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
45
+ 'drone-dji': 'http://www.dji.com/drone-dji/1.0/'
46
+ }
47
+
48
+ # Find the rdf:Description element
49
+ rdf_description = root.find('.//rdf:Description', ns)
50
+
51
+ # Extract the desired values
52
+ relative_altitude = float(rdf_description.get('{http://www.dji.com/drone-dji/1.0/}RelativeAltitude', '0'))
53
+ gimbal_yaw_degree = float(rdf_description.get('{http://www.dji.com/drone-dji/1.0/}GimbalYawDegree', '0'))
54
+ gimbal_pitch_degree = float(rdf_description.get('{http://www.dji.com/drone-dji/1.0/}GimbalPitchDegree', '0'))
55
+
56
+ return relative_altitude, gimbal_yaw_degree, gimbal_pitch_degree
57
+
58
+ def save_image_with_metadata(img, img_path):
59
+ # Convert PIL Image to a format that retains EXIF
60
+ img_format = img.format or 'JPEG'
61
+
62
+ # Save image to a temporary file to preserve metadata
63
+ img.save(img_path, format=img_format)
64
+
65
+
66
+ def predict_image(img, conf_threshold, iou_threshold):
67
+ # Define the file path within the uploads directory
68
+ img_path = os.path.join(UPLOAD_DIR, 'uploaded_image.jpg')
69
+
70
+ # Save the image
71
+ save_image_with_metadata(img, img_path)
72
+
73
+ # Extract XMP data
74
+ xmp_data = img.info.get("xmp")
75
+
76
+ if xmp_data:
77
+ relative_altitude, gimbal_yaw_degree, gimbal_pitch_degree = extract_xmp_metadata(xmp_data)
78
+ # for debugging
79
+ print("Extracted XMP Metadata:")
80
+ print(f"Relative Altitude: {relative_altitude}")
81
+ print(f"Gimbal Yaw Degree: {gimbal_yaw_degree}")
82
+ print(f"Gimbal Pitch Degree: {gimbal_pitch_degree}")
83
+ else:
84
+ print("XMP data not found in the image.")
85
+
86
+ # Extract EXIF data
87
+ exif_data = img.info.get("exif")
88
+ try:
89
+ xmp_data = img.info.get("xmp")
90
+ #print(xmp_data)
91
+ except:
92
+ print("error loading xmp data")
93
+ #print(exif_data)
94
+
95
+ # Save the image with metadata
96
+ if exif_data:
97
+ img.save(img_path, exif=exif_data) # Save the image with its EXIF data
98
+ else:
99
+ img.save(img_path) # Save without EXIF data if not available
100
+
101
+ # Convert PIL Image to OpenCV image
102
+ img_cv2 = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
103
+
104
+ # Use ExifTool to extract metadata
105
+ metadata = {}
106
+ tag_list = [
107
+ "Composite:FOV",
108
+ "Composite:GPSLatitude",
109
+ "Composite:GPSLongitude",
110
+ "XMP:AbsoluteAltitude",
111
+ "XMP:RelativeAltitude",
112
+ "XMP:GimbalRollDegree",
113
+ "XMP:GimbalYawDegree",
114
+ "XMP:GimbalPitchDegree"
115
+ ]
116
+
117
+ rel_path = img_path.lstrip("./")
118
+ #print(rel_path)
119
+ with ExifToolHelper() as et:
120
+ for d in et.get_metadata(rel_path):
121
+ metadata.update({k: v for k, v in d.items() if k in tag_list})
122
+
123
+ # Extract necessary metadata
124
+ CAMERA_GPS = (metadata["Composite:GPSLatitude"], metadata["Composite:GPSLongitude"])
125
+ RELATIVE_ALTITUDE = float(relative_altitude)
126
+ GIMBAL_YAW_DEGREE = float(gimbal_yaw_degree)
127
+ FOV_HORIZONTAL = float(metadata["Composite:FOV"])
128
+ FOV_VERTICAL = FOV_HORIZONTAL * (IMAGE_HEIGHT / IMAGE_WIDTH)
129
+ #GIMBAL_PITCH_DEGREE = float(gimbal_pitch_degree)
130
+
131
+ # Convert degrees to radians
132
+ yaw_rad = np.radians(GIMBAL_YAW_DEGREE)
133
+ #pitch_rad = np.radians(GIMBAL_PITCH_DEGREE)
134
+
135
+ # Perform prediction
136
+ results = model.predict(
137
+ source=img_cv2,
138
+ conf=conf_threshold,
139
+ iou=iou_threshold,
140
+ show_labels=True,
141
+ show_conf=True,
142
+ imgsz=640,
143
+ )
144
+
145
+ detections = sv.Detections.from_ultralytics(results[0])
146
+
147
+ # Annotate and display image
148
+ for r in results:
149
+ im_array = r.plot()
150
+ im = Image.fromarray(im_array[..., ::-1])
151
+
152
+ # Process detections and calculate GPS coordinates
153
+ building_locations = []
154
+ for i, box in enumerate(detections.xyxy): # Correct way to iterate through boxes
155
+ # Extract bounding box coordinates and class
156
+ #print(box)
157
+ x_min, y_min, x_max, y_max = box # Access the first (and only) box
158
+ class_id = int(detections.class_id[i]) # Get class ID as an integer
159
+
160
+ x_center = (x_min + x_max) / 2
161
+ y_center = (y_min + y_max) / 2
162
+
163
+ pixel_distance_x = x_center - IMAGE_WIDTH / 2
164
+ pixel_distance_y = IMAGE_HEIGHT / 2 - y_center
165
+
166
+ ground_distance_x = calculate_ground_distance(RELATIVE_ALTITUDE, FOV_HORIZONTAL, IMAGE_WIDTH, pixel_distance_x)
167
+ ground_distance_y = calculate_ground_distance(RELATIVE_ALTITUDE, FOV_VERTICAL, IMAGE_HEIGHT, pixel_distance_y)
168
+
169
+ east_offset = ground_distance_x * np.cos(yaw_rad) - ground_distance_y * np.sin(yaw_rad)
170
+ north_offset = ground_distance_x * np.sin(yaw_rad) + ground_distance_y * np.cos(yaw_rad)
171
+
172
+ building_lat, building_lon = get_gps_coordinates(CAMERA_GPS[0], CAMERA_GPS[1], north_offset, east_offset)
173
+ building_locations.append((building_lat, building_lon, class_id))
174
+
175
+ # Create a Folium map centered at the camera's GPS position
176
+ map_center = CAMERA_GPS
177
+ m = folium.Map(
178
+ location=map_center,
179
+ zoom_start=18,
180
+ tiles='Esri.WorldImagery'
181
+ )
182
+
183
+ # Add markers for each detected building
184
+ for i, (building_lat, building_lon, class_id) in enumerate(building_locations):
185
+ building_status = 'Damaged' if class_id == 1 else 'Undamaged'
186
+
187
+ folium.Marker(
188
+ location=(building_lat, building_lon),
189
+ popup=f'Building {i+1}: {building_status}',
190
+ icon=folium.Icon(color='red' if class_id == 1 else 'green', icon='home')
191
+ ).add_to(m)
192
+
193
+ # Save map to HTML and convert to display in Gradio
194
+ m.save('temp_map.html')
195
+ with open('temp_map.html', 'r') as f:
196
+ folium_map_html = f.read()
197
+
198
+ encoded_html = base64.b64encode(folium_map_html.encode()).decode('utf-8')
199
+ data_url = f"data:text/html;base64,{encoded_html}"
200
+
201
+ return im, f'<iframe src="{data_url}" width="100%" height="600" style="border:none;"></iframe>'
202
+
203
+ # Gradio Interface
204
+ iface = gr.Interface(
205
+ fn=predict_image,
206
+ inputs=[
207
+ gr.Image(type="pil", label="Upload Image"),
208
+ gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold"),
209
+ gr.Slider(minimum=0, maximum=1, value=0.45, label="IoU threshold"),
210
+ ],
211
+ outputs=[
212
+ gr.Image(type="pil", label="Annotated Image"),
213
+ gr.HTML(label="Map"),
214
+ ],
215
+ title="Custom trained Yolov10 Model on Rescuenet Dataset",
216
+ description="Upload images for inference and view detected building locations on map.",
217
+ )
218
+
219
+ if __name__ == "__main__":
220
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1
2
+ altair==5.3.0
3
+ annotated-types==0.7.0
4
+ anyio==4.4.0
5
+ attrs==23.2.0
6
+ beautifulsoup4==4.12.3
7
+ bleach==6.1.0
8
+ branca==0.7.2
9
+ certifi==2024.6.2
10
+ chardet==4.0.0
11
+ click==8.1.7
12
+ comet-ml==3.44.3
13
+ configobj==5.0.8
14
+ contourpy==1.2.1
15
+ cycler==0.12.1
16
+ defusedxml==0.7.1
17
+ dnspython==2.6.1
18
+ docopt==0.6.2
19
+ dulwich==0.22.1
20
+ email_validator==2.2.0
21
+ everett==3.1.0
22
+ exceptiongroup==1.2.1
23
+ ExifRead==3.0.0
24
+ fastapi==0.111.0
25
+ fastapi-cli==0.0.4
26
+ fastjsonschema==2.20.0
27
+ ffmpy==0.3.2
28
+ filetype==1.2.0
29
+ folium==0.17.0
30
+ fonttools==4.53.0
31
+ fsspec==2024.6.0
32
+ geographiclib==2.0
33
+ geopy==2.4.1
34
+ gradio==4.31.5
35
+ gradio_client==0.16.4
36
+ h11==0.14.0
37
+ httpcore==1.0.5
38
+ httptools==0.6.1
39
+ httpx==0.27.0
40
+ huggingface-hub==0.23.2
41
+ importlib_metadata==8.0.0
42
+ importlib_resources==6.4.0
43
+ ipython==8.12.3
44
+ jsonschema==4.22.0
45
+ jsonschema-specifications==2023.12.1
46
+ jupyterlab_pygments==0.3.0
47
+ kiwisolver==1.4.5
48
+ markdown-it-py==3.0.0
49
+ matplotlib==3.9.0
50
+ mdurl==0.1.2
51
+ mistune==3.0.2
52
+ nbclient==0.10.0
53
+ nbconvert==7.16.4
54
+ nbformat==5.10.4
55
+ onnx==1.14.0
56
+ onnxruntime==1.15.1
57
+ onnxsim==0.4.36
58
+ opencv-python==4.9.0.80
59
+ opencv-python-headless==4.10.0.84
60
+ orjson==3.10.5
61
+ pandas==2.2.2
62
+ pandocfilters==1.5.1
63
+ piexif==1.1.3
64
+ pillow==10.3.0
65
+ pipreqs==0.5.0
66
+ protobuf==4.25.3
67
+ py-cpuinfo==9.0.0
68
+ pycocotools==2.0.7
69
+ pydantic==2.7.4
70
+ pydantic_core==2.18.4
71
+ pydub==0.25.1
72
+ PyExifTool==0.5.6
73
+ pyparsing==3.1.2
74
+ python-box==6.1.0
75
+ python-dotenv==1.0.1
76
+ python-multipart==0.0.9
77
+ pytz==2024.1
78
+ referencing==0.35.1
79
+ requests-toolbelt==1.0.0
80
+ rich==13.7.1
81
+ roboflow==1.1.36
82
+ rpds-py==0.18.1
83
+ ruff==0.4.10
84
+ safetensors==0.4.3
85
+ scipy==1.13.0
86
+ seaborn==0.13.2
87
+ semantic-version==2.10.0
88
+ sentry-sdk==2.12.0
89
+ shellingham==1.5.4
90
+ simplejson==3.19.2
91
+ sniffio==1.3.1
92
+ soupsieve==2.5
93
+ starlette==0.37.2
94
+ supervision==0.22.0
95
+ tinycss2==1.3.0
96
+ tomlkit==0.12.0
97
+ toolz==0.12.1
98
+ torch==2.0.1
99
+ torchvision==0.15.2
100
+ tqdm==4.66.4
101
+ typer==0.12.3
102
+ tzdata==2024.1
103
+ ujson==5.10.0
104
+ ultralytics @ git+https://github.com/THU-MIG/yolov10.git@aad320dd80b56694e590c950b25060a134966496
105
+ uvicorn==0.30.1
106
+ uvloop==0.19.0
107
+ watchfiles==0.22.0
108
+ webencodings==0.5.1
109
+ websockets==11.0.3
110
+ wrapt==1.16.0
111
+ wurlitzer==3.1.1
112
+ xyzservices==2024.6.0
113
+ yarg==0.1.9
114
+ zipp==3.19.2
weights/best.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:23a3ca2bc5fb2555d94a6c9ae7c888b0c88232f3baebd5fb5edfdb9ec4f7dbf5
3
+ size 16527660