Robert Boscacci commited on
Commit
ceaf1b9
·
1 Parent(s): 5904d42

Init repo.

Browse files
Files changed (6) hide show
  1. .gitattributes +3 -0
  2. .gitignore +4 -0
  3. README.md +4 -4
  4. app.py +141 -0
  5. export.pkl +3 -0
  6. requirements.txt +4 -0
.gitattributes CHANGED
@@ -33,3 +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
 
 
 
 
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
+ export.pkl filter=lfs diff=lfs merge=lfs -text
37
+ examples/forrest_1.png filter=lfs diff=lfs merge=lfs -text
38
+ examples/forrest_2.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ examples/forrest_1.png
2
+ examples/forrest_2.png
3
+ examples/forrest_1.png
4
+ examples/forrest_2.png
README.md CHANGED
@@ -1,13 +1,13 @@
1
  ---
2
- title: Film Slate Or Nah
3
  emoji: 👁
4
- colorFrom: blue
5
- colorTo: gray
6
  sdk: gradio
7
  sdk_version: 5.25.2
8
  app_file: app.py
9
  pinned: false
10
- short_description: Film slate, or nah?
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Film Slate Or No Film Slate
3
  emoji: 👁
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: gradio
7
  sdk_version: 5.25.2
8
  app_file: app.py
9
  pinned: false
10
+ short_description: Classifies images as having or not having a film slate
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastai.learner import load_learner
2
+ from fastai.vision.core import PILImage
3
+ from fastai.vision.all import DisplayedTransform
4
+ from pathlib import Path
5
+ import gradio as gr
6
+ import PIL
7
+ import sys
8
+ import os
9
+ import albumentations as A
10
+ import numpy as np
11
+
12
+ # Print debug information
13
+ print(f"Python version: {sys.version}")
14
+ print(f"PIL version: {PIL.__version__}")
15
+ print(f"fastai path: {Path(__file__).parent}")
16
+ print(f"Current working directory: {os.getcwd()}")
17
+
18
+ # Create a custom transform class that integrates Albumentations with fastai
19
+ class AlbumentationsTransform(DisplayedTransform):
20
+ split_idx, order = None, 2 # Apply to both train and validation sets
21
+
22
+ def __init__(self, train_aug, valid_aug=None):
23
+ self.train_aug = train_aug
24
+ self.valid_aug = valid_aug or A.Compose([
25
+ A.SmallestMaxSize(max_size=224),
26
+ A.CenterCrop(height=224, width=224)
27
+ ])
28
+
29
+ def before_call(self, b, split_idx):
30
+ self.split_idx = split_idx
31
+
32
+ def encodes(self, img: PILImage):
33
+ # Use validation augmentation for inference
34
+ aug = self.valid_aug
35
+ # Convert to numpy array and ensure it's uint8 before augmentation
36
+ img_array = np.array(img).astype(np.uint8)
37
+ aug_img = aug(image=img_array)['image']
38
+ # Convert back to PIL Image
39
+ return PILImage.create(aug_img)
40
+
41
+ # Define the albumentations transforms
42
+ def get_train_transform():
43
+ return A.Compose([
44
+ A.SmallestMaxSize(max_size=256),
45
+ A.RandomCrop(height=224, width=224),
46
+ A.HorizontalFlip(p=0.5),
47
+ A.RandomBrightnessContrast(p=0.3),
48
+ ])
49
+
50
+ def get_valid_transform():
51
+ return A.Compose([
52
+ A.SmallestMaxSize(max_size=256),
53
+ A.CenterCrop(height=224, width=224),
54
+ ])
55
+
56
+ try:
57
+ learn = load_learner('export.pkl')
58
+ print(f"Model loaded successfully: {type(learn)}")
59
+
60
+ # Define friendly label names
61
+ label_mapping = {
62
+ 'positive': "Slate!",
63
+ 'negative': "No Slate!"
64
+ }
65
+
66
+ # Get original labels
67
+ original_labels = learn.dls.vocab
68
+ print(f"Original labels: {original_labels}")
69
+
70
+ def predict(img):
71
+ # Convert to PILImage and apply transforms
72
+ img_pil = PILImage.create(img)
73
+ # Create transform with both train and valid transforms (will use valid for inference)
74
+ transform = AlbumentationsTransform(get_train_transform(), get_valid_transform())
75
+ transformed_img = transform.encodes(img_pil)
76
+
77
+ # Get prediction
78
+ pred, pred_idx, probs = learn.predict(transformed_img)
79
+
80
+ # Map the original labels to friendly names
81
+ return {label_mapping[original_labels[i]]: float(probs[i]) for i in range(len(original_labels))}
82
+
83
+ # Create a more attractive interface with custom styling
84
+ with gr.Blocks(css="footer {visibility: hidden}") as demo:
85
+ gr.Markdown("# 🎬 Image Classifier: Slate or No Slate?")
86
+ gr.Markdown("Upload an image and let AI tell you whether or not it contains a film slate!")
87
+
88
+ with gr.Row():
89
+ with gr.Column(scale=1):
90
+ # Remove webcam by setting sources to only 'upload' and 'clipboard'
91
+ input_image = gr.Image(
92
+ type="pil",
93
+ label="Upload Image",
94
+ sources=["upload", "clipboard"]
95
+ )
96
+ submit_btn = gr.Button("Classify", variant="primary")
97
+
98
+ with gr.Column(scale=1):
99
+ output = gr.Label(num_top_classes=3, label="Predictions")
100
+
101
+ with gr.Accordion("About", open=False):
102
+ gr.Markdown("""
103
+ ## How it works
104
+ This app uses a deep learning model trained with fastai to classify images.
105
+
106
+ ## Tips for best results
107
+ - Use clear, well-lit images
108
+ - Center the subject in the frame
109
+ - Supported categories: """ + ", ".join([label_mapping[label] for label in original_labels]))
110
+
111
+ # Set up the prediction flow
112
+ submit_btn.click(
113
+ fn=predict,
114
+ inputs=input_image,
115
+ outputs=output
116
+ )
117
+
118
+ # Allow image input to trigger prediction as well
119
+ input_image.change(
120
+ fn=predict,
121
+ inputs=input_image,
122
+ outputs=output
123
+ )
124
+
125
+ # Add examples if you have them
126
+ gr.Examples(
127
+ examples=[
128
+ "examples/forrest_1.png",
129
+ "examples/forrest_2.png"
130
+ ],
131
+ inputs=input_image
132
+ )
133
+
134
+ allowed_paths = ["examples/forrest_1.png", "examples/forrest_2.png"]
135
+
136
+ # Launch the app, allow access to the examples directory for @Gradio
137
+ demo.launch(allowed_paths=allowed_paths) # ssr_mode=False
138
+ except Exception as e:
139
+ print(f"Error occurred: {e}")
140
+ import traceback
141
+ traceback.print_exc()
export.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9728965243f2f98129d46b636456c34aec3a946fe84b410731f702cdf10a8f3a
3
+ size 114674957
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ albumentations==2.0.5
2
+ fastai==2.7.18
3
+ gradio==5.25.2
4
+ timm==1.0.15