Kunitomi commited on
Commit
b5baf31
·
unverified ·
1 Parent(s): dab6900

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,4 +33,6 @@ 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
 
 
36
  *.png 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
+ examples/green_beans.png filter=lfs diff=lfs merge=lfs -text
37
+ examples/roasted_beans.png filter=lfs diff=lfs merge=lfs -text
38
  *.png filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,12 +1,64 @@
1
  ---
2
  title: Coffee Bean Detection
3
- emoji: 😻
4
- colorFrom: pink
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.47.0
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Coffee Bean Detection
3
+ emoji:
4
+ colorFrom: red
5
+ colorTo: yellow
6
  sdk: gradio
7
+ sdk_version: 4.44.0
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
  ---
12
 
13
+ # Coffee Bean Detection with Mask R-CNN
14
+
15
+ An interactive demo for detecting and segmenting coffee beans using a fine-tuned Mask R-CNN model.
16
+
17
+ ## Features
18
+
19
+ 🎯 **High Accuracy Detection**
20
+ - Precision: 99.92%
21
+ - Recall: 96.71%
22
+ - Average IoU: 90.93%
23
+
24
+ 🔧 **Adjustable Parameters**
25
+ - Confidence threshold for detection sensitivity
26
+ - NMS threshold for overlap handling
27
+ - Maximum detection limits
28
+
29
+ 📊 **Detailed Results**
30
+ - Individual bean segmentation masks
31
+ - Confidence scores for each detection
32
+ - Summary statistics
33
+
34
+ ## How to Use
35
+
36
+ 1. **Upload an Image**: Drop or select an image of coffee beans
37
+ 2. **Adjust Settings** (optional): Fine-tune detection parameters
38
+ 3. **View Results**: See detected beans with masks and confidence scores
39
+
40
+ ## Model Details
41
+
42
+ - **Architecture**: Mask R-CNN with ResNet-50 FPN backbone
43
+ - **Framework**: PyTorch/TorchVision
44
+ - **Training**: Fine-tuned on 128 coffee bean images
45
+ - **Hardware**: Trained on Mac Mini M2 (CPU only)
46
+ - **Model Size**: 176MB in SafeTensors format
47
+
48
+ ## Applications
49
+
50
+ - Coffee bean quality control
51
+ - Automated inventory counting
52
+ - Bean size and shape analysis
53
+ - Agricultural research
54
+ - Educational demonstrations
55
+
56
+ ## Links
57
+
58
+ - 🤗 [Model Repository](https://huggingface.co/Kunitomi/coffee-bean-maskrcnn)
59
+ - 💻 [Source Code](https://github.com/Markkunitomi/bean-vision)
60
+ - 📖 [Documentation](https://github.com/Markkunitomi/bean-vision/blob/main/README.md)
61
+
62
+ ---
63
+
64
+ Built by [Mark Kunitomi](https://huggingface.co/Kunitomi)
app.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import torchvision
4
+ from torchvision.models.detection import maskrcnn_resnet50_fpn
5
+ from torchvision.transforms import functional as F
6
+ import torchvision.ops as ops
7
+ import numpy as np
8
+ from PIL import Image, ImageDraw
9
+ import matplotlib.pyplot as plt
10
+ import matplotlib.patches as patches
11
+ from matplotlib import cm
12
+ import io
13
+ import requests
14
+ from huggingface_hub import hf_hub_download
15
+
16
+ # Download model from Hugging Face Hub
17
+ @torch.no_grad()
18
+ def load_model():
19
+ model_path = hf_hub_download(
20
+ repo_id="Kunitomi/coffee-bean-maskrcnn",
21
+ filename="maskrcnn_coffeebeans_v1.safetensors"
22
+ )
23
+
24
+ model = maskrcnn_resnet50_fpn(num_classes=2) # background + bean
25
+
26
+ from safetensors.torch import load_file
27
+ state_dict = load_file(model_path)
28
+ model.load_state_dict(state_dict)
29
+ model.eval()
30
+
31
+ return model
32
+
33
+ # Load model once at startup
34
+ model = load_model()
35
+
36
+ def predict_beans(image, confidence_threshold, nms_threshold, max_detections):
37
+ """Run inference on uploaded image."""
38
+ if image is None:
39
+ return None, "Please upload an image first."
40
+
41
+ # Convert to PIL if needed
42
+ if not isinstance(image, Image.Image):
43
+ image = Image.fromarray(image)
44
+
45
+ # Convert to RGB
46
+ image = image.convert('RGB')
47
+
48
+ # Preprocess image
49
+ image_tensor = F.to_tensor(image).unsqueeze(0)
50
+
51
+ # Run inference
52
+ with torch.no_grad():
53
+ predictions = model(image_tensor)[0]
54
+
55
+ # Apply NMS
56
+ keep = ops.nms(predictions['boxes'], predictions['scores'], nms_threshold)
57
+ predictions = {k: v[keep] for k, v in predictions.items()}
58
+
59
+ # Filter by confidence threshold
60
+ mask = predictions['scores'] > confidence_threshold
61
+ filtered_predictions = {
62
+ 'boxes': predictions['boxes'][mask],
63
+ 'labels': predictions['labels'][mask],
64
+ 'scores': predictions['scores'][mask],
65
+ 'masks': predictions['masks'][mask]
66
+ }
67
+
68
+ # Limit number of detections
69
+ if len(filtered_predictions['boxes']) > max_detections:
70
+ # Keep top detections by confidence
71
+ top_indices = torch.topk(filtered_predictions['scores'], max_detections)[1]
72
+ filtered_predictions = {k: v[top_indices] for k, v in filtered_predictions.items()}
73
+
74
+ bean_count = len(filtered_predictions['boxes'])
75
+
76
+ # Create visualization
77
+ fig, ax = plt.subplots(1, 1, figsize=(12, 8))
78
+ ax.imshow(image)
79
+ ax.axis('off')
80
+
81
+ # Colors for visualization
82
+ colors = cm.get_cmap('tab20')
83
+
84
+ # Draw detections
85
+ for i in range(bean_count):
86
+ color = colors(i % 20)
87
+
88
+ # Draw mask
89
+ mask = filtered_predictions['masks'][i][0].cpu().numpy()
90
+ masked = np.ma.masked_where(mask < 0.5, mask)
91
+ ax.imshow(masked, alpha=0.4, cmap=plt.cm.colors.ListedColormap([color]))
92
+
93
+ # Draw bounding box
94
+ box = filtered_predictions['boxes'][i].cpu().numpy()
95
+ x1, y1, x2, y2 = box
96
+ rect = patches.Rectangle(
97
+ (x1, y1), x2 - x1, y2 - y1,
98
+ linewidth=2, edgecolor=color, facecolor='none'
99
+ )
100
+ ax.add_patch(rect)
101
+
102
+ # Add confidence score
103
+ score = filtered_predictions['scores'][i].cpu().item()
104
+ ax.text(
105
+ x1, y1 - 5, f'{score:.2f}',
106
+ color='white', fontsize=10, weight='bold',
107
+ bbox=dict(boxstyle='round,pad=0.3', facecolor=color, alpha=0.8)
108
+ )
109
+
110
+ ax.set_title(f'Detected {bean_count} Coffee Beans', fontsize=16, fontweight='bold')
111
+
112
+ plt.tight_layout()
113
+
114
+ # Convert plot to image
115
+ buf = io.BytesIO()
116
+ plt.savefig(buf, format='png', dpi=150, bbox_inches='tight')
117
+ buf.seek(0)
118
+ result_image = Image.open(buf)
119
+ plt.close()
120
+
121
+ # Create summary text
122
+ if bean_count > 0:
123
+ avg_confidence = filtered_predictions['scores'].mean().item()
124
+ min_confidence = filtered_predictions['scores'].min().item()
125
+ max_confidence = filtered_predictions['scores'].max().item()
126
+
127
+ summary = f"""
128
+ ## Detection Results 📊
129
+ - **Beans Detected**: {bean_count}
130
+ - **Average Confidence**: {avg_confidence:.3f}
131
+ - **Confidence Range**: {min_confidence:.3f} - {max_confidence:.3f}
132
+ - **Settings Used**:
133
+ - Confidence Threshold: {confidence_threshold}
134
+ - NMS Threshold: {nms_threshold}
135
+ - Max Detections: {max_detections}
136
+ """
137
+ else:
138
+ summary = f"""
139
+ ## Detection Results 📊
140
+ - **Beans Detected**: 0
141
+ - **Try adjusting**: Lower the confidence threshold or check image quality
142
+ - **Settings Used**:
143
+ - Confidence Threshold: {confidence_threshold}
144
+ - NMS Threshold: {nms_threshold}
145
+ """
146
+
147
+ return result_image, summary
148
+
149
+ # Example images
150
+ examples = [
151
+ ["examples/green_beans.png", 0.5, 0.5, 100],
152
+ ["examples/roasted_beans.png", 0.5, 0.3, 100],
153
+ ]
154
+
155
+ # Create Gradio interface
156
+ with gr.Blocks(title="Coffee Bean Detection", theme=gr.themes.Soft()) as demo:
157
+ gr.Markdown("""
158
+ # ☕ Coffee Bean Detection with Mask R-CNN
159
+
160
+ Upload an image of coffee beans to detect and segment individual beans using a fine-tuned Mask R-CNN model.
161
+
162
+ **Model Performance:**
163
+ - 🎯 **Precision**: 99.92%
164
+ - 🔍 **Recall**: 96.71%
165
+ - 📐 **Average IoU**: 90.93%
166
+ - ⚡ **Trained on**: Mac Mini M2 (CPU)
167
+ """)
168
+
169
+ with gr.Row():
170
+ with gr.Column(scale=1):
171
+ # Input controls
172
+ input_image = gr.Image(
173
+ type="pil",
174
+ label="Upload Coffee Bean Image",
175
+ height=400
176
+ )
177
+
178
+ with gr.Accordion("Advanced Settings", open=False):
179
+ confidence_threshold = gr.Slider(
180
+ minimum=0.1,
181
+ maximum=0.9,
182
+ value=0.5,
183
+ step=0.05,
184
+ label="Confidence Threshold",
185
+ info="Higher values = fewer but more confident detections"
186
+ )
187
+
188
+ nms_threshold = gr.Slider(
189
+ minimum=0.1,
190
+ maximum=0.8,
191
+ value=0.5,
192
+ step=0.05,
193
+ label="NMS Threshold",
194
+ info="Lower values = less overlap between detections"
195
+ )
196
+
197
+ max_detections = gr.Slider(
198
+ minimum=10,
199
+ maximum=200,
200
+ value=100,
201
+ step=10,
202
+ label="Maximum Detections",
203
+ info="Limit total number of detections shown"
204
+ )
205
+
206
+ detect_btn = gr.Button("🔍 Detect Beans", variant="primary", size="lg")
207
+
208
+ with gr.Column(scale=1):
209
+ # Output
210
+ output_image = gr.Image(label="Detection Results", height=400)
211
+ results_text = gr.Markdown()
212
+
213
+ # Event handlers
214
+ detect_btn.click(
215
+ fn=predict_beans,
216
+ inputs=[input_image, confidence_threshold, nms_threshold, max_detections],
217
+ outputs=[output_image, results_text]
218
+ )
219
+
220
+ # Auto-detect when image is uploaded
221
+ input_image.change(
222
+ fn=predict_beans,
223
+ inputs=[input_image, confidence_threshold, nms_threshold, max_detections],
224
+ outputs=[output_image, results_text]
225
+ )
226
+
227
+ # Examples section
228
+ gr.Markdown("## 📸 Try These Examples")
229
+ gr.Examples(
230
+ examples=examples,
231
+ inputs=[input_image, confidence_threshold, nms_threshold, max_detections],
232
+ outputs=[output_image, results_text],
233
+ fn=predict_beans,
234
+ cache_examples=True
235
+ )
236
+
237
+ # Footer
238
+ gr.Markdown("""
239
+ ---
240
+ **Model Details:**
241
+ - Architecture: Mask R-CNN with ResNet-50 FPN backbone
242
+ - Framework: PyTorch/TorchVision
243
+ - Fine-tuned on 128 coffee bean images
244
+ - Model size: 176MB (SafeTensors format)
245
+
246
+ **Links:**
247
+ - 🤗 [Model on Hugging Face](https://huggingface.co/Kunitomi/coffee-bean-maskrcnn)
248
+ - 💻 [Code Repository](https://github.com/Markkunitomi/bean-vision)
249
+
250
+ Built by [Mark Kunitomi](https://huggingface.co/Kunitomi)
251
+ """)
252
+
253
+ if __name__ == "__main__":
254
+ demo.launch()
examples/green_beans.png ADDED

Git LFS Details

  • SHA256: e3a5142de33d011debf2828a49c614eb8c14fedce53fc4483ea25a2383a58369
  • Pointer size: 132 Bytes
  • Size of remote file: 7.95 MB
examples/roasted_beans.png ADDED

Git LFS Details

  • SHA256: 58bfc58ec9bfee8b350d99cf3fee7bf4ee2fc394707fa4a5c228119ca03b65b1
  • Pointer size: 132 Bytes
  • Size of remote file: 8.94 MB
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ torch>=2.0.0
3
+ torchvision>=0.15.0
4
+ pillow>=9.0.0
5
+ numpy>=1.21.0
6
+ matplotlib>=3.5.0
7
+ safetensors>=0.3.0
8
+ huggingface-hub>=0.16.0