GGORG revised this gist . Go to revision
4 files changed, 5 insertions, 5 deletions
index.html
@@ -2,7 +2,7 @@ | |||
2 | 2 | <html lang="en"> | |
3 | 3 | <head> | |
4 | 4 | <meta charset="UTF-8"> | |
5 | - | <meta name="viewport" c initial-scale=1.0"> | |
5 | + | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
6 | 6 | <title>Image Classifier</title> | |
7 | 7 | <style> | |
8 | 8 | #preview { | |
@@ -14,7 +14,7 @@ | |||
14 | 14 | </head> | |
15 | 15 | <body> | |
16 | 16 | <h1>Wczytaj obraz do klasyfikacji</h1> | |
17 | - | <form acti method="POST" enctype="multipart/form-data"> | |
17 | + | <form active method="POST" enctype="multipart/form-data"> | |
18 | 18 | <input type="file" name="image" id="imageInput" accept="image/*" required> | |
19 | 19 | <br> | |
20 | 20 | <img id="preview" src="#" alt="Image Preview" style="display: none;"> |
poziom1.py
@@ -9,7 +9,7 @@ import timm | |||
9 | 9 | # ta wersja jest wyuczona na zbiorze ImageNet-21k | |
10 | 10 | nazwa_modelu = "swin_large_patch4_window7_224" | |
11 | 11 | klasyfikator = timm.create_model(nazwa_modelu, pretrained=True) | |
12 | - | # klasyfikator.eval() | |
12 | + | # klasyfikator.eval() | |
13 | 13 | ||
14 | 14 | # Pobierz zbiór ImageNet (1000 klas) | |
15 | 15 | import json |
poziom2_flask.py
@@ -18,7 +18,7 @@ os.makedirs(UPLOAD_FOLDER, exist_ok=True) | |||
18 | 18 | # ta wersja jest wyuczona na zbiorze ImageNet-21k | |
19 | 19 | nazwa_modelu = "swin_large_patch4_window7_224" | |
20 | 20 | klasyfikator = timm.create_model(nazwa_modelu, pretrained=True) | |
21 | - | #klasyfikator.eval() | |
21 | + | #klasyfikator.eval() | |
22 | 22 | ||
23 | 23 | # Pobierz zbiór ImageNet (1000 klas) | |
24 | 24 | imagenet_labels_url = "https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json" |
result.html
@@ -2,7 +2,7 @@ | |||
2 | 2 | <html lang="en"> | |
3 | 3 | <head> | |
4 | 4 | <meta charset="UTF-8"> | |
5 | - | <meta name="viewport" c initial-scale=1.0"> | |
5 | + | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
6 | 6 | <title>Wyniki klasyfikacji</title> | |
7 | 7 | </head> | |
8 | 8 | <body> |
GGORG revised this gist . Go to revision
1 file changed, 1 insertion, 1 deletion
index.html
@@ -17,7 +17,7 @@ | |||
17 | 17 | <form acti method="POST" enctype="multipart/form-data"> | |
18 | 18 | <input type="file" name="image" id="imageInput" accept="image/*" required> | |
19 | 19 | <br> | |
20 | - | <img id="preview" src="#" alt="Image Preview" none;"> | |
20 | + | <img id="preview" src="#" alt="Image Preview" style="display: none;"> | |
21 | 21 | <br> | |
22 | 22 | <button type="submit">Klasyfikuj</button> | |
23 | 23 | </form> |
GGORG revised this gist . Go to revision
1 file changed, 1 insertion, 1 deletion
result.html
@@ -7,7 +7,7 @@ | |||
7 | 7 | </head> | |
8 | 8 | <body> | |
9 | 9 | <h1>Wyniki klasyfikacji</h1> | |
10 | - | <img src="{{ image_path }}" alt="Uploaded Image" 500px; max-height: 500px;"> | |
10 | + | <img src="{{ image_path }}" alt="Uploaded Image" style="max-width: 500px; max-height: 500px;"> | |
11 | 11 | <h2>5 najlepszych trafień:</h2> | |
12 | 12 | <ol> | |
13 | 13 | {% for label, confidence in predictions %} |
GGORG revised this gist . Go to revision
3 files changed, 65 insertions, 1 deletion
index.html(file created)
@@ -0,0 +1,45 @@ | |||
1 | + | <!DOCTYPE html> | |
2 | + | <html lang="en"> | |
3 | + | <head> | |
4 | + | <meta charset="UTF-8"> | |
5 | + | <meta name="viewport" c initial-scale=1.0"> | |
6 | + | <title>Image Classifier</title> | |
7 | + | <style> | |
8 | + | #preview { | |
9 | + | max-width: 500px; | |
10 | + | max-height: 500px; | |
11 | + | margin-top: 20px; | |
12 | + | } | |
13 | + | </style> | |
14 | + | </head> | |
15 | + | <body> | |
16 | + | <h1>Wczytaj obraz do klasyfikacji</h1> | |
17 | + | <form acti method="POST" enctype="multipart/form-data"> | |
18 | + | <input type="file" name="image" id="imageInput" accept="image/*" required> | |
19 | + | <br> | |
20 | + | <img id="preview" src="#" alt="Image Preview" none;"> | |
21 | + | <br> | |
22 | + | <button type="submit">Klasyfikuj</button> | |
23 | + | </form> | |
24 | + | ||
25 | + | <script> | |
26 | + | const imageInput = document.getElementById('imageInput'); | |
27 | + | const preview = document.getElementById('preview'); | |
28 | + | ||
29 | + | imageInput.addEventListener('change', function(event) { | |
30 | + | const file = event.target.files[0]; | |
31 | + | if (file) { | |
32 | + | const reader = new FileReader(); | |
33 | + | reader.onload = function(e) { | |
34 | + | preview.src = e.target.result; | |
35 | + | preview.style.display = 'block'; | |
36 | + | }; | |
37 | + | reader.readAsDataURL(file); | |
38 | + | } else { | |
39 | + | preview.style.display = 'none'; | |
40 | + | } | |
41 | + | }); | |
42 | + | </script> | |
43 | + | </body> | |
44 | + | </html> | |
45 | + |
poziom2_flask.py
@@ -53,7 +53,7 @@ def recognize_image(img_path): | |||
53 | 53 | def index(): | |
54 | 54 | return render_template("index.html") | |
55 | 55 | ||
56 | - | @app.route('/classify', methods=['POST']) | |
56 | + | @app.route('/', methods=['POST']) | |
57 | 57 | def classify_image(): | |
58 | 58 | if 'image' not in request.files: | |
59 | 59 | return redirect(url_for('index')) |
result.html(file created)
@@ -0,0 +1,19 @@ | |||
1 | + | <!DOCTYPE html> | |
2 | + | <html lang="en"> | |
3 | + | <head> | |
4 | + | <meta charset="UTF-8"> | |
5 | + | <meta name="viewport" c initial-scale=1.0"> | |
6 | + | <title>Wyniki klasyfikacji</title> | |
7 | + | </head> | |
8 | + | <body> | |
9 | + | <h1>Wyniki klasyfikacji</h1> | |
10 | + | <img src="{{ image_path }}" alt="Uploaded Image" 500px; max-height: 500px;"> | |
11 | + | <h2>5 najlepszych trafień:</h2> | |
12 | + | <ol> | |
13 | + | {% for label, confidence in predictions %} | |
14 | + | <li>{{ label }}: {{ confidence | round(2) }}</li> | |
15 | + | {% endfor %} | |
16 | + | </ol> | |
17 | + | <a href="/">Powtórz</a> | |
18 | + | </body> | |
19 | + | </html> |
GGORG revised this gist . Go to revision
2 files changed, 128 insertions
poziom1.py(file created)
@@ -0,0 +1,50 @@ | |||
1 | + | # Importowanie bibliotek | |
2 | + | # Torch - głębokie sieci neuronowe (ang. Deep Neural Networks) | |
3 | + | import torch | |
4 | + | from torchvision import transforms | |
5 | + | from PIL import Image | |
6 | + | import timm | |
7 | + | ||
8 | + | # Wczytaj model Swin Transformer z biblioteki timm | |
9 | + | # ta wersja jest wyuczona na zbiorze ImageNet-21k | |
10 | + | nazwa_modelu = "swin_large_patch4_window7_224" | |
11 | + | klasyfikator = timm.create_model(nazwa_modelu, pretrained=True) | |
12 | + | # klasyfikator.eval() | |
13 | + | ||
14 | + | # Pobierz zbiór ImageNet (1000 klas) | |
15 | + | import json | |
16 | + | imagenet_labels_url = "https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json" | |
17 | + | import requests | |
18 | + | labels = json.loads(requests.get(imagenet_labels_url).text) | |
19 | + | ||
20 | + | # Potok przetwarzania obrazu na potrzeby klasyfikatora | |
21 | + | preprocess = transforms.Compose([ | |
22 | + | transforms.Resize((224, 224)), # model Swin Transformer bierze na wejściu obrazy 224x224 | |
23 | + | transforms.ToTensor(), | |
24 | + | transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), # Normalizacja | |
25 | + | ]) | |
26 | + | ||
27 | + | ||
28 | + | def recognize_image(img_path): | |
29 | + | """Wczytuje obraz z pliku, przetwarza zgodnie z potokiem preprocess a na koniec klasyfikuje""" | |
30 | + | img = Image.open(img_path).convert("RGB") | |
31 | + | # Dodatkowy wymiar na wejściu | |
32 | + | img_tensor = preprocess(img).unsqueeze(0) | |
33 | + | ||
34 | + | # Predykcja, czyli przypisanie prawdopodobieństw klas do obrazu wejściowego | |
35 | + | with torch.no_grad(): | |
36 | + | logits = klasyfikator(img_tensor) | |
37 | + | probabilities = torch.nn.functional.softmax(logits, dim=-1) | |
38 | + | top5_prob, top5_catid = torch.topk(probabilities, 5) | |
39 | + | ||
40 | + | # Przeliczenie prawdopodobieństw na etykiety klas | |
41 | + | results = [(labels[catid], prob.item()) for catid, prob in zip(top5_catid[0], top5_prob[0])] | |
42 | + | return results | |
43 | + | ||
44 | + | ||
45 | + | if __name__ == "__main__": | |
46 | + | img_path = "obrazek.jpg" | |
47 | + | wyjscie_klasyfikatora = recognize_image(img_path) | |
48 | + | for i, (label, confidence) in enumerate(wyjscie_klasyfikatora): | |
49 | + | print(f"{i + 1}: {label} ({confidence:.2f})") | |
50 | + |
poziom2_flask.py(file created)
@@ -0,0 +1,78 @@ | |||
1 | + | from flask import Flask, request, render_template, redirect, url_for | |
2 | + | import torch | |
3 | + | from torchvision import transforms | |
4 | + | from PIL import Image | |
5 | + | import timm | |
6 | + | import json | |
7 | + | import requests | |
8 | + | import os | |
9 | + | ||
10 | + | app = Flask(__name__) | |
11 | + | UPLOAD_FOLDER = 'static/uploads' | |
12 | + | app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER | |
13 | + | ||
14 | + | # Folder na załadowane obrazki | |
15 | + | os.makedirs(UPLOAD_FOLDER, exist_ok=True) | |
16 | + | ||
17 | + | # Wczytaj model Swin Transformer z biblioteki timm | |
18 | + | # ta wersja jest wyuczona na zbiorze ImageNet-21k | |
19 | + | nazwa_modelu = "swin_large_patch4_window7_224" | |
20 | + | klasyfikator = timm.create_model(nazwa_modelu, pretrained=True) | |
21 | + | #klasyfikator.eval() | |
22 | + | ||
23 | + | # Pobierz zbiór ImageNet (1000 klas) | |
24 | + | imagenet_labels_url = "https://raw.githubusercontent.com/anishathalye/imagenet-simple-labels/master/imagenet-simple-labels.json" | |
25 | + | labels = json.loads(requests.get(imagenet_labels_url).text) | |
26 | + | ||
27 | + | # Potok przetwarzania obrazu na potrzeby klasyfikatora | |
28 | + | preprocess = transforms.Compose([ | |
29 | + | transforms.Resize((224, 224)), | |
30 | + | transforms.ToTensor(), | |
31 | + | transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), | |
32 | + | ]) | |
33 | + | ||
34 | + | def recognize_image(img_path): | |
35 | + | """ | |
36 | + | Wczytuje obraz z pliku, przetwarza zgodnie z potokiem preprocess a na koniec klasyfikuje | |
37 | + | """ | |
38 | + | img = Image.open(img_path).convert("RGB") | |
39 | + | # Dodatkowy wymiar na wejściu | |
40 | + | img_tensor = preprocess(img).unsqueeze(0) | |
41 | + | ||
42 | + | # Predykcja, czyli przypisanie prawdopodobieństw klas do obrazu wejściowego | |
43 | + | with torch.no_grad(): | |
44 | + | logits = klasyfikator(img_tensor) | |
45 | + | probabilities = torch.nn.functional.softmax(logits, dim=-1) | |
46 | + | top5_prob, top5_catid = torch.topk(probabilities, 5) | |
47 | + | ||
48 | + | # Przeliczenie prawdopodobieństw na etykiety klas | |
49 | + | results = [(labels[catid], prob.item()) for catid, prob in zip(top5_catid[0], top5_prob[0])] | |
50 | + | return results | |
51 | + | ||
52 | + | @app.route('/') | |
53 | + | def index(): | |
54 | + | return render_template("index.html") | |
55 | + | ||
56 | + | @app.route('/classify', methods=['POST']) | |
57 | + | def classify_image(): | |
58 | + | if 'image' not in request.files: | |
59 | + | return redirect(url_for('index')) | |
60 | + | ||
61 | + | image = request.files['image'] | |
62 | + | if image.filename == '': | |
63 | + | return redirect(url_for('index')) | |
64 | + | ||
65 | + | try: | |
66 | + | # Zapisz wczytany obraz do katalogu UPLOAD_FOLDER | |
67 | + | image_path = os.path.join(app.config['UPLOAD_FOLDER'], image.filename) | |
68 | + | image.save(image_path) | |
69 | + | ||
70 | + | # Klasyfikacja | |
71 | + | wyjscie_klasyfikatora = recognize_image(image_path) | |
72 | + | return render_template("result.html", image_path=image_path, predictions=wyjscie_klasyfikatora) | |
73 | + | except Exception as e: | |
74 | + | return str(e), 500 | |
75 | + | ||
76 | + | if __name__ == "__main__": | |
77 | + | app.run(debug=True) | |
78 | + |