mikoba commited on
Commit
95bc3ae
1 Parent(s): a44ce7b
Files changed (2) hide show
  1. app.py +110 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+ import cv2
4
+ from transformers import SamModel, SamProcessor
5
+ import gradio as gr
6
+
7
+ # Load the SAM model and processor from Hugging Face
8
+ model_id = "facebook/sam-vit-huge"
9
+ device = "cuda" if torch.cuda.is_available() else "cpu"
10
+
11
+ sam = SamModel.from_pretrained(model_id).to(device)
12
+ processor = SamProcessor.from_pretrained(model_id)
13
+
14
+ def segment_rocks(image):
15
+ # Preprocess the image
16
+ inputs = processor(image, return_tensors="pt").to(device)
17
+
18
+ # Generate image embeddings
19
+ with torch.no_grad():
20
+ image_embeddings = sam.get_image_embeddings(inputs["pixel_values"])
21
+
22
+ # Generate masks
23
+ masks = []
24
+ for i in range(3): # Generate multiple masks
25
+ inputs = processor(
26
+ image,
27
+ input_points=None,
28
+ return_tensors="pt",
29
+ input_boxes=[[[0, 0, image.shape[1], image.shape[0]]]],
30
+ ).to(device)
31
+
32
+ with torch.no_grad():
33
+ outputs = sam(
34
+ input_points=inputs["input_points"],
35
+ input_boxes=inputs["input_boxes"],
36
+ image_embeddings=image_embeddings,
37
+ multimask_output=True,
38
+ )
39
+
40
+ masks.extend(outputs.pred_masks.squeeze().cpu().numpy())
41
+
42
+ return masks
43
+
44
+ def compute_rock_properties(mask):
45
+ # Find contours of the mask
46
+ contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
47
+
48
+ properties = []
49
+ for contour in contours:
50
+ # Compute area
51
+ area = cv2.contourArea(contour)
52
+
53
+ # Compute perimeter
54
+ perimeter = cv2.arcLength(contour, True)
55
+
56
+ # Compute circularity
57
+ circularity = 4 * np.pi * area / (perimeter ** 2) if perimeter > 0 else 0
58
+
59
+ # Fit an ellipse to get major and minor axes
60
+ if len(contour) >= 5:
61
+ ellipse = cv2.fitEllipse(contour)
62
+ major_axis = max(ellipse[1])
63
+ minor_axis = min(ellipse[1])
64
+ aspect_ratio = major_axis / minor_axis if minor_axis > 0 else 0
65
+ else:
66
+ major_axis = minor_axis = aspect_ratio = 0
67
+
68
+ properties.append({
69
+ 'area': area,
70
+ 'perimeter': perimeter,
71
+ 'circularity': circularity,
72
+ 'major_axis': major_axis,
73
+ 'minor_axis': minor_axis,
74
+ 'aspect_ratio': aspect_ratio
75
+ })
76
+
77
+ return properties
78
+
79
+ def process_image(input_image):
80
+ # Convert to RGB if needed
81
+ if input_image.shape[2] == 4: # RGBA
82
+ input_image = cv2.cvtColor(input_image, cv2.COLOR_RGBA2RGB)
83
+ elif len(input_image.shape) == 2: # Grayscale
84
+ input_image = cv2.cvtColor(input_image, cv2.COLOR_GRAY2RGB)
85
+
86
+ masks = segment_rocks(input_image)
87
+
88
+ results = []
89
+ for i, mask in enumerate(masks):
90
+ properties = compute_rock_properties(mask)
91
+
92
+ # Visualize the segmentation
93
+ masked_image = input_image.copy()
94
+ masked_image[mask] = (masked_image[mask] * 0.7 + np.array([255, 0, 0]) * 0.3).astype(np.uint8)
95
+
96
+ results.append((masked_image, f"Rock {i+1} properties: {properties}"))
97
+
98
+ return results
99
+
100
+ # Gradio interface
101
+ iface = gr.Interface(
102
+ fn=process_image,
103
+ inputs=gr.Image(type="numpy"),
104
+ outputs=[gr.Image(type="numpy"), gr.Textbox(label="Properties")] * 3,
105
+ title="Rock Segmentation using SAM",
106
+ description="Upload an image to segment rocks and compute their properties."
107
+ )
108
+
109
+ # Launch the interface
110
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ transformers==4.30.0
2
+ torch==1.9.0
3
+ torchvision==0.10.0
4
+ opencv-python==4.5.3.56
5
+ numpy==1.21.0
6
+ gradio==3.35.2