Harsh-7300 commited on
Commit
bf7dc7e
·
verified ·
1 Parent(s): 5ff134f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -85
app.py CHANGED
@@ -1,91 +1,98 @@
1
  import cv2
2
  import numpy as np
3
- import matplotlib.pyplot as plt
4
- import streamlit as st
5
- from skimage import measure
6
- from io import BytesIO
7
 
8
- # Define the scale factor: 1 pixel = X meters (for example, 1 pixel = 0.5 meter)
9
- SCALE_FACTOR = 0.5 # In meters, adjust as per your image's scale
10
-
11
- def preprocess_image(image):
12
- img = cv2.imdecode(np.frombuffer(image.read(), np.uint8), cv2.IMREAD_COLOR)
13
-
14
- if img is None:
15
- st.error("Error: Unable to load image")
16
- return None, None
17
-
18
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
19
- blurred = cv2.GaussianBlur(gray, (5, 5), 0)
 
 
 
 
 
20
 
21
- return img, blurred
22
-
23
- def detect_edges(blurred_image):
24
- edges = cv2.Canny(blurred_image, 50, 150)
25
- return edges
26
-
27
- def find_contours(edges_image):
28
- contours, _ = cv2.findContours(edges_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
29
- return contours
30
-
31
- def filter_contours(contours, min_area=1000):
32
- filtered_contours = [contour for contour in contours if cv2.contourArea(contour) > min_area]
33
- return filtered_contours
34
-
35
- def draw_contours(image, contours):
36
- output_image = image.copy()
37
- cv2.drawContours(output_image, contours, -1, (0, 255, 0), 3)
38
- return output_image
39
-
40
- def calculate_area_in_meters(contours):
41
- total_area_pixels = sum(cv2.contourArea(contour) for contour in contours)
42
-
43
- # Convert pixel area to real-world area (in square meters)
44
- total_area_meters = total_area_pixels * (SCALE_FACTOR ** 2)
45
- return total_area_meters
46
-
47
- def remove_shadows(image):
48
- hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
49
- lower_shadow = np.array([0, 0, 0])
50
- upper_shadow = np.array([180, 255, 80])
51
- shadow_mask = cv2.inRange(hsv, lower_shadow, upper_shadow)
52
- result = cv2.inpaint(image, shadow_mask, 3, cv2.INPAINT_TELEA)
53
- return result
54
 
55
- def main():
56
- st.title("Rooftop Area Calculation from Satellite Image")
57
-
58
- # Allow the user to upload a file
59
- uploaded_file = st.file_uploader("Upload a rooftop image", type=["jpg", "png"])
60
-
61
- if uploaded_file is not None:
62
- # Step 1: Preprocess image
63
- img, blurred = preprocess_image(uploaded_file)
64
-
65
- if img is None:
66
- return
67
-
68
- # Step 2: Detect edges
69
- edges = detect_edges(blurred)
70
-
71
- # Step 3: Find contours
72
- contours = find_contours(edges)
73
-
74
- # Step 4: Filter contours to exclude unwanted areas
75
- filtered_contours = filter_contours(contours)
76
-
77
- # Step 5: Remove shadows from the image
78
- image_no_shadows = remove_shadows(img)
79
-
80
- # Step 6: Draw the predicted rooftop boundaries
81
- output_img = draw_contours(image_no_shadows, filtered_contours)
82
-
83
- # Step 7: Calculate the actual area of the rooftop (in square meters)
84
- total_area = calculate_area_in_meters(filtered_contours)
85
-
86
- # Step 8: Display the result
87
- st.image(output_img, channels="BGR", caption="Detected Rooftop with Boundaries")
88
- st.write(f"Total Rooftop Area: {total_area:.2f} square meters")
89
 
90
- if __name__ == "__main__":
91
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import cv2
2
  import numpy as np
 
 
 
 
3
 
4
+ def process_rooftop_image(image_path, geographic_bounds):
5
+ """
6
+ Process the rooftop image to detect rooftops, exclude shadows, and calculate real-world area.
7
+
8
+ Parameters:
9
+ image_path (str): Path to the input image (PNG or JPG).
10
+ geographic_bounds (dict): Geographic bounds with the following keys:
11
+ - lat_min, lat_max, lon_min, lon_max (floats): Latitude and longitude bounds of the image.
12
+
13
+ Returns:
14
+ final_image (numpy array): Image with predicted boundaries and excluded shadows.
15
+ real_world_area (float): Computed rooftop area in square meters.
16
+ """
17
+ # Load the image
18
+ image = cv2.imread(image_path)
19
+ if image is None:
20
+ raise FileNotFoundError("Image file not found. Please check the path.")
21
 
22
+ # Step 1: Convert to grayscale for processing
23
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ # Step 2: Apply Gaussian Blur to reduce noise
26
+ blurred = cv2.GaussianBlur(gray, (5, 5), 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ # Step 3: Edge detection (Canny)
29
+ edges = cv2.Canny(blurred, 50, 150)
30
+
31
+ # Step 4: Morphological operations to close gaps in edges
32
+ kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
33
+ closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
34
+
35
+ # Step 5: Find contours of the rooftop
36
+ contours, _ = cv2.findContours(closed_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
37
+
38
+ # Create a blank mask for shadow removal
39
+ mask = np.zeros_like(gray)
40
+
41
+ for contour in contours:
42
+ # Approximate the contour and filter out unwanted small areas
43
+ approx = cv2.approxPolyDP(contour, 0.02 * cv2.arcLength(contour, True), True)
44
+ area = cv2.contourArea(approx)
45
+ if area > 500: # Minimum area threshold to remove noise
46
+ cv2.drawContours(mask, [approx], -1, 255, -1)
47
+
48
+ # Step 6: Exclude shadows (thresholding)
49
+ shadow_removed = cv2.bitwise_and(gray, gray, mask=mask)
50
+ _, thresholded = cv2.threshold(shadow_removed, 120, 255, cv2.THRESH_BINARY)
51
+
52
+ # Step 7: Calculate the area in pixels
53
+ pixel_area = np.sum(thresholded > 0)
54
+
55
+ # Step 8: Convert pixels to real-world area
56
+ lat_min, lat_max, lon_min, lon_max = (
57
+ geographic_bounds['lat_min'],
58
+ geographic_bounds['lat_max'],
59
+ geographic_bounds['lon_min'],
60
+ geographic_bounds['lon_max'],
61
+ )
62
+ lat_diff = abs(lat_max - lat_min)
63
+ lon_diff = abs(lon_max - lon_min)
64
+
65
+ # Assuming Earth radius = 6371 km
66
+ earth_radius = 6371000 # in meters
67
+ lat_conversion = (lat_diff * np.pi / 180) * earth_radius
68
+ lon_conversion = (lon_diff * np.pi / 180) * earth_radius * np.cos(lat_min * np.pi / 180)
69
+
70
+ # Conversion factor: real-world area per pixel
71
+ conversion_factor = (lat_conversion * lon_conversion) / (image.shape[0] * image.shape[1])
72
+ real_world_area = pixel_area * conversion_factor # in square meters
73
+
74
+ # Step 9: Overlay contours on the original image
75
+ final_image = image.copy()
76
+ cv2.drawContours(final_image, contours, -1, (0, 255, 0), 2)
77
+
78
+ return final_image, real_world_area
79
+
80
+ # Example Usage
81
+ geographic_bounds = {
82
+ 'lat_min': 12.9716,
83
+ 'lat_max': 12.9756,
84
+ 'lon_min': 77.5946,
85
+ 'lon_max': 77.5986,
86
+ }
87
+ input_image_path = "rooftop_image.jpg"
88
+
89
+ final_image, calculated_area = process_rooftop_image(input_image_path, geographic_bounds)
90
+ print(f"Calculated Rooftop Area: {calculated_area:.2f} square meters")
91
+
92
+ # Save the final image with contours
93
+ cv2.imwrite("processed_image_with_boundaries.jpg", final_image)
94
+
95
+ # Display the final image
96
+ cv2.imshow("Rooftop Detection", final_image)
97
+ cv2.waitKey(0)
98
+ cv2.destroyAllWindows()