regisLik commited on
Commit
c9595c6
·
1 Parent(s): 2504b4d
.gitignore ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110
+ .pdm.toml
111
+ .pdm-python
112
+ .pdm-build/
113
+
114
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115
+ __pypackages__/
116
+
117
+ # Celery stuff
118
+ celerybeat-schedule
119
+ celerybeat.pid
120
+
121
+ # SageMath parsed files
122
+ *.sage.py
123
+
124
+ # Environments
125
+ .env
126
+ .venv
127
+ env/
128
+ venv/
129
+ ENV/
130
+ env.bak/
131
+ venv.bak/
132
+
133
+ # Spyder project settings
134
+ .spyderproject
135
+ .spyproject
136
+
137
+ # Rope project settings
138
+ .ropeproject
139
+
140
+ # mkdocs documentation
141
+ /site
142
+
143
+ # mypy
144
+ .mypy_cache/
145
+ .dmypy.json
146
+ dmypy.json
147
+
148
+ # Pyre type checker
149
+ .pyre/
150
+
151
+ # pytype static type analyzer
152
+ .pytype/
153
+
154
+ # Cython debug symbols
155
+ cython_debug/
156
+
157
+ # PyCharm
158
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
159
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
160
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
161
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
162
+ #.idea/
163
+ #
164
+ /mdodels/models--keizer77--samyolo2
165
+ /models/*
166
+
167
+ #files
168
+ *.pth
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Étape 1 : Utiliser l'image officielle Python 3.12
2
+ FROM python:3.12-slim
3
+
4
+ # Étape 2 : Définir le répertoire de travail dans le conteneur
5
+ WORKDIR /app
6
+
7
+ # Étape 3 : Copier les fichiers nécessaires dans le conteneur
8
+ COPY . /app
9
+
10
+ # Étape 4 : Donner les permissions au fichier .sh
11
+ RUN chmod +x ./startup.sh
12
+
13
+ # Étape 5 : Installer les dépendances Python
14
+ RUN pip install --upgrade pip
15
+ RUN pip install -r requirements.txt
16
+
17
+ # Étape 6 : Exposer le port (par défaut pour Gunicorn)
18
+ EXPOSE 8000
19
+
20
+ # Étape 7 : Définir la commande d'entrée pour exécuter le script .sh
21
+ CMD ["./startup.sh"]
app.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory,url_for
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ app = Flask(
11
+ __name__,
12
+ template_folder='templates', # Chemin des fichiers HTML
13
+ static_folder='static' # Chemin des fichiers statiques
14
+ )
15
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
16
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
17
+
18
+ # Charger le modèle SAM
19
+ MODEL_TYPE = "vit_b"
20
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
21
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
22
+
23
+ print("Chargement du modèle SAM...")
24
+ try:
25
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
26
+ except TypeError:
27
+ with warnings.catch_warnings():
28
+ warnings.simplefilter("ignore", category=UserWarning)
29
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
30
+
31
+ # Initialiser et charger le modèle
32
+ sam = sam_model_registry[MODEL_TYPE]()
33
+ sam.load_state_dict(state_dict, strict=False)
34
+ sam.to(device=device)
35
+ predictor = SamPredictor(sam)
36
+ print("Modèle SAM chargé avec succès!")
37
+
38
+ # Générer une couleur unique pour chaque classe
39
+ # Fonction pour générer une couleur unique pour chaque classe
40
+ def get_color_for_class(class_name):
41
+ np.random.seed(hash(class_name) % (2**32))
42
+ return tuple(np.random.randint(0, 256, size=3).tolist())
43
+
44
+ # Convertir un masque en bounding box au format YOLOv5
45
+ def mask_to_yolo_bbox(mask):
46
+ y_indices, x_indices = np.where(mask > 0)
47
+ if len(x_indices) == 0 or len(y_indices) == 0:
48
+ return None
49
+ x_min, x_max = x_indices.min(), x_indices.max()
50
+ y_min, y_max = y_indices.min(), y_indices.max()
51
+ x_center = (x_min + x_max) / 2
52
+ y_center = (y_min + y_max) / 2
53
+ width = x_max - x_min
54
+ height = y_max - y_min
55
+ return x_center, y_center, width, height
56
+
57
+ @app.route('/', methods=['GET', 'POST'])
58
+ def index():
59
+ """Page principale pour télécharger et afficher les images."""
60
+ if request.method == 'POST':
61
+ files = request.files.getlist('images')
62
+ if not files:
63
+ return "Aucun fichier sélectionné", 400
64
+
65
+ filenames = []
66
+ for file in files:
67
+ filename = secure_filename(file.filename)
68
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
69
+ file.save(filepath)
70
+ filenames.append(filename)
71
+
72
+ return render_template('index.html', uploaded_images=filenames)
73
+
74
+ uploaded_images = os.listdir(app.config['UPLOAD_FOLDER'])
75
+ return render_template('index.html', uploaded_images=uploaded_images)
76
+
77
+ @app.route('/uploads/<filename>')
78
+ def uploaded_file(filename):
79
+ """Servir les fichiers uploadés."""
80
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
81
+
82
+ @app.route('/segment', methods=['POST'])
83
+ def segment():
84
+ """Endpoint pour effectuer la segmentation des images."""
85
+ try:
86
+ data = request.get_json()
87
+ print("Données reçues :", data)
88
+
89
+ if not isinstance(data, list):
90
+ return jsonify({'success': False, 'error': 'Format incorrect : liste attendue'}), 400
91
+
92
+ output = []
93
+
94
+ for item in data:
95
+ image_name = item.get('image_name')
96
+ points = item.get('points', [])
97
+
98
+ if not image_name or not points:
99
+ return jsonify({'success': False, 'error': f"Données manquantes pour l'image {image_name}"}), 400
100
+
101
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
102
+ if not os.path.exists(image_path):
103
+ return jsonify({'success': False, 'error': f"Image {image_name} non trouvée"}), 404
104
+
105
+ # Charger l'image
106
+ image = cv2.imread(image_path)
107
+ if image is None:
108
+ return jsonify({'success': False, 'error': f"Impossible de charger l'image {image_name}"}), 400
109
+
110
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
111
+ predictor.set_image(image_rgb)
112
+ annotated_image = image.copy()
113
+ yolo_annotations = []
114
+
115
+ for point in points:
116
+ x, y = point['x'], point['y']
117
+ class_name = point.get('class', 'Unknown')
118
+ color = get_color_for_class(class_name)
119
+
120
+ try:
121
+ masks, _, _ = predictor.predict(
122
+ point_coords=np.array([[x, y]]),
123
+ point_labels=np.array([1]),
124
+ multimask_output=False
125
+ )
126
+ mask = masks[0]
127
+ annotated_image[mask > 0] = color
128
+
129
+ # Convertir le masque en bounding box YOLOv5
130
+ bbox = mask_to_yolo_bbox(mask)
131
+ if bbox:
132
+ x_center, y_center, width, height = bbox
133
+ x_center /= image.shape[1]
134
+ y_center /= image.shape[0]
135
+ width /= image.shape[1]
136
+ height /= image.shape[0]
137
+ yolo_annotations.append(f"{class_name} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
138
+
139
+ except Exception as e:
140
+ print(f"Erreur de segmentation pour le point {point} : {e}")
141
+
142
+ # Sauvegarder les résultats
143
+ output_dir = os.path.join(app.config['UPLOAD_FOLDER'], os.path.splitext(image_name)[0])
144
+ os.makedirs(output_dir, exist_ok=True)
145
+ annotated_path = os.path.join(output_dir, f"annotated_{image_name}")
146
+ cv2.imwrite(annotated_path, annotated_image)
147
+
148
+ yolo_path = os.path.join(output_dir, f"{os.path.splitext(image_name)[0]}.txt")
149
+ with open(yolo_path, "w") as f:
150
+ f.write("\n".join(yolo_annotations))
151
+
152
+ new_image_path = os.path.join(output_dir, image_name)
153
+ if not os.path.exists(new_image_path):
154
+ os.rename(image_path, new_image_path)
155
+
156
+ output.append({
157
+ 'image_name': image_name,
158
+ 'annotated_image': url_for('static', filename=f"uploads/{os.path.splitext(image_name)[0]}/annotated_{image_name}"),
159
+ 'yolo_annotations': url_for('static', filename=f"uploads/{os.path.splitext(image_name)[0]}/{os.path.splitext(image_name)[0]}.txt")
160
+ })
161
+
162
+ return jsonify({'success': True, 'results': output})
163
+
164
+ except Exception as e:
165
+ print("Erreur dans /segment :", str(e))
166
+ return jsonify({'success': False, 'error': str(e)}), 500
167
+
168
+ if __name__ == '__main__':
169
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v1_app.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ # Initialisation de Flask
11
+ app = Flask(
12
+ __name__,
13
+ template_folder='templates', # Chemin des fichiers HTML
14
+ static_folder='static' # Chemin des fichiers statiques
15
+ )
16
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
17
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
18
+
19
+ # Charger le modèle SAM
20
+ MODEL_TYPE = "vit_b"
21
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
22
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
23
+
24
+ print("Chargement du modèle SAM...")
25
+ try:
26
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
27
+ except TypeError:
28
+ with warnings.catch_warnings():
29
+ warnings.simplefilter("ignore", category=UserWarning)
30
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
31
+
32
+ # Initialiser et charger le modèle
33
+ sam = sam_model_registry[MODEL_TYPE]()
34
+ sam.load_state_dict(state_dict, strict=False)
35
+ sam.to(device=device)
36
+ predictor = SamPredictor(sam)
37
+ print("Modèle SAM chargé avec succès!")
38
+
39
+
40
+ @app.route('/', methods=['GET', 'POST'])
41
+ def index():
42
+ if request.method == 'POST':
43
+ if 'image' not in request.files:
44
+ return "Aucun fichier sélectionné", 400
45
+ file = request.files['image']
46
+ if file.filename == '':
47
+ return "Nom de fichier vide", 400
48
+ filename = secure_filename(file.filename)
49
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
50
+ file.save(filepath)
51
+ # Passer le nom du fichier au template pour affichage
52
+ return render_template('index.html', uploaded_image=filename)
53
+ return render_template('index.html')
54
+
55
+
56
+ @app.route('/uploads/<filename>')
57
+ def uploaded_file(filename):
58
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
59
+
60
+
61
+ if __name__ == '__main__':
62
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v2_app.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ # Initialisation de Flask
11
+ app = Flask(
12
+ __name__,
13
+ template_folder='templates', # Chemin des fichiers HTML
14
+ static_folder='static' # Chemin des fichiers statiques
15
+ )
16
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
17
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
18
+
19
+ # Charger le modèle SAM
20
+ MODEL_TYPE = "vit_b"
21
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
22
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
23
+
24
+ print("Chargement du modèle SAM...")
25
+ try:
26
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
27
+ except TypeError:
28
+ with warnings.catch_warnings():
29
+ warnings.simplefilter("ignore", category=UserWarning)
30
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
31
+
32
+ # Initialiser et charger le modèle
33
+ sam = sam_model_registry[MODEL_TYPE]()
34
+ sam.load_state_dict(state_dict, strict=False)
35
+ sam.to(device=device)
36
+ predictor = SamPredictor(sam)
37
+ print("Modèle SAM chargé avec succès!")
38
+
39
+
40
+ @app.route('/', methods=['GET', 'POST'])
41
+ def index():
42
+ if request.method == 'POST':
43
+ if 'image' not in request.files:
44
+ return "Aucun fichier sélectionné", 400
45
+ file = request.files['image']
46
+ if file.filename == '':
47
+ return "Nom de fichier vide", 400
48
+ filename = secure_filename(file.filename)
49
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
50
+ file.save(filepath)
51
+ # Passer le nom du fichier au template pour affichage
52
+ return render_template('index.html', uploaded_image=filename)
53
+ return render_template('index.html')
54
+
55
+
56
+ @app.route('/uploads/<filename>')
57
+ def uploaded_file(filename):
58
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
59
+
60
+ @app.route('/segment', methods=['POST'])
61
+ def segment():
62
+ """Endpoint pour segmenter une image et sauvegarder les annotations."""
63
+ data = request.json
64
+ image_name = data.get('image_name')
65
+ points = data.get('points')
66
+
67
+ if not image_name or not points:
68
+ return jsonify({'success': False, 'error': 'Données manquantes'}), 400
69
+
70
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
71
+ if not os.path.exists(image_path):
72
+ return jsonify({'success': False, 'error': 'Image non trouvée'}), 404
73
+
74
+ # Charger l'image
75
+ image = cv2.imread(image_path)
76
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
77
+ predictor.set_image(image_rgb)
78
+
79
+ # Annoter l'image avec les masques et les classes
80
+ annotated_image = image.copy()
81
+ for point in points:
82
+ x, y = point['x'], point['y']
83
+ class_name = point['class']
84
+ input_points = np.array([[x, y]])
85
+ input_labels = np.array([1])
86
+ masks, _, _ = predictor.predict(
87
+ point_coords=input_points,
88
+ point_labels=input_labels,
89
+ multimask_output=False
90
+ )
91
+ mask = masks[0]
92
+ mask_image = (mask * 255).astype(np.uint8)
93
+
94
+ # Superposer le masque à l'image
95
+ color = (0, 255, 0) # Couleur verte pour les masques
96
+ annotated_image[mask > 0] = color
97
+
98
+ # Ajouter le texte de la classe
99
+ cv2.putText(annotated_image, class_name, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
100
+
101
+ # Sauvegarder l'image annotée
102
+ annotated_path = os.path.join(app.config['UPLOAD_FOLDER'], f"annotated_{image_name}")
103
+ cv2.imwrite(annotated_path, annotated_image)
104
+
105
+ return jsonify({'success': True, 'annotated_image': f"annotated_{image_name}"})
106
+
107
+
108
+
109
+
110
+ if __name__ == '__main__':
111
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v3_app.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ # Initialisation de Flask
11
+ app = Flask(
12
+ __name__,
13
+ template_folder='templates', # Chemin des fichiers HTML
14
+ static_folder='static' # Chemin des fichiers statiques
15
+ )
16
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
17
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
18
+
19
+ # Charger le modèle SAM
20
+ MODEL_TYPE = "vit_b"
21
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
22
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
23
+
24
+ print("Chargement du modèle SAM...")
25
+ try:
26
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
27
+ except TypeError:
28
+ with warnings.catch_warnings():
29
+ warnings.simplefilter("ignore", category=UserWarning)
30
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
31
+
32
+ # Initialiser et charger le modèle
33
+ sam = sam_model_registry[MODEL_TYPE]()
34
+ sam.load_state_dict(state_dict, strict=False)
35
+ sam.to(device=device)
36
+ predictor = SamPredictor(sam)
37
+ print("Modèle SAM chargé avec succès!")
38
+
39
+
40
+ @app.route('/', methods=['GET', 'POST'])
41
+ def index():
42
+ if request.method == 'POST':
43
+ if 'image' not in request.files:
44
+ return "Aucun fichier sélectionné", 400
45
+ file = request.files['image']
46
+ if file.filename == '':
47
+ return "Nom de fichier vide", 400
48
+ filename = secure_filename(file.filename)
49
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
50
+ file.save(filepath)
51
+ # Passer le nom du fichier au template pour affichage
52
+ return render_template('index.html', uploaded_image=filename)
53
+ return render_template('index.html')
54
+
55
+
56
+ @app.route('/uploads/<filename>')
57
+ def uploaded_file(filename):
58
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
59
+
60
+
61
+ @app.route('/segment', methods=['POST'])
62
+ def segment():
63
+ """Endpoint pour segmenter une image et sauvegarder les annotations."""
64
+ try:
65
+ data = request.get_json()
66
+ image_name = data.get('image_name')
67
+ points = data.get('points')
68
+
69
+ if not image_name or not points:
70
+ return jsonify({'success': False, 'error': 'Données manquantes'}), 400
71
+
72
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
73
+ if not os.path.exists(image_path):
74
+ return jsonify({'success': False, 'error': 'Image non trouvée'}), 404
75
+
76
+ # Charger l'image
77
+ image = cv2.imread(image_path)
78
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
79
+ predictor.set_image(image_rgb)
80
+
81
+ # Annoter l'image avec les masques et les classes
82
+ annotated_image = image.copy()
83
+ for point in points:
84
+ x, y = point['x'], point['y']
85
+ class_name = point.get('class', 'Unknown')
86
+ input_points = np.array([[x, y]])
87
+ input_labels = np.array([1])
88
+ masks, _, _ = predictor.predict(
89
+ point_coords=input_points,
90
+ point_labels=input_labels,
91
+ multimask_output=False
92
+ )
93
+ mask = masks[0]
94
+ mask_image = (mask * 255).astype(np.uint8)
95
+
96
+ # Superposer le masque à l'image
97
+ color = (0, 255, 0) # Couleur verte pour les masques
98
+ annotated_image[mask > 0] = color
99
+
100
+ # Ajouter le texte de la classe
101
+ cv2.putText(annotated_image, class_name, (int(x), int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
102
+
103
+ # Sauvegarder l'image annotée
104
+ annotated_path = os.path.join(app.config['UPLOAD_FOLDER'], f"annotated_{image_name}")
105
+ cv2.imwrite(annotated_path, annotated_image)
106
+
107
+ return jsonify({'success': True, 'annotated_image': f"annotated_{image_name}"})
108
+ except Exception as e:
109
+ return jsonify({'success': False, 'error': str(e)}), 500
110
+
111
+
112
+ if __name__ == '__main__':
113
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v4_app.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ # Initialisation de Flask
11
+ app = Flask(
12
+ __name__,
13
+ template_folder='templates', # Chemin des fichiers HTML
14
+ static_folder='static' # Chemin des fichiers statiques
15
+ )
16
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
17
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
18
+
19
+ # Charger le modèle SAM
20
+ MODEL_TYPE = "vit_b"
21
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
22
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
23
+
24
+ print("Chargement du modèle SAM...")
25
+ try:
26
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
27
+ except TypeError:
28
+ with warnings.catch_warnings():
29
+ warnings.simplefilter("ignore", category=UserWarning)
30
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
31
+
32
+ # Initialiser et charger le modèle
33
+ sam = sam_model_registry[MODEL_TYPE]()
34
+ sam.load_state_dict(state_dict, strict=False)
35
+ sam.to(device=device)
36
+ predictor = SamPredictor(sam)
37
+ print("Modèle SAM chargé avec succès!")
38
+
39
+ # Fonction pour générer une couleur unique pour chaque classe
40
+ def get_color_for_class(class_name):
41
+ np.random.seed(hash(class_name) % (2**32))
42
+ return tuple(np.random.randint(0, 256, size=3).tolist())
43
+
44
+ @app.route('/', methods=['GET', 'POST'])
45
+ def index():
46
+ if request.method == 'POST':
47
+ file = request.files.get('image')
48
+ if not file or not file.filename:
49
+ return "Aucun fichier sélectionné", 400
50
+ filename = secure_filename(file.filename)
51
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
52
+ file.save(filepath)
53
+ return render_template('index.html', uploaded_image=filename)
54
+ return render_template('index.html')
55
+
56
+ @app.route('/uploads/<filename>')
57
+ def uploaded_file(filename):
58
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
59
+
60
+ @app.route('/segment', methods=['POST'])
61
+ def segment():
62
+ data = request.get_json()
63
+ image_name = data.get('image_name')
64
+ points = data.get('points')
65
+
66
+ if not image_name or not points:
67
+ return jsonify({'success': False, 'error': 'Données manquantes'}), 400
68
+
69
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
70
+ if not os.path.exists(image_path):
71
+ return jsonify({'success': False, 'error': 'Image non trouvée'}), 404
72
+
73
+ # Charger l'image et effectuer la segmentation
74
+ image = cv2.imread(image_path)
75
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
76
+ predictor.set_image(image_rgb)
77
+ annotated_image = image.copy()
78
+
79
+ for point in points:
80
+ x, y = point['x'], point['y']
81
+ class_name = point.get('class', 'Unknown')
82
+ color = get_color_for_class(class_name) # Couleur unique pour chaque classe
83
+ masks, _, _ = predictor.predict(
84
+ point_coords=np.array([[x, y]]),
85
+ point_labels=np.array([1]),
86
+ multimask_output=False
87
+ )
88
+ annotated_image[masks[0] > 0] = color # Superposer le masque avec la couleur
89
+ cv2.putText(annotated_image, class_name, (int(x), int(y)),
90
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) # Texte blanc
91
+
92
+ # Sauvegarder et renvoyer l'image annotée
93
+ annotated_filename = f"annotated_{image_name}"
94
+ annotated_path = os.path.join(app.config['UPLOAD_FOLDER'], annotated_filename)
95
+ cv2.imwrite(annotated_path, annotated_image)
96
+ return jsonify({'success': True, 'annotated_image': f"uploads/{annotated_filename}"})
97
+
98
+ if __name__ == '__main__':
99
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v5_app.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ # Initialisation de Flask
11
+ app = Flask(
12
+ __name__,
13
+ template_folder='templates', # Chemin des fichiers HTML
14
+ static_folder='static' # Chemin des fichiers statiques
15
+ )
16
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
17
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
18
+
19
+ # Charger le modèle SAM
20
+ MODEL_TYPE = "vit_b"
21
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
22
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
23
+
24
+ print("Chargement du modèle SAM...")
25
+ try:
26
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
27
+ except TypeError:
28
+ with warnings.catch_warnings():
29
+ warnings.simplefilter("ignore", category=UserWarning)
30
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
31
+
32
+ # Initialiser et charger le modèle
33
+ sam = sam_model_registry[MODEL_TYPE]()
34
+ sam.load_state_dict(state_dict, strict=False)
35
+ sam.to(device=device)
36
+ predictor = SamPredictor(sam)
37
+ print("Modèle SAM chargé avec succès!")
38
+
39
+ # Fonction pour générer une couleur unique pour chaque classe
40
+ def get_color_for_class(class_name):
41
+ np.random.seed(hash(class_name) % (2**32))
42
+ return tuple(np.random.randint(0, 256, size=3).tolist())
43
+
44
+ # Convertir un masque en bounding box au format YOLOv5
45
+ def mask_to_yolo_bbox(mask):
46
+ y_indices, x_indices = np.where(mask > 0)
47
+ if len(x_indices) == 0 or len(y_indices) == 0:
48
+ return None
49
+ x_min, x_max = x_indices.min(), x_indices.max()
50
+ y_min, y_max = y_indices.min(), y_indices.max()
51
+
52
+ # YOLOv5 format: x_center, y_center, width, height (normalized)
53
+ x_center = (x_min + x_max) / 2
54
+ y_center = (y_min + y_max) / 2
55
+ width = x_max - x_min
56
+ height = y_max - y_min
57
+
58
+ return x_center, y_center, width, height
59
+
60
+ @app.route('/', methods=['GET', 'POST'])
61
+ def index():
62
+ if request.method == 'POST':
63
+ file = request.files.get('image')
64
+ if not file or not file.filename:
65
+ return "Aucun fichier sélectionné", 400
66
+ filename = secure_filename(file.filename)
67
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
68
+ file.save(filepath)
69
+ return render_template('index.html', uploaded_image=filename)
70
+ return render_template('index.html')
71
+
72
+ @app.route('/uploads/<filename>')
73
+ def uploaded_file(filename):
74
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
75
+
76
+ @app.route('/segment', methods=['POST'])
77
+ def segment():
78
+ data = request.get_json()
79
+ image_name = data.get('image_name')
80
+ points = data.get('points')
81
+
82
+ if not image_name or not points:
83
+ return jsonify({'success': False, 'error': 'Données manquantes'}), 400
84
+
85
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
86
+ if not os.path.exists(image_path):
87
+ return jsonify({'success': False, 'error': 'Image non trouvée'}), 404
88
+
89
+ # Créer un dossier pour sauvegarder les résultats
90
+ output_dir = os.path.join(app.config['UPLOAD_FOLDER'], os.path.splitext(image_name)[0])
91
+ os.makedirs(output_dir, exist_ok=True)
92
+
93
+ # Charger l'image et effectuer la segmentation
94
+ image = cv2.imread(image_path)
95
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
96
+ predictor.set_image(image_rgb)
97
+ annotated_image = image.copy()
98
+
99
+ # YOLOv5 annotation
100
+ yolo_annotations = []
101
+
102
+ for point in points:
103
+ x, y = point['x'], point['y']
104
+ class_name = point.get('class', 'Unknown')
105
+ class_id = hash(class_name) % 1000 # Générer un ID unique basé sur le nom
106
+ color = get_color_for_class(class_name) # Couleur unique pour chaque classe
107
+ masks, _, _ = predictor.predict(
108
+ point_coords=np.array([[x, y]]),
109
+ point_labels=np.array([1]),
110
+ multimask_output=False
111
+ )
112
+ mask = masks[0]
113
+ annotated_image[mask > 0] = color # Superposer le masque avec la couleur
114
+
115
+ # Convertir le masque en bounding box YOLOv5
116
+ bbox = mask_to_yolo_bbox(mask)
117
+ if bbox:
118
+ x_center, y_center, width, height = bbox
119
+ # Normaliser les valeurs
120
+ x_center /= image.shape[1]
121
+ y_center /= image.shape[0]
122
+ width /= image.shape[1]
123
+ height /= image.shape[0]
124
+ yolo_annotations.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
125
+
126
+ # Ajouter le texte de la classe
127
+ cv2.putText(annotated_image, class_name, (int(x), int(y)),
128
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) # Texte blanc
129
+
130
+ # Sauvegarder les résultats
131
+ annotated_filename = f"annotated_{image_name}"
132
+ annotated_path = os.path.join(output_dir, annotated_filename)
133
+ cv2.imwrite(annotated_path, annotated_image)
134
+
135
+ # Sauvegarder les annotations YOLOv5
136
+ yolo_path = os.path.join(output_dir, f"{os.path.splitext(image_name)[0]}.txt")
137
+ with open(yolo_path, "w") as f:
138
+ f.write("\n".join(yolo_annotations))
139
+
140
+ # Copier l'image originale dans le dossier
141
+ original_copy_path = os.path.join(output_dir, image_name)
142
+ if not os.path.exists(original_copy_path):
143
+ os.rename(image_path, original_copy_path)
144
+
145
+ # Renvoyer le chemin relatif pour affichage
146
+ relative_output_dir = output_dir.replace("static/", "")
147
+ return jsonify({
148
+ 'success': True,
149
+ 'output_dir': relative_output_dir,
150
+ 'annotated_image': f"{relative_output_dir}/{annotated_filename}"
151
+ })
152
+
153
+ if __name__ == '__main__':
154
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v6_app.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+ import json
10
+
11
+ # Initialisation de Flask
12
+ app = Flask(
13
+ __name__,
14
+ template_folder='templates',
15
+ static_folder='static'
16
+ )
17
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
18
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
19
+
20
+ # Charger le modèle SAM
21
+ MODEL_TYPE = "vit_b"
22
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
23
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
24
+
25
+ print("Chargement du modèle SAM...")
26
+ try:
27
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
28
+ except TypeError:
29
+ with warnings.catch_warnings():
30
+ warnings.simplefilter("ignore", category=UserWarning)
31
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
32
+
33
+ # Initialiser et charger le modèle
34
+ sam = sam_model_registry[MODEL_TYPE]()
35
+ sam.load_state_dict(state_dict, strict=False)
36
+ sam.to(device=device)
37
+ predictor = SamPredictor(sam)
38
+ print("Modèle SAM chargé avec succès!")
39
+
40
+ # Fonction pour générer une couleur unique pour chaque classe
41
+ def get_color_for_class(class_name):
42
+ np.random.seed(hash(class_name) % (2**32))
43
+ return tuple(np.random.randint(0, 256, size=3).tolist())
44
+
45
+ # Convertir un masque en bounding box au format YOLOv5
46
+ def mask_to_yolo_bbox(mask):
47
+ y_indices, x_indices = np.where(mask > 0)
48
+ if len(x_indices) == 0 or len(y_indices) == 0:
49
+ return None
50
+ x_min, x_max = x_indices.min(), x_indices.max()
51
+ y_min, y_max = y_indices.min(), y_indices.max()
52
+
53
+ # YOLOv5 format: x_center, y_center, width, height (normalized)
54
+ x_center = (x_min + x_max) / 2
55
+ y_center = (y_min + y_max) / 2
56
+ width = x_max - x_min
57
+ height = y_max - y_min
58
+
59
+ return x_center, y_center, width, height
60
+
61
+ @app.route('/', methods=['GET', 'POST'])
62
+ def index():
63
+ if request.method == 'POST':
64
+ files = request.files.getlist('images') # Get multiple files
65
+ if not files:
66
+ return "Aucun fichier sélectionné", 400
67
+
68
+ filenames = []
69
+ for file in files:
70
+ filename = secure_filename(file.filename)
71
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
72
+ file.save(filepath)
73
+ filenames.append(filename)
74
+
75
+ return render_template('index.html', uploaded_images=filenames, all_annotated=False)
76
+
77
+ # Pour l'affichage des images déjà téléchargées
78
+ uploaded_images = os.listdir(app.config['UPLOAD_FOLDER'])
79
+ return render_template('index.html', uploaded_images=uploaded_images, all_annotated=False)
80
+
81
+ @app.route('/uploads/<filename>')
82
+ def uploaded_file(filename):
83
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
84
+
85
+ @app.route('/segment', methods=['POST'])
86
+ def segment():
87
+ data = request.get_json()
88
+ print("Données reçues :", data) # Log pour vérifier les données envoyées par le frontend
89
+
90
+ image_names = data.get('image_names')
91
+ points = data.get('points')
92
+
93
+ if not image_names or not points:
94
+ return jsonify({'success': False, 'error': 'Données manquantes'}), 400
95
+
96
+ output = []
97
+ for image_name in image_names:
98
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
99
+ if not os.path.exists(image_path):
100
+ return jsonify({'success': False, 'error': f'Image {image_name} non trouvée'}), 404
101
+
102
+ # Créer un dossier pour sauvegarder les résultats
103
+ output_dir = os.path.join(app.config['UPLOAD_FOLDER'], os.path.splitext(image_name)[0])
104
+ os.makedirs(output_dir, exist_ok=True)
105
+
106
+ # Charger l'image et effectuer la segmentation
107
+ image = cv2.imread(image_path)
108
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
109
+ predictor.set_image(image_rgb)
110
+ annotated_image = image.copy()
111
+
112
+ # YOLOv5 annotation
113
+ yolo_annotations = []
114
+
115
+ for point in points:
116
+ x, y = point['x'], point['y']
117
+ class_name = point.get('class', 'Unknown')
118
+ class_id = hash(class_name) % 1000 # Générer un ID unique basé sur le nom
119
+ color = get_color_for_class(class_name) # Couleur unique pour chaque classe
120
+ masks, _, _ = predictor.predict(
121
+ point_coords=np.array([[x, y]]),
122
+ point_labels=np.array([1]),
123
+ multimask_output=False
124
+ )
125
+ mask = masks[0]
126
+ annotated_image[mask > 0] = color # Superposer le masque avec la couleur
127
+
128
+ # Convertir le masque en bounding box YOLOv5
129
+ bbox = mask_to_yolo_bbox(mask)
130
+ if bbox:
131
+ x_center, y_center, width, height = bbox
132
+ # Normaliser les valeurs
133
+ x_center /= image.shape[1]
134
+ y_center /= image.shape[0]
135
+ width /= image.shape[1]
136
+ height /= image.shape[0]
137
+ yolo_annotations.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
138
+
139
+ # Ajouter le texte de la classe
140
+ cv2.putText(annotated_image, class_name, (int(x), int(y)),
141
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) # Texte blanc
142
+
143
+ # Sauvegarder les résultats
144
+ annotated_filename = f"annotated_{image_name}"
145
+ annotated_path = os.path.join(output_dir, annotated_filename)
146
+ cv2.imwrite(annotated_path, annotated_image)
147
+
148
+ # Sauvegarder les annotations YOLOv5
149
+ yolo_path = os.path.join(output_dir, f"{os.path.splitext(image_name)[0]}.txt")
150
+ with open(yolo_path, "w") as f:
151
+ f.write("\n".join(yolo_annotations))
152
+
153
+ # Copier l'image originale dans le dossier
154
+ original_copy_path = os.path.join(output_dir, image_name)
155
+ if not os.path.exists(original_copy_path):
156
+ os.rename(image_path, original_copy_path)
157
+
158
+ # Renvoyer le chemin relatif pour affichage
159
+ relative_output_dir = output_dir.replace("static/", "")
160
+ output.append({
161
+ 'success': True,
162
+ 'image': f"{relative_output_dir}/{annotated_filename}",
163
+ 'yolo_annotations': f"{relative_output_dir}/{os.path.splitext(image_name)[0]}.txt"
164
+ })
165
+
166
+ return jsonify(output)
167
+
168
+ if __name__ == '__main__':
169
+ app.run(debug=True, host='0.0.0.0', port=5000)
app_version/v7_multi_segmentaion.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template, jsonify, send_from_directory,url_for
2
+ import os
3
+ import torch
4
+ import numpy as np
5
+ import cv2
6
+ from segment_anything import sam_model_registry, SamPredictor
7
+ from werkzeug.utils import secure_filename
8
+ import warnings
9
+
10
+ app = Flask(
11
+ __name__,
12
+ template_folder='templates', # Chemin des fichiers HTML
13
+ static_folder='static' # Chemin des fichiers statiques
14
+ )
15
+ app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads')
16
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
17
+
18
+ # Charger le modèle SAM
19
+ MODEL_TYPE = "vit_b"
20
+ MODEL_PATH = os.path.join('models', 'sam_vit_b_01ec64.pth')
21
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
22
+
23
+ print("Chargement du modèle SAM...")
24
+ try:
25
+ state_dict = torch.load(MODEL_PATH, map_location="cpu", weights_only=True)
26
+ except TypeError:
27
+ with warnings.catch_warnings():
28
+ warnings.simplefilter("ignore", category=UserWarning)
29
+ state_dict = torch.load(MODEL_PATH, map_location="cpu")
30
+
31
+ # Initialiser et charger le modèle
32
+ sam = sam_model_registry[MODEL_TYPE]()
33
+ sam.load_state_dict(state_dict, strict=False)
34
+ sam.to(device=device)
35
+ predictor = SamPredictor(sam)
36
+ print("Modèle SAM chargé avec succès!")
37
+
38
+ # Générer une couleur unique pour chaque classe
39
+ # Fonction pour générer une couleur unique pour chaque classe
40
+ def get_color_for_class(class_name):
41
+ np.random.seed(hash(class_name) % (2**32))
42
+ return tuple(np.random.randint(0, 256, size=3).tolist())
43
+
44
+ # Convertir un masque en bounding box au format YOLOv5
45
+ def mask_to_yolo_bbox(mask):
46
+ y_indices, x_indices = np.where(mask > 0)
47
+ if len(x_indices) == 0 or len(y_indices) == 0:
48
+ return None
49
+ x_min, x_max = x_indices.min(), x_indices.max()
50
+ y_min, y_max = y_indices.min(), y_indices.max()
51
+ x_center = (x_min + x_max) / 2
52
+ y_center = (y_min + y_max) / 2
53
+ width = x_max - x_min
54
+ height = y_max - y_min
55
+ return x_center, y_center, width, height
56
+
57
+ @app.route('/', methods=['GET', 'POST'])
58
+ def index():
59
+ """Page principale pour télécharger et afficher les images."""
60
+ if request.method == 'POST':
61
+ files = request.files.getlist('images')
62
+ if not files:
63
+ return "Aucun fichier sélectionné", 400
64
+
65
+ filenames = []
66
+ for file in files:
67
+ filename = secure_filename(file.filename)
68
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
69
+ file.save(filepath)
70
+ filenames.append(filename)
71
+
72
+ return render_template('index.html', uploaded_images=filenames)
73
+
74
+ uploaded_images = os.listdir(app.config['UPLOAD_FOLDER'])
75
+ return render_template('index.html', uploaded_images=uploaded_images)
76
+
77
+ @app.route('/uploads/<filename>')
78
+ def uploaded_file(filename):
79
+ """Servir les fichiers uploadés."""
80
+ return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
81
+
82
+ @app.route('/segment', methods=['POST'])
83
+ def segment():
84
+ """Endpoint pour effectuer la segmentation des images."""
85
+ try:
86
+ data = request.get_json()
87
+ print("Données reçues :", data)
88
+
89
+ if not isinstance(data, list):
90
+ return jsonify({'success': False, 'error': 'Format incorrect : liste attendue'}), 400
91
+
92
+ output = []
93
+
94
+ for item in data:
95
+ image_name = item.get('image_name')
96
+ points = item.get('points', [])
97
+
98
+ if not image_name or not points:
99
+ return jsonify({'success': False, 'error': f"Données manquantes pour l'image {image_name}"}), 400
100
+
101
+ image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_name)
102
+ if not os.path.exists(image_path):
103
+ return jsonify({'success': False, 'error': f"Image {image_name} non trouvée"}), 404
104
+
105
+ # Charger l'image
106
+ image = cv2.imread(image_path)
107
+ if image is None:
108
+ return jsonify({'success': False, 'error': f"Impossible de charger l'image {image_name}"}), 400
109
+
110
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
111
+ predictor.set_image(image_rgb)
112
+ annotated_image = image.copy()
113
+ yolo_annotations = []
114
+
115
+ for point in points:
116
+ x, y = point['x'], point['y']
117
+ class_name = point.get('class', 'Unknown')
118
+ color = get_color_for_class(class_name)
119
+
120
+ try:
121
+ masks, _, _ = predictor.predict(
122
+ point_coords=np.array([[x, y]]),
123
+ point_labels=np.array([1]),
124
+ multimask_output=False
125
+ )
126
+ mask = masks[0]
127
+ annotated_image[mask > 0] = color
128
+
129
+ # Convertir le masque en bounding box YOLOv5
130
+ bbox = mask_to_yolo_bbox(mask)
131
+ if bbox:
132
+ x_center, y_center, width, height = bbox
133
+ x_center /= image.shape[1]
134
+ y_center /= image.shape[0]
135
+ width /= image.shape[1]
136
+ height /= image.shape[0]
137
+ yolo_annotations.append(f"{class_name} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}")
138
+
139
+ except Exception as e:
140
+ print(f"Erreur de segmentation pour le point {point} : {e}")
141
+
142
+ # Sauvegarder les résultats
143
+ output_dir = os.path.join(app.config['UPLOAD_FOLDER'], os.path.splitext(image_name)[0])
144
+ os.makedirs(output_dir, exist_ok=True)
145
+ annotated_path = os.path.join(output_dir, f"annotated_{image_name}")
146
+ cv2.imwrite(annotated_path, annotated_image)
147
+
148
+ yolo_path = os.path.join(output_dir, f"{os.path.splitext(image_name)[0]}.txt")
149
+ with open(yolo_path, "w") as f:
150
+ f.write("\n".join(yolo_annotations))
151
+
152
+ new_image_path = os.path.join(output_dir, image_name)
153
+ if not os.path.exists(new_image_path):
154
+ os.rename(image_path, new_image_path)
155
+
156
+ output.append({
157
+ 'image_name': image_name,
158
+ 'annotated_image': url_for('static', filename=f"uploads/{os.path.splitext(image_name)[0]}/annotated_{image_name}"),
159
+ 'yolo_annotations': url_for('static', filename=f"uploads/{os.path.splitext(image_name)[0]}/{os.path.splitext(image_name)[0]}.txt")
160
+ })
161
+
162
+ return jsonify({'success': True, 'results': output})
163
+
164
+ except Exception as e:
165
+ print("Erreur dans /segment :", str(e))
166
+ return jsonify({'success': False, 'error': str(e)}), 500
167
+
168
+ if __name__ == '__main__':
169
+ app.run(debug=True, host='0.0.0.0', port=5000)
convert_label.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ def convert_labels_in_place(input_dir, class_mapping):
4
+ """
5
+ Convertit les fichiers de labels en format YOLOv5 directement dans les fichiers originaux.
6
+
7
+ Args:
8
+ input_dir (str): Répertoire contenant les fichiers de labels à convertir.
9
+ class_mapping (dict): Dictionnaire {nom_classe: index}.
10
+ """
11
+ for file_name in os.listdir(input_dir):
12
+ if not file_name.endswith(".txt"):
13
+ continue
14
+
15
+ input_path = os.path.join(input_dir, file_name)
16
+ temp_path = input_path + ".temp" # Fichier temporaire pour éviter d'écraser immédiatement
17
+
18
+ with open(input_path, "r") as infile, open(temp_path, "w") as tempfile:
19
+ for line in infile:
20
+ parts = line.split()
21
+ # Vérifier que la ligne a au moins 10 éléments
22
+ if len(parts) < 10:
23
+ print(f"Skipping invalid line in {file_name}: {line.strip()}")
24
+ continue
25
+
26
+ try:
27
+ # Extraire les sommets du polygone
28
+ x1, y1 = float(parts[0]), float(parts[1])
29
+ x2, y2 = float(parts[2]), float(parts[3])
30
+ x3, y3 = float(parts[4]), float(parts[5])
31
+ x4, y4 = float(parts[6]), float(parts[7])
32
+
33
+ # Calculer les coordonnées de la bounding box
34
+ x_min = min(x1, x2, x3, x4)
35
+ y_min = min(y1, y2, y3, y4)
36
+ x_max = max(x1, x2, x3, x4)
37
+ y_max = max(y1, y2, y3, y4)
38
+
39
+ # Calculer x_center, y_center, width, height normalisés
40
+ img_width, img_height = 640, 640 # Assurez-vous que cette taille est correcte
41
+ x_center = ((x_min + x_max) / 2) / img_width
42
+ y_center = ((y_min + y_max) / 2) / img_height
43
+ width = (x_max - x_min) / img_width
44
+ height = (y_max - y_min) / img_height
45
+
46
+ # Convertir le nom de classe en indice
47
+ class_name = parts[8]
48
+ if class_name not in class_mapping:
49
+ print(f"Classe inconnue dans {file_name}: {class_name}")
50
+ continue
51
+
52
+ class_id = class_mapping[class_name]
53
+
54
+ # Écrire la ligne convertie dans le fichier temporaire
55
+ tempfile.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")
56
+ except ValueError as e:
57
+ print(f"Erreur de conversion dans {file_name}: {line.strip()} | Erreur : {e}")
58
+ continue
59
+
60
+ # Remplacer le fichier original par le fichier temporaire
61
+ os.replace(temp_path, input_path)
62
+ print(f"Converti : {input_path}")
63
+
64
+
65
+ # Mapping des noms de classes aux indices
66
+ class_mapping = {
67
+ "component": 0,
68
+ "void": 1
69
+ }
70
+
71
+ # Répertoire des fichiers de labels
72
+ input_dir = "labelid_image/valid/labels"
73
+
74
+ # Conversion des labels directement dans les fichiers originaux
75
+ convert_labels_in_place(input_dir, class_mapping)
download_lodel_yolo.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import hf_hub_download
2
+ import os
3
+
4
+ def download_yolo_model(repo_id="keizer77/samyolo2", filename="best.pt", output_dir="models"):
5
+ """
6
+ Télécharge un modèle YOLOv5 depuis Hugging Face.
7
+ """
8
+ os.makedirs(output_dir, exist_ok=True) # Créez le dossier si nécessaire
9
+
10
+ print(f"Téléchargement du modèle {filename} depuis le dépôt {repo_id}...")
11
+ model_path = hf_hub_download(repo_id=repo_id, filename=filename, cache_dir=output_dir)
12
+ print(f"Modèle téléchargé et sauvegardé dans : {model_path}")
13
+ return model_path
14
+
15
+ if __name__ == "__main__":
16
+ # Exemple d'utilisation
17
+ try:
18
+ downloaded_model_path = download_yolo_model()
19
+ print(f"Modèle prêt à être utilisé : {downloaded_model_path}")
20
+ except Exception as e:
21
+ print(f"Erreur lors du téléchargement du modèle : {e}")
download_model_sam.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+
4
+ # Créer le dossier cible s'il n'existe pas
5
+ os.makedirs("models", exist_ok=True)
6
+
7
+ # URL du modèle et chemin de destination
8
+ url = "https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth"
9
+ output_path = "models/sam_vit_b_01ec64.pth"
10
+
11
+ # Téléchargement
12
+ print("Téléchargement du modèle...")
13
+ response = requests.get(url, stream=True)
14
+ with open(output_path, "wb") as f:
15
+ for chunk in response.iter_content(chunk_size=8192):
16
+ f.write(chunk)
17
+
18
+ print("Téléchargement terminé ! Modèle sauvegardé dans :", output_path)
filestructure.txt ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ |-- .env
2
+ |-- app.py
3
+ |-- app_version
4
+ |-- v1_app.py
5
+ |-- v2_app.py
6
+ |-- v3_app.py
7
+ |-- v4_app.py
8
+ |-- v5_app.py
9
+ |-- v6_app.py
10
+ |-- v7_multi_segmentaion.py
11
+ |-- convert_label.py
12
+ |-- download_lodel_yolo.py
13
+ |-- download_model_sam.py
14
+ |-- idea
15
+ |-- auto training.py
16
+ |-- labelid_image
17
+ |-- data.yaml
18
+ |-- README.dataset.txt
19
+ |-- README.roboflow.txt
20
+ |-- test
21
+ |-- images
22
+ |-- 17_jpg.rf.bffd529c5bf4033da45bac4266570627.jpg
23
+ |-- 19_jpg.rf.d87571c6606039070d1f4d1ef6670a36.jpg
24
+ |-- 32_jpg.rf.17cfc81f24a609daff2ee0d7f9c403ea.jpg
25
+ |-- normal-reflow_jpg.rf.0bc1cd422852f197d37487cab35277de.jpg
26
+ |-- techtips_31_jpg.rf.cbc3a3c054285bbc91389e7b9944e0f1.jpg
27
+ |-- labels
28
+ |-- 17_jpg.rf.bffd529c5bf4033da45bac4266570627.txt
29
+ |-- 19_jpg.rf.d87571c6606039070d1f4d1ef6670a36.txt
30
+ |-- 32_jpg.rf.17cfc81f24a609daff2ee0d7f9c403ea.txt
31
+ |-- normal-reflow_jpg.rf.0bc1cd422852f197d37487cab35277de.txt
32
+ |-- techtips_31_jpg.rf.cbc3a3c054285bbc91389e7b9944e0f1.txt
33
+ |-- train
34
+ |-- images
35
+ |-- 02_JPG_jpg.rf.46475e2af0b81494f535407dca8a90df.jpg
36
+ |-- 02_JPG_jpg.rf.607f51fe5af261b2c6e1dcfdff8807dc.jpg
37
+ |-- 02_JPG_jpg.rf.ba454d33d656fe844e51c117639d3925.jpg
38
+ |-- 03_JPG_jpg.rf.3d664335f4575e8fa835d0e1b95ecd4a.jpg
39
+ |-- 03_JPG_jpg.rf.c1c14f4372dea6bb8c4812c6bc6b7748.jpg
40
+ |-- 03_JPG_jpg.rf.dce6c58b1c141a11eaa0ba797a39b8a0.jpg
41
+ |-- 04_JPG_jpg.rf.228ed8ab0bdabf748d31b6cf538e679a.jpg
42
+ |-- 04_JPG_jpg.rf.820d285cdb23efd232dcdcc2ddc19d0b.jpg
43
+ |-- 04_JPG_jpg.rf.8d252968125f0d1dcac7a227d9e81a14.jpg
44
+ |-- 05_jpg.rf.6f0497dc70803ad97f4fd7237ace269d.jpg
45
+ |-- 05_jpg.rf.a79bf109741928d7f0ec5c6ee1f60072.jpg
46
+ |-- 05_jpg.rf.b4b0f5581dc62bfd0eccf71f319a9426.jpg
47
+ |-- 08_JPG_jpg.rf.4af8990adfea52c23f0ee3b14626c289.jpg
48
+ |-- 08_JPG_jpg.rf.5ffca502a77dd15a24aeaa7cbf4bf419.jpg
49
+ |-- 08_JPG_jpg.rf.aa7636f8942d951b261a991e42c97abc.jpg
50
+ |-- 09_JPG_jpg.rf.1107a2106d3668730d997bc2f82e108c.jpg
51
+ |-- 09_JPG_jpg.rf.73bae9724ed4b99db8e4bd1416b5db79.jpg
52
+ |-- 09_JPG_jpg.rf.e3e36389aff5a943291dd5451fb13faf.jpg
53
+ |-- 10_JPG_jpg.rf.2692f3e373299579213dd91139305bf7.jpg
54
+ |-- 10_JPG_jpg.rf.79f0d2c21f3bdc9327961b56b6e63f0b.jpg
55
+ |-- 10_JPG_jpg.rf.ad9b4018e10df1f0f75945f983b447e3.jpg
56
+ |-- 11_JPG_jpg.rf.77790fe84eafc0d7f2af5c55620b236c.jpg
57
+ |-- 11_JPG_jpg.rf.9f16d7f9c3d7161a3e3cdd1cd31ff9dd.jpg
58
+ |-- 11_JPG_jpg.rf.c973e51ebd3c9138adf67aaa774cc3d1.jpg
59
+ |-- 12_jpg.rf.7327ab6b3de3aae49dca43ffa34b44eb.jpg
60
+ |-- 12_jpg.rf.cc6a06dd9d8d8c92b72b0200c8de9abd.jpg
61
+ |-- 12_jpg.rf.fdc79e50721cf51af7567ee329ef41b8.jpg
62
+ |-- 14_jpg.rf.34999d604ae615c91d3d902c6398b353.jpg
63
+ |-- 14_jpg.rf.4b37ab1bcc3adf9434a65cc6e8b1aa71.jpg
64
+ |-- 14_jpg.rf.c009a995ccc6605b6437fca4fef54b41.jpg
65
+ |-- 15r_jpg.rf.77fc1c57937c9f3671a76200321173c3.jpg
66
+ |-- 15r_jpg.rf.b7ad8e525ddc94abe50382d6d2001879.jpg
67
+ |-- 15r_jpg.rf.ebf6187721b3ccc403cd92708b213aad.jpg
68
+ |-- 15_jpg.rf.50a38ce8f7212ff40bc6462c54b4211d.jpg
69
+ |-- 15_jpg.rf.669e667f658e1652774eba6f02dfa5f2.jpg
70
+ |-- 15_jpg.rf.9553dee235f52bf9972979d2ecfa4b71.jpg
71
+ |-- 16_jpg.rf.448dc56101375a0f4f7dbbdfc6dfd6a8.jpg
72
+ |-- 16_jpg.rf.54131510d29bf7a96ac9a80096cc1709.jpg
73
+ |-- 16_jpg.rf.68e880a57b02225fb70f820fdd4e2e3f.jpg
74
+ |-- 18_jpg.rf.79ed74b38cded1cc737cc76593904f19.jpg
75
+ |-- 18_jpg.rf.a353c435e23b700c5762ab3c43a3b7b5.jpg
76
+ |-- 18_jpg.rf.d62c259c631f16821b9f18885bb6c3f2.jpg
77
+ |-- 20_jpg.rf.309c1e9931e0284a6eab07d703200db3.jpg
78
+ |-- 20_jpg.rf.be67670f261f896bcfa20a004664ea00.jpg
79
+ |-- 20_jpg.rf.e41773cdfef39afe830d48c80e7b9904.jpg
80
+ |-- 21_jpg.rf.027aced6583517fa7ab88f60cb721364.jpg
81
+ |-- 21_jpg.rf.6d6f283a384fd79667a128309a8504f7.jpg
82
+ |-- 21_jpg.rf.a9fdcbfb74638d7a07b66f21bd4346e7.jpg
83
+ |-- 22_jpg.rf.8636f2782cb04acd648403e779377f8e.jpg
84
+ |-- 22_jpg.rf.abe76c6faa4884e53e31a29197950769.jpg
85
+ |-- 22_jpg.rf.f0e7fef41d3d403c9c79875382262f74.jpg
86
+ |-- 25_jpg.rf.8484926dfad59e541b0ef2ae6784fcc8.jpg
87
+ |-- 25_jpg.rf.8fc6793b7c7195393a7a47447418f1ff.jpg
88
+ |-- 25_jpg.rf.cfdbc9ad0c5de9e42808c493e4dbea6f.jpg
89
+ |-- 26_jpg.rf.49f85c4d0d03d1d25be3c0e9ea0b251f.jpg
90
+ |-- 26_jpg.rf.8ce3aced6387343f0a9ab1d6250aecca.jpg
91
+ |-- 26_jpg.rf.df215b109ee20ef6618e41cc1f97d45a.jpg
92
+ |-- 29_jpg.rf.4898bea8a08db8612de89ab7d6b6c2fc.jpg
93
+ |-- 29_jpg.rf.5c441fbdbd06613382c8f780cde68cc8.jpg
94
+ |-- 29_jpg.rf.86abde10c2569ee60d13bf10a1f3752e.jpg
95
+ |-- 31_jpg.rf.52ca7660b43fc02e73d8687125d4fcde.jpg
96
+ |-- 31_jpg.rf.57070e9b0ffc517e0fff77f5b80c30ca.jpg
97
+ |-- 31_jpg.rf.792707571b6921b2141e8ab4fa84d736.jpg
98
+ |-- 7-Figure14-1_jpg.rf.63850a94a9f5642c721b088ed199d784.jpg
99
+ |-- 7-Figure14-1_jpg.rf.a1ac2d25ae90b3bad946773d77f8e216.jpg
100
+ |-- 7-Figure14-1_jpg.rf.d26136f007fc7c28647325a3cea8d763.jpg
101
+ |-- gc10_lake_voids_260-31_jpg.rf.35b70d42805f4eea091131a18e700121.jpg
102
+ |-- gc10_lake_voids_260-31_jpg.rf.55f5665abb89d3fae508e9d083d39c4a.jpg
103
+ |-- gc10_lake_voids_260-31_jpg.rf.73b30aed15e43196c52468d4b21f832f.jpg
104
+ |-- images_jpg.rf.059d5258ab915be973e1d87cdc0088d5.jpg
105
+ |-- images_jpg.rf.50f23ee8fafc1907c6400e5d9b897bc9.jpg
106
+ |-- images_jpg.rf.542b8e12e80348293e377385efb2766a.jpg
107
+ |-- LU-F_mod_jpg.rf.3c78583335c231eaf94d6381f2be6334.jpg
108
+ |-- LU-F_mod_jpg.rf.8e64fdb5f210effde8da288fa66f885c.jpg
109
+ |-- LU-F_mod_jpg.rf.beaff19f7c32f6ae36c17b66556eba6c.jpg
110
+ |-- qfn-voiding_0_jpg.rf.9feb6ba12734821030795e5a32bf0fe4.jpg
111
+ |-- qfn-voiding_0_jpg.rf.df9bf150f8a30becc2d7905db5a21ffb.jpg
112
+ |-- qfn-voiding_0_jpg.rf.fa13b031eddf08b3f80681a719d5d522.jpg
113
+ |-- Solder_Voids_jpg.rf.c7ff029524960bb21ad7c54c3699812d.jpg
114
+ |-- Solder_Voids_jpg.rf.d169656b8d049bb6257228e28afe7e45.jpg
115
+ |-- Solder_Voids_jpg.rf.f90508c3dcfae8bf2491a8eb1b15bb3a.jpg
116
+ |-- techtips_3_jpg.rf.5fa851d765dc5d0f7f599ba8d301a1bf.jpg
117
+ |-- techtips_3_jpg.rf.654255d42d56231a422190bbc0f5c5c1.jpg
118
+ |-- techtips_3_jpg.rf.875113b878fa23648c7a8c92ffe8c932.jpg
119
+ |-- labels
120
+ |-- 02_JPG_jpg.rf.46475e2af0b81494f535407dca8a90df.txt
121
+ |-- 02_JPG_jpg.rf.607f51fe5af261b2c6e1dcfdff8807dc.txt
122
+ |-- 02_JPG_jpg.rf.ba454d33d656fe844e51c117639d3925.txt
123
+ |-- 03_JPG_jpg.rf.3d664335f4575e8fa835d0e1b95ecd4a.txt
124
+ |-- 03_JPG_jpg.rf.c1c14f4372dea6bb8c4812c6bc6b7748.txt
125
+ |-- 03_JPG_jpg.rf.dce6c58b1c141a11eaa0ba797a39b8a0.txt
126
+ |-- 04_JPG_jpg.rf.228ed8ab0bdabf748d31b6cf538e679a.txt
127
+ |-- 04_JPG_jpg.rf.820d285cdb23efd232dcdcc2ddc19d0b.txt
128
+ |-- 04_JPG_jpg.rf.8d252968125f0d1dcac7a227d9e81a14.txt
129
+ |-- 05_jpg.rf.6f0497dc70803ad97f4fd7237ace269d.txt
130
+ |-- 05_jpg.rf.a79bf109741928d7f0ec5c6ee1f60072.txt
131
+ |-- 05_jpg.rf.b4b0f5581dc62bfd0eccf71f319a9426.txt
132
+ |-- 08_JPG_jpg.rf.4af8990adfea52c23f0ee3b14626c289.txt
133
+ |-- 08_JPG_jpg.rf.5ffca502a77dd15a24aeaa7cbf4bf419.txt
134
+ |-- 08_JPG_jpg.rf.aa7636f8942d951b261a991e42c97abc.txt
135
+ |-- 09_JPG_jpg.rf.1107a2106d3668730d997bc2f82e108c.txt
136
+ |-- 09_JPG_jpg.rf.73bae9724ed4b99db8e4bd1416b5db79.txt
137
+ |-- 09_JPG_jpg.rf.e3e36389aff5a943291dd5451fb13faf.txt
138
+ |-- 10_JPG_jpg.rf.2692f3e373299579213dd91139305bf7.txt
139
+ |-- 10_JPG_jpg.rf.79f0d2c21f3bdc9327961b56b6e63f0b.txt
140
+ |-- 10_JPG_jpg.rf.ad9b4018e10df1f0f75945f983b447e3.txt
141
+ |-- 11_JPG_jpg.rf.77790fe84eafc0d7f2af5c55620b236c.txt
142
+ |-- 11_JPG_jpg.rf.9f16d7f9c3d7161a3e3cdd1cd31ff9dd.txt
143
+ |-- 11_JPG_jpg.rf.c973e51ebd3c9138adf67aaa774cc3d1.txt
144
+ |-- 12_jpg.rf.7327ab6b3de3aae49dca43ffa34b44eb.txt
145
+ |-- 12_jpg.rf.cc6a06dd9d8d8c92b72b0200c8de9abd.txt
146
+ |-- 12_jpg.rf.fdc79e50721cf51af7567ee329ef41b8.txt
147
+ |-- 14_jpg.rf.34999d604ae615c91d3d902c6398b353.txt
148
+ |-- 14_jpg.rf.4b37ab1bcc3adf9434a65cc6e8b1aa71.txt
149
+ |-- 14_jpg.rf.c009a995ccc6605b6437fca4fef54b41.txt
150
+ |-- 15r_jpg.rf.77fc1c57937c9f3671a76200321173c3.txt
151
+ |-- 15r_jpg.rf.b7ad8e525ddc94abe50382d6d2001879.txt
152
+ |-- 15r_jpg.rf.ebf6187721b3ccc403cd92708b213aad.txt
153
+ |-- 15_jpg.rf.50a38ce8f7212ff40bc6462c54b4211d.txt
154
+ |-- 15_jpg.rf.669e667f658e1652774eba6f02dfa5f2.txt
155
+ |-- 15_jpg.rf.9553dee235f52bf9972979d2ecfa4b71.txt
156
+ |-- 16_jpg.rf.448dc56101375a0f4f7dbbdfc6dfd6a8.txt
157
+ |-- 16_jpg.rf.54131510d29bf7a96ac9a80096cc1709.txt
158
+ |-- 16_jpg.rf.68e880a57b02225fb70f820fdd4e2e3f.txt
159
+ |-- 18_jpg.rf.79ed74b38cded1cc737cc76593904f19.txt
160
+ |-- 18_jpg.rf.a353c435e23b700c5762ab3c43a3b7b5.txt
161
+ |-- 18_jpg.rf.d62c259c631f16821b9f18885bb6c3f2.txt
162
+ |-- 20_jpg.rf.309c1e9931e0284a6eab07d703200db3.txt
163
+ |-- 20_jpg.rf.be67670f261f896bcfa20a004664ea00.txt
164
+ |-- 20_jpg.rf.e41773cdfef39afe830d48c80e7b9904.txt
165
+ |-- 21_jpg.rf.027aced6583517fa7ab88f60cb721364.txt
166
+ |-- 21_jpg.rf.6d6f283a384fd79667a128309a8504f7.txt
167
+ |-- 21_jpg.rf.a9fdcbfb74638d7a07b66f21bd4346e7.txt
168
+ |-- 22_jpg.rf.8636f2782cb04acd648403e779377f8e.txt
169
+ |-- 22_jpg.rf.abe76c6faa4884e53e31a29197950769.txt
170
+ |-- 22_jpg.rf.f0e7fef41d3d403c9c79875382262f74.txt
171
+ |-- 25_jpg.rf.8484926dfad59e541b0ef2ae6784fcc8.txt
172
+ |-- 25_jpg.rf.8fc6793b7c7195393a7a47447418f1ff.txt
173
+ |-- 25_jpg.rf.cfdbc9ad0c5de9e42808c493e4dbea6f.txt
174
+ |-- 26_jpg.rf.49f85c4d0d03d1d25be3c0e9ea0b251f.txt
175
+ |-- 26_jpg.rf.8ce3aced6387343f0a9ab1d6250aecca.txt
176
+ |-- 26_jpg.rf.df215b109ee20ef6618e41cc1f97d45a.txt
177
+ |-- 29_jpg.rf.4898bea8a08db8612de89ab7d6b6c2fc.txt
178
+ |-- 29_jpg.rf.5c441fbdbd06613382c8f780cde68cc8.txt
179
+ |-- 29_jpg.rf.86abde10c2569ee60d13bf10a1f3752e.txt
180
+ |-- 31_jpg.rf.52ca7660b43fc02e73d8687125d4fcde.txt
181
+ |-- 31_jpg.rf.57070e9b0ffc517e0fff77f5b80c30ca.txt
182
+ |-- 31_jpg.rf.792707571b6921b2141e8ab4fa84d736.txt
183
+ |-- 7-Figure14-1_jpg.rf.63850a94a9f5642c721b088ed199d784.txt
184
+ |-- 7-Figure14-1_jpg.rf.a1ac2d25ae90b3bad946773d77f8e216.txt
185
+ |-- 7-Figure14-1_jpg.rf.d26136f007fc7c28647325a3cea8d763.txt
186
+ |-- gc10_lake_voids_260-31_jpg.rf.35b70d42805f4eea091131a18e700121.txt
187
+ |-- gc10_lake_voids_260-31_jpg.rf.55f5665abb89d3fae508e9d083d39c4a.txt
188
+ |-- gc10_lake_voids_260-31_jpg.rf.73b30aed15e43196c52468d4b21f832f.txt
189
+ |-- images_jpg.rf.059d5258ab915be973e1d87cdc0088d5.txt
190
+ |-- images_jpg.rf.50f23ee8fafc1907c6400e5d9b897bc9.txt
191
+ |-- images_jpg.rf.542b8e12e80348293e377385efb2766a.txt
192
+ |-- LU-F_mod_jpg.rf.3c78583335c231eaf94d6381f2be6334.txt
193
+ |-- LU-F_mod_jpg.rf.8e64fdb5f210effde8da288fa66f885c.txt
194
+ |-- LU-F_mod_jpg.rf.beaff19f7c32f6ae36c17b66556eba6c.txt
195
+ |-- qfn-voiding_0_jpg.rf.9feb6ba12734821030795e5a32bf0fe4.txt
196
+ |-- qfn-voiding_0_jpg.rf.df9bf150f8a30becc2d7905db5a21ffb.txt
197
+ |-- qfn-voiding_0_jpg.rf.fa13b031eddf08b3f80681a719d5d522.txt
198
+ |-- Solder_Voids_jpg.rf.c7ff029524960bb21ad7c54c3699812d.txt
199
+ |-- Solder_Voids_jpg.rf.d169656b8d049bb6257228e28afe7e45.txt
200
+ |-- Solder_Voids_jpg.rf.f90508c3dcfae8bf2491a8eb1b15bb3a.txt
201
+ |-- techtips_3_jpg.rf.5fa851d765dc5d0f7f599ba8d301a1bf.txt
202
+ |-- techtips_3_jpg.rf.654255d42d56231a422190bbc0f5c5c1.txt
203
+ |-- techtips_3_jpg.rf.875113b878fa23648c7a8c92ffe8c932.txt
204
+ |-- valid
205
+ |-- images
206
+ |-- 025_JPG_jpg.rf.d47dd8a24eec04a980085bb1fad81c1a.jpg
207
+ |-- 06_jpg.rf.ecf5de84954b61d29689eb0ce22c2044.jpg
208
+ |-- 07_JPG_jpg.rf.ccbbfdd3058e17eda2b2bcd0f0a46bc7.jpg
209
+ |-- 23_jpg.rf.1d1064aa64b455552f45fef20943bb89.jpg
210
+ |-- 24_jpg.rf.8aae72276db597edcc3464081d34670b.jpg
211
+ |-- 27_jpg.rf.999555b4b2a11b6c670968471381258f.jpg
212
+ |-- 28_jpg.rf.62e004c9a7670f016a0fb7f35a9c197a.jpg
213
+ |-- 30_jpg.rf.1f2e82377ba9f9219921b7a8d82f32cf.jpg
214
+ |-- labels
215
+ |-- 025_JPG_jpg.rf.d47dd8a24eec04a980085bb1fad81c1a.txt
216
+ |-- 06_jpg.rf.ecf5de84954b61d29689eb0ce22c2044.txt
217
+ |-- 07_JPG_jpg.rf.ccbbfdd3058e17eda2b2bcd0f0a46bc7.txt
218
+ |-- 23_jpg.rf.1d1064aa64b455552f45fef20943bb89.txt
219
+ |-- 24_jpg.rf.8aae72276db597edcc3464081d34670b.txt
220
+ |-- 27_jpg.rf.999555b4b2a11b6c670968471381258f.txt
221
+ |-- 28_jpg.rf.62e004c9a7670f016a0fb7f35a9c197a.txt
222
+ |-- 30_jpg.rf.1f2e82377ba9f9219921b7a8d82f32cf.txt
223
+ |-- models
224
+ |-- .locks
225
+ |-- models--keizer77--samyolo2
226
+ |-- models--keizer77--samyolo2
227
+ |-- blobs
228
+ |-- refs
229
+ |-- main
230
+ |-- snapshots
231
+ |-- 74c8cb12ae448ff0b8bae9ef522b54ec09b47c20
232
+ |-- best.pt
233
+ |-- sam_vit_b_01ec64.pth
234
+ |-- requirements.txt
235
+ |-- static
236
+ |-- css
237
+ |-- styles.css
238
+ |-- uploads
239
+ |-- templates
240
+ |-- index.html
241
+ |-- v1_index.html
242
+ |-- v3_index.html
243
+ |-- v4_index.html
244
+ |-- v5_index.html
245
+ |-- v6_index.py
246
+ |-- v7_multi_segmentation.html
247
+ |-- weights
248
+ |-- custom_model
249
+ |-- hyp.yaml
250
+ |-- opt.yaml
251
+ |-- weights
252
+ |-- custom_model10
253
+ |-- hyp.yaml
254
+ |-- labels.jpg
255
+ |-- labels_correlogram.jpg
256
+ |-- opt.yaml
257
+ |-- weights
258
+ |-- custom_model11
259
+ |-- hyp.yaml
260
+ |-- opt.yaml
261
+ |-- weights
262
+ |-- custom_model12
263
+ |-- hyp.yaml
264
+ |-- opt.yaml
265
+ |-- weights
266
+ |-- custom_model13
267
+ |-- hyp.yaml
268
+ |-- labels.jpg
269
+ |-- labels_correlogram.jpg
270
+ |-- opt.yaml
271
+ |-- weights
272
+ |-- custom_model14
273
+ |-- hyp.yaml
274
+ |-- labels.jpg
275
+ |-- labels_correlogram.jpg
276
+ |-- opt.yaml
277
+ |-- weights
278
+ |-- custom_model15
279
+ |-- hyp.yaml
280
+ |-- opt.yaml
281
+ |-- weights
282
+ |-- custom_model2
283
+ |-- hyp.yaml
284
+ |-- opt.yaml
285
+ |-- weights
286
+ |-- custom_model3
287
+ |-- hyp.yaml
288
+ |-- opt.yaml
289
+ |-- weights
290
+ |-- custom_model4
291
+ |-- hyp.yaml
292
+ |-- opt.yaml
293
+ |-- weights
294
+ |-- custom_model5
295
+ |-- hyp.yaml
296
+ |-- opt.yaml
297
+ |-- weights
298
+ |-- custom_model6
299
+ |-- hyp.yaml
300
+ |-- opt.yaml
301
+ |-- weights
302
+ |-- custom_model7
303
+ |-- hyp.yaml
304
+ |-- opt.yaml
305
+ |-- weights
306
+ |-- custom_model8
307
+ |-- hyp.yaml
308
+ |-- opt.yaml
309
+ |-- weights
310
+ |-- custom_model9
311
+ |-- hyp.yaml
312
+ |-- opt.yaml
313
+ |-- weights
314
+ |-- yolov5
315
+ |-- .dockerignore
316
+ |-- .gitattributes
317
+ |-- .github
318
+ |-- dependabot.yml
319
+ |-- ISSUE_TEMPLATE
320
+ |-- bug-report.yml
321
+ |-- config.yml
322
+ |-- feature-request.yml
323
+ |-- question.yml
324
+ |-- workflows
325
+ |-- ci-testing.yml
326
+ |-- cla.yml
327
+ |-- codeql-analysis.yml
328
+ |-- docker.yml
329
+ |-- format.yml
330
+ |-- links.yml
331
+ |-- merge-main-into-prs.yml
332
+ |-- stale.yml
333
+ |-- .gitignore
334
+ |-- benchmarks.py
335
+ |-- CITATION.cff
336
+ |-- classify
337
+ |-- predict.py
338
+ |-- train.py
339
+ |-- tutorial.ipynb
340
+ |-- val.py
341
+ |-- CONTRIBUTING.md
342
+ |-- data
343
+ |-- Argoverse.yaml
344
+ |-- coco.yaml
345
+ |-- coco128-seg.yaml
346
+ |-- coco128.yaml
347
+ |-- GlobalWheat2020.yaml
348
+ |-- hyps
349
+ |-- hyp.no-augmentation.yaml
350
+ |-- hyp.Objects365.yaml
351
+ |-- hyp.scratch-high.yaml
352
+ |-- hyp.scratch-low.yaml
353
+ |-- hyp.scratch-med.yaml
354
+ |-- hyp.VOC.yaml
355
+ |-- ImageNet.yaml
356
+ |-- ImageNet10.yaml
357
+ |-- ImageNet100.yaml
358
+ |-- ImageNet1000.yaml
359
+ |-- images
360
+ |-- bus.jpg
361
+ |-- zidane.jpg
362
+ |-- Objects365.yaml
363
+ |-- scripts
364
+ |-- download_weights.sh
365
+ |-- get_coco.sh
366
+ |-- get_coco128.sh
367
+ |-- get_imagenet.sh
368
+ |-- get_imagenet10.sh
369
+ |-- get_imagenet100.sh
370
+ |-- get_imagenet1000.sh
371
+ |-- SKU-110K.yaml
372
+ |-- VisDrone.yaml
373
+ |-- VOC.yaml
374
+ |-- xView.yaml
375
+ |-- detect.py
376
+ |-- export.py
377
+ |-- hubconf.py
378
+ |-- LICENSE
379
+ |-- models
380
+ |-- common.py
381
+ |-- experimental.py
382
+ |-- hub
383
+ |-- anchors.yaml
384
+ |-- yolov3-spp.yaml
385
+ |-- yolov3-tiny.yaml
386
+ |-- yolov3.yaml
387
+ |-- yolov5-bifpn.yaml
388
+ |-- yolov5-fpn.yaml
389
+ |-- yolov5-p2.yaml
390
+ |-- yolov5-p34.yaml
391
+ |-- yolov5-p6.yaml
392
+ |-- yolov5-p7.yaml
393
+ |-- yolov5-panet.yaml
394
+ |-- yolov5l6.yaml
395
+ |-- yolov5m6.yaml
396
+ |-- yolov5n6.yaml
397
+ |-- yolov5s-ghost.yaml
398
+ |-- yolov5s-LeakyReLU.yaml
399
+ |-- yolov5s-transformer.yaml
400
+ |-- yolov5s6.yaml
401
+ |-- yolov5x6.yaml
402
+ |-- segment
403
+ |-- yolov5l-seg.yaml
404
+ |-- yolov5m-seg.yaml
405
+ |-- yolov5n-seg.yaml
406
+ |-- yolov5s-seg.yaml
407
+ |-- yolov5x-seg.yaml
408
+ |-- tf.py
409
+ |-- yolo.py
410
+ |-- yolov5l.yaml
411
+ |-- yolov5m.yaml
412
+ |-- yolov5n.yaml
413
+ |-- yolov5s.yaml
414
+ |-- yolov5x.yaml
415
+ |-- __init__.py
416
+ |-- __pycache__
417
+ |-- common.cpython-312.pyc
418
+ |-- experimental.cpython-312.pyc
419
+ |-- yolo.cpython-312.pyc
420
+ |-- __init__.cpython-312.pyc
421
+ |-- pyproject.toml
422
+ |-- README.md
423
+ |-- README.zh-CN.md
424
+ |-- requirements.txt
425
+ |-- segment
426
+ |-- predict.py
427
+ |-- train.py
428
+ |-- tutorial.ipynb
429
+ |-- val.py
430
+ |-- train.py
431
+ |-- tutorial.ipynb
432
+ |-- utils
433
+ |-- activations.py
434
+ |-- augmentations.py
435
+ |-- autoanchor.py
436
+ |-- autobatch.py
437
+ |-- aws
438
+ |-- mime.sh
439
+ |-- resume.py
440
+ |-- userdata.sh
441
+ |-- __init__.py
442
+ |-- callbacks.py
443
+ |-- dataloaders.py
444
+ |-- docker
445
+ |-- Dockerfile
446
+ |-- Dockerfile-arm64
447
+ |-- Dockerfile-cpu
448
+ |-- downloads.py
449
+ |-- flask_rest_api
450
+ |-- example_request.py
451
+ |-- README.md
452
+ |-- restapi.py
453
+ |-- general.py
454
+ |-- google_app_engine
455
+ |-- additional_requirements.txt
456
+ |-- app.yaml
457
+ |-- Dockerfile
458
+ |-- loggers
459
+ |-- clearml
460
+ |-- clearml_utils.py
461
+ |-- hpo.py
462
+ |-- README.md
463
+ |-- __init__.py
464
+ |-- __pycache__
465
+ |-- clearml_utils.cpython-312.pyc
466
+ |-- __init__.cpython-312.pyc
467
+ |-- comet
468
+ |-- comet_utils.py
469
+ |-- hpo.py
470
+ |-- optimizer_config.json
471
+ |-- README.md
472
+ |-- __init__.py
473
+ |-- __pycache__
474
+ |-- comet_utils.cpython-312.pyc
475
+ |-- __init__.cpython-312.pyc
476
+ |-- wandb
477
+ |-- wandb_utils.py
478
+ |-- __init__.py
479
+ |-- __pycache__
480
+ |-- wandb_utils.cpython-312.pyc
481
+ |-- __init__.cpython-312.pyc
482
+ |-- __init__.py
483
+ |-- __pycache__
484
+ |-- __init__.cpython-312.pyc
485
+ |-- loss.py
486
+ |-- metrics.py
487
+ |-- plots.py
488
+ |-- segment
489
+ |-- augmentations.py
490
+ |-- dataloaders.py
491
+ |-- general.py
492
+ |-- loss.py
493
+ |-- metrics.py
494
+ |-- plots.py
495
+ |-- __init__.py
496
+ |-- torch_utils.py
497
+ |-- triton.py
498
+ |-- __init__.py
499
+ |-- __pycache__
500
+ |-- augmentations.cpython-312.pyc
501
+ |-- autoanchor.cpython-312.pyc
502
+ |-- autobatch.cpython-312.pyc
503
+ |-- callbacks.cpython-312.pyc
504
+ |-- dataloaders.cpython-312.pyc
505
+ |-- downloads.cpython-312.pyc
506
+ |-- general.cpython-312.pyc
507
+ |-- loss.cpython-312.pyc
508
+ |-- metrics.cpython-312.pyc
509
+ |-- plots.cpython-312.pyc
510
+ |-- torch_utils.cpython-312.pyc
511
+ |-- __init__.cpython-312.pyc
512
+ |-- val.py
513
+ |-- __pycache__
514
+ |-- train.cpython-312.pyc
515
+ |-- val.cpython-312.pyc
516
+ |-- yolo_training.py
517
+ |-- yolo_training_v1.py
requirements.txt ADDED
Binary file (1.08 kB). View file
 
startup.sh ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ echo "Starting the deployment process"
4
+
5
+ # 1. Créer une virtual environment
6
+ echo "Creating virtual environment..."
7
+ python3 -m venv venv
8
+
9
+ # 2. Activer la virtual environment
10
+ echo "Activating virtual environment..."
11
+ source venv/bin/activate
12
+
13
+ # 3. Installer les dépendances
14
+ echo "Installing dependencies..."
15
+ pip install --upgrade pip
16
+ pip install -r requirements.txt
17
+
18
+ # 4. Exécuter les fichiers Python contenant 'download' dans leur nom
19
+ echo "Running download scripts..."
20
+ for file in $(ls | grep download.*\.py); do
21
+ echo "Executing $file..."
22
+ python $file
23
+ done
24
+
25
+ # 5. Démarrer l'application avec Gunicorn
26
+ echo "Starting the Flask application with Gunicorn..."
27
+ gunicorn --bind 0.0.0.0:8000 app:app
static/css/styles.css ADDED
File without changes
templates/index.html ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ <style>
9
+ /* General Styles */
10
+ body {
11
+ font-family: Arial, sans-serif;
12
+ margin: 0;
13
+ padding: 0;
14
+ background-color: #f4f4f4;
15
+ }
16
+
17
+ header {
18
+ background-color: #4CAF50;
19
+ padding: 15px 0;
20
+ text-align: center;
21
+ color: white;
22
+ font-size: 24px;
23
+ font-weight: bold;
24
+ }
25
+
26
+ section {
27
+ margin: 20px auto;
28
+ max-width: 1200px;
29
+ padding: 20px;
30
+ background: white;
31
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
32
+ border-radius: 8px;
33
+ }
34
+
35
+ .upload-section {
36
+ text-align: center;
37
+ }
38
+
39
+ .upload-section input[type="file"] {
40
+ margin: 10px 0;
41
+ }
42
+
43
+ .image-container {
44
+ display: flex;
45
+ flex-wrap: wrap;
46
+ gap: 20px;
47
+ justify-content: center;
48
+ }
49
+
50
+ .image-item {
51
+ width: 150px;
52
+ height: 150px;
53
+ overflow: hidden;
54
+ border: 2px solid #ddd;
55
+ border-radius: 8px;
56
+ cursor: pointer;
57
+ transition: transform 0.3s ease, border-color 0.3s ease;
58
+ display: flex;
59
+ justify-content: center;
60
+ align-items: center;
61
+ background-color: #fff;
62
+ }
63
+
64
+ .image-item:hover {
65
+ border-color: #4CAF50;
66
+ transform: scale(1.05);
67
+ }
68
+
69
+ .image-item img {
70
+ max-width: 100%;
71
+ max-height: 100%;
72
+ object-fit: cover;
73
+ }
74
+
75
+ canvas {
76
+ border: 2px solid #ddd;
77
+ border-radius: 8px;
78
+ margin: 20px auto;
79
+ display: block;
80
+ }
81
+
82
+ .class-management {
83
+ text-align: center;
84
+ margin-bottom: 20px;
85
+ }
86
+
87
+ .class-management input[type="text"] {
88
+ padding: 8px;
89
+ font-size: 16px;
90
+ width: 300px;
91
+ margin-right: 10px;
92
+ }
93
+
94
+ .class-list {
95
+ display: flex;
96
+ justify-content: center;
97
+ flex-wrap: wrap;
98
+ gap: 10px;
99
+ list-style: none;
100
+ padding: 0;
101
+ }
102
+
103
+ .class-item {
104
+ padding: 5px 15px;
105
+ border-radius: 20px;
106
+ background-color: #f4f4f4;
107
+ border: 1px solid #ccc;
108
+ cursor: pointer;
109
+ transition: all 0.3s ease;
110
+ }
111
+
112
+ .class-item:hover {
113
+ background-color: #ddd;
114
+ }
115
+
116
+ .class-item.active {
117
+ background-color: #4CAF50;
118
+ color: white;
119
+ border-color: #45a049;
120
+ }
121
+
122
+ .controls {
123
+ text-align: center;
124
+ margin-top: 20px;
125
+ }
126
+
127
+ button {
128
+ background-color: #4CAF50;
129
+ color: white;
130
+ border: none;
131
+ padding: 10px 20px;
132
+ font-size: 16px;
133
+ cursor: pointer;
134
+ border-radius: 5px;
135
+ transition: background-color 0.3s ease;
136
+ margin: 0 10px;
137
+ }
138
+
139
+ button:hover {
140
+ background-color: #45a049;
141
+ }
142
+
143
+ button:disabled {
144
+ background-color: #ccc;
145
+ cursor: not-allowed;
146
+ }
147
+
148
+ .result-section img {
149
+ max-width: 100%;
150
+ margin: 20px auto;
151
+ display: block;
152
+ border: 2px solid #4CAF50;
153
+ border-radius: 8px;
154
+ }
155
+ </style>
156
+ </head>
157
+ <body>
158
+ <header>Labélisation d'Images avec SAM</header>
159
+
160
+ <!-- Section 1: Téléchargement d'images -->
161
+ <section class="upload-section">
162
+ <h2>Télécharger vos images</h2>
163
+ <form method="post" enctype="multipart/form-data">
164
+ <input type="file" id="image" name="images" accept="image/*" multiple required>
165
+ <br>
166
+ <button type="submit">Télécharger</button>
167
+ </form>
168
+ </section>
169
+
170
+ {% if uploaded_images %}
171
+ <!-- Section 2: Galerie des images téléchargées -->
172
+ <section>
173
+ <h2>Images téléchargées</h2>
174
+ <div class="image-container">
175
+ {% for image in uploaded_images %}
176
+ <div class="image-item" onclick="loadImage('{{ image }}')">
177
+ <img src="{{ url_for('static', filename='uploads/' + image) }}" alt="{{ image }}">
178
+ </div>
179
+ {% endfor %}
180
+ </div>
181
+ </section>
182
+
183
+ <!-- Section 3: Zone de travail -->
184
+ <section>
185
+ <canvas id="image-canvas"></canvas>
186
+ </section>
187
+
188
+ <!-- Section 4: Gestion des classes -->
189
+ <section class="class-management">
190
+ <h3>Ajouter une classe</h3>
191
+ <input type="text" id="class-name" placeholder="Nom de la classe">
192
+ <button id="add-class">Ajouter</button>
193
+ <ul id="class-list" class="class-list"></ul>
194
+ </section>
195
+
196
+ <!-- Section 5: Contrôles -->
197
+ <section class="controls">
198
+ <button id="finish-button" disabled>Terminer l'annotation</button>
199
+ <button id="segment-button" disabled>Lancer la segmentation</button>
200
+ </section>
201
+ {% endif %}
202
+
203
+ <script>
204
+ let selectedImage = null; // Image actuellement sélectionnée
205
+ let annotations = {}; // Stocke les annotations de chaque image (clé : image, valeur : points)
206
+ let currentClass = null; // Classe actuellement sélectionnée
207
+ const finishButton = document.getElementById('finish-button');
208
+ const segmentButton = document.getElementById('segment-button');
209
+
210
+ function loadImage(imageName) {
211
+ if (!imageName) {
212
+ alert("Veuillez sélectionner une image !");
213
+ return;
214
+ }
215
+
216
+ selectedImage = imageName; // Stockez le nom de l'image sélectionnée
217
+ console.log("Image sélectionnée :", selectedImage);
218
+
219
+ // Initialiser les annotations pour cette image si elles n'existent pas
220
+ if (!annotations[selectedImage]) {
221
+ annotations[selectedImage] = [];
222
+ }
223
+
224
+ const img = new Image();
225
+ img.src = `/static/uploads/${imageName}`;
226
+ img.onload = () => {
227
+ const canvas = document.getElementById('image-canvas');
228
+ const ctx = canvas.getContext('2d');
229
+ canvas.width = img.width;
230
+ canvas.height = img.height;
231
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
232
+ ctx.drawImage(img, 0, 0);
233
+
234
+ // Dessiner les points existants pour cette image
235
+ annotations[selectedImage].forEach(point => {
236
+ drawPoint(ctx, point.x, point.y, point.class);
237
+ });
238
+ };
239
+
240
+ finishButton.disabled = false;
241
+ }
242
+
243
+ function drawPoint(ctx, x, y, pointClass) {
244
+ ctx.fillStyle = pointClass === 'arbre' ? 'green' : 'red';
245
+ ctx.beginPath();
246
+ ctx.arc(x, y, 5, 0, 2 * Math.PI);
247
+ ctx.fill();
248
+ }
249
+
250
+ document.getElementById('add-class').addEventListener('click', () => {
251
+ const className = document.getElementById('class-name').value.trim();
252
+ if (!className) {
253
+ alert("Veuillez entrer un nom de classe !");
254
+ return;
255
+ }
256
+ const li = document.createElement('li');
257
+ li.textContent = className;
258
+ li.classList.add('class-item');
259
+ li.onclick = () => {
260
+ document.querySelectorAll('.class-item').forEach(item => item.classList.remove('active'));
261
+ li.classList.add('active');
262
+ currentClass = className;
263
+ console.log("Classe sélectionnée :", currentClass);
264
+ };
265
+ document.getElementById('class-list').appendChild(li);
266
+ document.getElementById('class-name').value = '';
267
+ });
268
+
269
+ const canvas = document.getElementById('image-canvas');
270
+ const ctx = canvas.getContext('2d');
271
+
272
+ canvas.addEventListener('click', (event) => {
273
+ if (!currentClass) {
274
+ alert("Veuillez sélectionner une classe avant d'ajouter des points !");
275
+ return;
276
+ }
277
+
278
+ if (!selectedImage) {
279
+ alert("Veuillez sélectionner une image avant d'ajouter des points !");
280
+ return;
281
+ }
282
+
283
+ const rect = canvas.getBoundingClientRect();
284
+ const x = event.clientX - rect.left;
285
+ const y = event.clientY - rect.top;
286
+
287
+ const newPoint = { x, y, class: currentClass };
288
+ annotations[selectedImage].push(newPoint);
289
+ console.log(`Point ajouté pour ${selectedImage}:`, newPoint);
290
+
291
+ drawPoint(ctx, x, y, currentClass);
292
+ });
293
+
294
+ finishButton.addEventListener('click', () => {
295
+ if (!selectedImage) {
296
+ alert("Veuillez sélectionner une image !");
297
+ return;
298
+ }
299
+
300
+ console.log(`Annotation terminée pour ${selectedImage}.`);
301
+ alert(`Annotation pour ${selectedImage} terminée !`);
302
+
303
+ finishButton.disabled = true;
304
+
305
+ // Vérifiez si toutes les annotations sont terminées
306
+ if (Object.keys(annotations).length > 0) {
307
+ segmentButton.disabled = false;
308
+ }
309
+ });
310
+
311
+ segmentButton.addEventListener('click', () => {
312
+ const dataToSend = Object.keys(annotations).map(imageName => ({
313
+ image_name: imageName,
314
+ points: annotations[imageName]
315
+ }));
316
+
317
+ console.log("Données envoyées :", dataToSend);
318
+
319
+ fetch('/segment', {
320
+ method: 'POST',
321
+ headers: { 'Content-Type': 'application/json' },
322
+ body: JSON.stringify(dataToSend)
323
+ })
324
+ .then(response => response.json())
325
+ .then(data => {
326
+ console.log("Réponse du backend :", data);
327
+ if (data.success) {
328
+ alert("Segmentation réussie !");
329
+ } else {
330
+ alert("Erreur : " + data.error);
331
+ }
332
+ })
333
+ .catch(err => console.error('Erreur lors de la segmentation :', err));
334
+ });
335
+ </script>
336
+ </body>
337
+ </html>
templates/v1_index.html ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ </head>
9
+ <body>
10
+ <h1>Labélisation d'Images avec SAM</h1>
11
+
12
+ <!-- Formulaire pour télécharger une image -->
13
+ <form method="post" enctype="multipart/form-data">
14
+ <label for="image">Télécharger une image :</label>
15
+ <input type="file" id="image" name="image" accept="image/*" required>
16
+ <button type="submit">Télécharger</button>
17
+ </form>
18
+
19
+ <!-- Prévisualisation de l'image sélectionnée -->
20
+ <h2>Prévisualisation :</h2>
21
+ <img id="preview" src="#" alt="Prévisualisation de l'image" style="max-width: 100%; display: none; border: 1px solid #ddd;">
22
+
23
+ <!-- JavaScript pour afficher la prévisualisation -->
24
+ <script>
25
+ // Récupérer l'élément <input> pour l'image et la balise <img> pour la prévisualisation
26
+ const imageInput = document.getElementById('image');
27
+ const preview = document.getElementById('preview');
28
+
29
+ // Écouteur pour détecter les changements dans l'input
30
+ imageInput.addEventListener('change', function(event) {
31
+ const file = event.target.files[0]; // Récupérer le fichier sélectionné
32
+ if (file) {
33
+ const reader = new FileReader(); // Créer un FileReader pour lire le fichier
34
+ reader.onload = function(e) {
35
+ preview.src = e.target.result; // Mettre à jour la source de l'image
36
+ preview.style.display = 'block'; // Afficher l'image
37
+ };
38
+ reader.readAsDataURL(file); // Lire le fichier comme une URL de données
39
+ } else {
40
+ preview.src = '#'; // Réinitialiser si aucun fichier n'est sélectionné
41
+ preview.style.display = 'none';
42
+ }
43
+ });
44
+ </script>
45
+ </body>
46
+ </html>
templates/v3_index.html ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ </head>
9
+ <body>
10
+ <h1>Labélisation d'Images avec SAM</h1>
11
+ <div class="container">
12
+ <!-- Upload Section -->
13
+ <div class="upload-section">
14
+ <form method="post" enctype="multipart/form-data">
15
+ <label for="image">Télécharger une image :</label>
16
+ <input type="file" id="image" name="image" accept="image/*" required>
17
+ <button type="submit">Télécharger</button>
18
+ </form>
19
+ </div>
20
+
21
+ {% if uploaded_image %}
22
+ <!-- Display Uploaded Image -->
23
+ <canvas id="image-canvas"></canvas>
24
+
25
+ <!-- Class Management -->
26
+ <div class="class-management">
27
+ <h3>Ajouter une classe :</h3>
28
+ <input type="text" id="class-name" placeholder="Entrez une classe">
29
+ <button id="add-class">Ajouter</button>
30
+ <ul id="class-list"></ul>
31
+ </div>
32
+
33
+ <!-- Controls -->
34
+ <div class="controls">
35
+ <button id="segment-button" disabled>Lancer la Segmentation</button>
36
+ </div>
37
+ {% endif %}
38
+ </div>
39
+
40
+ <script>
41
+ let canvas = document.getElementById('image-canvas');
42
+ let ctx = canvas ? canvas.getContext('2d') : null;
43
+ let points = [];
44
+ let currentClass = null;
45
+ let img = null;
46
+
47
+ {% if uploaded_image %}
48
+ img = new Image();
49
+ img.src = "{{ url_for('static', filename='uploads/' + uploaded_image) }}";
50
+ img.onload = () => {
51
+ canvas.width = img.width;
52
+ canvas.height = img.height;
53
+ ctx.drawImage(img, 0, 0);
54
+ };
55
+
56
+ // Activer ou désactiver le bouton de segmentation
57
+ function updateSegmentButtonState() {
58
+ const segmentButton = document.getElementById('segment-button');
59
+ if (points.length > 0) {
60
+ segmentButton.disabled = false; // Activer le bouton
61
+ } else {
62
+ segmentButton.disabled = true; // Désactiver le bouton
63
+ }
64
+ }
65
+
66
+ // Gestion des clics sur le canvas
67
+ canvas.addEventListener('click', event => {
68
+ const rect = canvas.getBoundingClientRect();
69
+ const x = event.clientX - rect.left;
70
+ const y = event.clientY - rect.top;
71
+
72
+ if (!currentClass) {
73
+ alert('Veuillez sélectionner une classe avant d’ajouter des points.');
74
+ return;
75
+ }
76
+
77
+ // Ajouter le point
78
+ points.push({ x, y, class: currentClass });
79
+
80
+ // Dessiner le point sur le canvas
81
+ ctx.fillStyle = 'red';
82
+ ctx.beginPath();
83
+ ctx.arc(x, y, 5, 0, 2 * Math.PI);
84
+ ctx.fill();
85
+
86
+ // Mettre à jour l'état du bouton
87
+ updateSegmentButtonState();
88
+ });
89
+
90
+ // Ajouter une classe et la sélectionner
91
+ document.getElementById('add-class').addEventListener('click', () => {
92
+ const classNameInput = document.getElementById('class-name');
93
+ const className = classNameInput.value.trim();
94
+
95
+ if (!className) {
96
+ alert('Veuillez entrer une classe.');
97
+ return;
98
+ }
99
+
100
+ const classList = document.getElementById('class-list');
101
+ const li = document.createElement('li');
102
+ li.textContent = className;
103
+ li.classList.add('class-item');
104
+ li.addEventListener('click', () => {
105
+ document.querySelectorAll('.class-item').forEach(el => el.classList.remove('active'));
106
+ li.classList.add('active');
107
+ currentClass = className;
108
+ });
109
+
110
+ classList.appendChild(li);
111
+ classNameInput.value = '';
112
+ });
113
+
114
+ // Lancer la segmentation
115
+ document.getElementById('segment-button').addEventListener('click', () => {
116
+ const imageName = "{{ uploaded_image }}";
117
+
118
+ fetch('/segment', {
119
+ method: 'POST',
120
+ headers: { 'Content-Type': 'application/json' },
121
+ body: JSON.stringify({
122
+ image_name: imageName,
123
+ points: points
124
+ })
125
+ })
126
+ .then(response => response.json())
127
+ .then(data => {
128
+ if (data.success) {
129
+ alert('Segmentation réussie !');
130
+ } else {
131
+ alert('Erreur : ' + data.error);
132
+ }
133
+ })
134
+ .catch(error => {
135
+ console.error('Erreur lors de la segmentation :', error);
136
+ });
137
+ });
138
+
139
+ // Désactiver le bouton au chargement
140
+ updateSegmentButtonState();
141
+ {% endif %}
142
+ </script>
143
+
144
+ </body>
145
+ </html>
templates/v4_index.html ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ <style>
9
+ body {
10
+ font-family: Arial, sans-serif;
11
+ margin: 20px;
12
+ background-color: #f9f9f9;
13
+ }
14
+
15
+ h1 {
16
+ text-align: center;
17
+ color: #333;
18
+ }
19
+
20
+ section {
21
+ margin: 20px 0;
22
+ padding: 20px;
23
+ background: #fff;
24
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
25
+ border-radius: 8px;
26
+ }
27
+
28
+ canvas {
29
+ border: 2px solid #ddd;
30
+ border-radius: 8px;
31
+ display: block;
32
+ margin: 20px auto;
33
+ }
34
+
35
+ button {
36
+ background-color: #4CAF50;
37
+ color: white;
38
+ border: none;
39
+ padding: 10px 20px;
40
+ font-size: 14px;
41
+ cursor: pointer;
42
+ border-radius: 5px;
43
+ transition: background-color 0.3s ease;
44
+ }
45
+
46
+ button:hover {
47
+ background-color: #45a049;
48
+ }
49
+
50
+ button:disabled {
51
+ background-color: #ccc;
52
+ cursor: not-allowed;
53
+ }
54
+
55
+ .upload-section {
56
+ text-align: center;
57
+ }
58
+
59
+ .class-management {
60
+ text-align: center;
61
+ }
62
+
63
+ .class-list {
64
+ display: flex;
65
+ flex-wrap: wrap;
66
+ gap: 10px;
67
+ justify-content: center;
68
+ list-style: none;
69
+ padding: 0;
70
+ }
71
+
72
+ .class-item {
73
+ padding: 5px 10px;
74
+ border-radius: 5px;
75
+ background-color: #f4f4f4;
76
+ border: 1px solid #ccc;
77
+ cursor: pointer;
78
+ transition: all 0.3s ease;
79
+ }
80
+
81
+ .class-item:hover {
82
+ background-color: #ddd;
83
+ }
84
+
85
+ .class-item.active {
86
+ background-color: #4CAF50;
87
+ color: white;
88
+ border-color: #45a049;
89
+ }
90
+
91
+ #annotated-image {
92
+ display: block;
93
+ max-width: 100%;
94
+ margin: 20px auto;
95
+ border: 2px solid #4CAF50;
96
+ border-radius: 8px;
97
+ }
98
+
99
+ .status {
100
+ text-align: center;
101
+ margin-top: 10px;
102
+ font-weight: bold;
103
+ }
104
+
105
+ .status.success {
106
+ color: #4CAF50;
107
+ }
108
+
109
+ .status.error {
110
+ color: #f44336;
111
+ }
112
+ </style>
113
+ </head>
114
+ <body>
115
+ <h1>Labélisation d'Images avec SAM</h1>
116
+
117
+ <!-- Section 1: Upload Image -->
118
+ <section class="upload-section">
119
+ <form method="post" enctype="multipart/form-data">
120
+ <label for="image">Télécharger une image :</label><br>
121
+ <input type="file" id="image" name="image" accept="image/*" required>
122
+ <br>
123
+ <button type="submit">Télécharger</button>
124
+ </form>
125
+ </section>
126
+
127
+ {% if uploaded_image %}
128
+ <!-- Section 2: Canvas for Image -->
129
+ <section>
130
+ <canvas id="image-canvas"></canvas>
131
+ </section>
132
+
133
+ <!-- Section 3: Annotated Image -->
134
+ <section>
135
+ <h2>Image Annotée</h2>
136
+ <img id="annotated-image" style="display: none;" alt="Image Annotée">
137
+ </section>
138
+
139
+ <!-- Section 4: Manage Classes -->
140
+ <section class="class-management">
141
+ <h3>Ajouter une classe :</h3>
142
+ <input type="text" id="class-name" placeholder="Entrez une classe">
143
+ <button id="add-class">Ajouter</button>
144
+ <h4>Classes disponibles :</h4>
145
+ <ul id="class-list" class="class-list"></ul>
146
+ </section>
147
+
148
+ <!-- Section 5: Controls -->
149
+ <section>
150
+ <div class="controls">
151
+ <button id="segment-button" disabled>Lancer la Segmentation</button>
152
+ </div>
153
+ </section>
154
+ {% endif %}
155
+
156
+ <script>
157
+ let canvas = document.getElementById('image-canvas');
158
+ let ctx = canvas ? canvas.getContext('2d') : null;
159
+ let points = [];
160
+ let currentClass = null;
161
+
162
+ {% if uploaded_image %}
163
+ // Charger l'image téléchargée
164
+ const img = new Image();
165
+ img.src = "{{ url_for('static', filename='uploads/' + uploaded_image) }}";
166
+ img.onload = () => {
167
+ canvas.width = img.width;
168
+ canvas.height = img.height;
169
+ ctx.drawImage(img, 0, 0);
170
+ };
171
+
172
+ // Gestion des classes
173
+ document.getElementById('add-class').addEventListener('click', () => {
174
+ const className = document.getElementById('class-name').value.trim();
175
+ if (!className) return;
176
+
177
+ const li = document.createElement('li');
178
+ li.textContent = className;
179
+ li.classList.add('class-item');
180
+ li.onclick = () => {
181
+ // Marquer la classe comme sélectionnée
182
+ document.querySelectorAll('.class-item').forEach(item => item.classList.remove('active'));
183
+ li.classList.add('active');
184
+ currentClass = className;
185
+ };
186
+
187
+ document.getElementById('class-list').appendChild(li);
188
+ document.getElementById('class-name').value = '';
189
+ });
190
+
191
+ // Ajouter un point sur le canvas
192
+ canvas.addEventListener('click', event => {
193
+ if (!currentClass) {
194
+ alert('Veuillez sélectionner une classe.');
195
+ return;
196
+ }
197
+
198
+ const rect = canvas.getBoundingClientRect();
199
+ const x = event.clientX - rect.left;
200
+ const y = event.clientY - rect.top;
201
+ points.push({ x, y, class: currentClass });
202
+
203
+ // Dessiner le point sur le canvas
204
+ ctx.fillStyle = 'red';
205
+ ctx.beginPath();
206
+ ctx.arc(x, y, 5, 0, 2 * Math.PI);
207
+ ctx.fill();
208
+
209
+ // Activer le bouton Segmentation
210
+ document.getElementById('segment-button').disabled = points.length === 0;
211
+ });
212
+
213
+ // Lancer la segmentation
214
+ document.getElementById('segment-button').addEventListener('click', () => {
215
+ const status = document.createElement('div');
216
+ status.className = 'status';
217
+ document.body.appendChild(status);
218
+
219
+ fetch('/segment', {
220
+ method: 'POST',
221
+ headers: { 'Content-Type': 'application/json' },
222
+ body: JSON.stringify({
223
+ image_name: "{{ uploaded_image }}",
224
+ points: points
225
+ })
226
+ })
227
+ .then(response => response.json())
228
+ .then(data => {
229
+ if (data.success) {
230
+ status.textContent = 'Segmentation terminée !';
231
+ status.classList.add('success');
232
+ const annotatedImg = document.getElementById('annotated-image');
233
+ annotatedImg.src = "{{ url_for('static', filename='') }}" + data.annotated_image;
234
+ annotatedImg.style.display = 'block';
235
+ } else {
236
+ status.textContent = 'Erreur : ' + data.error;
237
+ status.classList.add('error');
238
+ }
239
+ })
240
+ .catch(err => {
241
+ status.textContent = 'Erreur de réseau.';
242
+ status.classList.add('error');
243
+ console.error('Erreur:', err);
244
+ });
245
+ });
246
+ {% endif %}
247
+ </script>
248
+ </body>
249
+ </html>
templates/v5_index.html ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ <style>
9
+ body {
10
+ font-family: Arial, sans-serif;
11
+ margin: 20px;
12
+ background-color: #f9f9f9;
13
+ }
14
+
15
+ h1 {
16
+ text-align: center;
17
+ color: #333;
18
+ }
19
+
20
+ section {
21
+ margin: 20px 0;
22
+ padding: 20px;
23
+ background: #fff;
24
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
25
+ border-radius: 8px;
26
+ }
27
+
28
+ canvas {
29
+ border: 2px solid #ddd;
30
+ border-radius: 8px;
31
+ display: block;
32
+ margin: 20px auto;
33
+ }
34
+
35
+ button {
36
+ background-color: #4CAF50;
37
+ color: white;
38
+ border: none;
39
+ padding: 10px 20px;
40
+ font-size: 14px;
41
+ cursor: pointer;
42
+ border-radius: 5px;
43
+ transition: background-color 0.3s ease;
44
+ }
45
+
46
+ button:hover {
47
+ background-color: #45a049;
48
+ }
49
+
50
+ button:disabled {
51
+ background-color: #ccc;
52
+ cursor: not-allowed;
53
+ }
54
+
55
+ .upload-section {
56
+ text-align: center;
57
+ }
58
+
59
+ .class-management {
60
+ text-align: center;
61
+ }
62
+
63
+ .class-list {
64
+ display: flex;
65
+ flex-wrap: wrap;
66
+ gap: 10px;
67
+ justify-content: center;
68
+ list-style: none;
69
+ padding: 0;
70
+ }
71
+
72
+ .class-item {
73
+ padding: 5px 10px;
74
+ border-radius: 5px;
75
+ background-color: #f4f4f4;
76
+ border: 1px solid #ccc;
77
+ cursor: pointer;
78
+ transition: all 0.3s ease;
79
+ }
80
+
81
+ .class-item:hover {
82
+ background-color: #ddd;
83
+ }
84
+
85
+ .class-item.active {
86
+ background-color: #4CAF50;
87
+ color: white;
88
+ border-color: #45a049;
89
+ }
90
+
91
+ #annotated-image {
92
+ display: block;
93
+ max-width: 100%;
94
+ margin: 20px auto;
95
+ border: 2px solid #4CAF50;
96
+ border-radius: 8px;
97
+ }
98
+
99
+ .status {
100
+ text-align: center;
101
+ margin-top: 10px;
102
+ font-weight: bold;
103
+ }
104
+
105
+ .status.success {
106
+ color: #4CAF50;
107
+ }
108
+
109
+ .status.error {
110
+ color: #f44336;
111
+ }
112
+ </style>
113
+ </head>
114
+ <body>
115
+ <h1>Labélisation d'Images avec SAM</h1>
116
+
117
+ <!-- Section 1: Upload Image -->
118
+ <section class="upload-section">
119
+ <form method="post" enctype="multipart/form-data">
120
+ <label for="image">Télécharger une image :</label><br>
121
+ <input type="file" id="image" name="image" accept="image/*" required>
122
+ <br>
123
+ <button type="submit">Télécharger</button>
124
+ </form>
125
+ </section>
126
+
127
+ {% if uploaded_image %}
128
+ <!-- Section 2: Canvas for Image -->
129
+ <section>
130
+ <canvas id="image-canvas"></canvas>
131
+ </section>
132
+
133
+ <!-- Section 3: Annotated Image -->
134
+ <section>
135
+ <h2>Image Annotée</h2>
136
+ <img id="annotated-image" style="display: none;" alt="Image Annotée">
137
+ </section>
138
+
139
+ <!-- Section 4: Manage Classes -->
140
+ <section class="class-management">
141
+ <h3>Ajouter une classe :</h3>
142
+ <input type="text" id="class-name" placeholder="Entrez une classe">
143
+ <button id="add-class">Ajouter</button>
144
+ <h4>Classes disponibles :</h4>
145
+ <ul id="class-list" class="class-list"></ul>
146
+ </section>
147
+
148
+ <!-- Section 5: Controls -->
149
+ <section>
150
+ <div class="controls">
151
+ <button id="segment-button" disabled>Lancer la Segmentation</button>
152
+ </div>
153
+ </section>
154
+ {% endif %}
155
+
156
+ <script>
157
+ let canvas = document.getElementById('image-canvas');
158
+ let ctx = canvas ? canvas.getContext('2d') : null;
159
+ let points = [];
160
+ let currentClass = null;
161
+
162
+ {% if uploaded_image %}
163
+ // Charger l'image téléchargée
164
+ const img = new Image();
165
+ img.src = "{{ url_for('static', filename='uploads/' + uploaded_image) }}";
166
+ img.onload = () => {
167
+ canvas.width = img.width;
168
+ canvas.height = img.height;
169
+ ctx.drawImage(img, 0, 0);
170
+ };
171
+
172
+ // Gestion des classes
173
+ document.getElementById('add-class').addEventListener('click', () => {
174
+ const className = document.getElementById('class-name').value.trim();
175
+ if (!className) return;
176
+
177
+ const li = document.createElement('li');
178
+ li.textContent = className;
179
+ li.classList.add('class-item');
180
+ li.onclick = () => {
181
+ // Marquer la classe comme sélectionnée
182
+ document.querySelectorAll('.class-item').forEach(item => item.classList.remove('active'));
183
+ li.classList.add('active');
184
+ currentClass = className;
185
+ };
186
+
187
+ document.getElementById('class-list').appendChild(li);
188
+ document.getElementById('class-name').value = '';
189
+ });
190
+
191
+ // Ajouter un point sur le canvas
192
+ canvas.addEventListener('click', event => {
193
+ if (!currentClass) {
194
+ alert('Veuillez sélectionner une classe.');
195
+ return;
196
+ }
197
+
198
+ const rect = canvas.getBoundingClientRect();
199
+ const x = event.clientX - rect.left;
200
+ const y = event.clientY - rect.top;
201
+ points.push({ x, y, class: currentClass });
202
+
203
+ // Dessiner le point sur le canvas
204
+ ctx.fillStyle = 'red';
205
+ ctx.beginPath();
206
+ ctx.arc(x, y, 5, 0, 2 * Math.PI);
207
+ ctx.fill();
208
+
209
+ // Activer le bouton Segmentation
210
+ document.getElementById('segment-button').disabled = points.length === 0;
211
+ });
212
+
213
+ // Lancer la segmentation
214
+ document.getElementById('segment-button').addEventListener('click', () => {
215
+ const status = document.createElement('div');
216
+ status.className = 'status';
217
+ document.body.appendChild(status);
218
+
219
+ fetch('/segment', {
220
+ method: 'POST',
221
+ headers: { 'Content-Type': 'application/json' },
222
+ body: JSON.stringify({
223
+ image_name: "{{ uploaded_image }}",
224
+ points: points
225
+ })
226
+ })
227
+ .then(response => response.json())
228
+ .then(data => {
229
+ if (data.success) {
230
+ status.textContent = 'Segmentation terminée !';
231
+ status.classList.add('success');
232
+ const annotatedImg = document.getElementById('annotated-image');
233
+ annotatedImg.src = "{{ url_for('static', filename='') }}" + data.annotated_image;
234
+ annotatedImg.style.display = 'block';
235
+ } else {
236
+ status.textContent = 'Erreur : ' + data.error;
237
+ status.classList.add('error');
238
+ }
239
+ })
240
+ .catch(err => {
241
+ status.textContent = 'Erreur de réseau.';
242
+ status.classList.add('error');
243
+ console.error('Erreur:', err);
244
+ });
245
+ });
246
+ {% endif %}
247
+ </script>
248
+ </body>
249
+ </html>
templates/v6_index.html ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ <style>
9
+ body {
10
+ font-family: Arial, sans-serif;
11
+ margin: 20px;
12
+ background-color: #f9f9f9;
13
+ }
14
+
15
+ h1 {
16
+ text-align: center;
17
+ color: #333;
18
+ }
19
+
20
+ section {
21
+ margin: 20px 0;
22
+ padding: 20px;
23
+ background: #fff;
24
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
25
+ border-radius: 8px;
26
+ }
27
+
28
+ canvas {
29
+ border: 2px solid #ddd;
30
+ border-radius: 8px;
31
+ display: block;
32
+ margin: 20px auto;
33
+ }
34
+
35
+ button {
36
+ background-color: #4CAF50;
37
+ color: white;
38
+ border: none;
39
+ padding: 10px 20px;
40
+ font-size: 14px;
41
+ cursor: pointer;
42
+ border-radius: 5px;
43
+ transition: background-color 0.3s ease;
44
+ }
45
+
46
+ button:hover {
47
+ background-color: #45a049;
48
+ }
49
+
50
+ button:disabled {
51
+ background-color: #ccc;
52
+ cursor: not-allowed;
53
+ }
54
+
55
+ .upload-section, .class-management, .controls {
56
+ text-align: center;
57
+ }
58
+
59
+ .class-list {
60
+ display: flex;
61
+ flex-wrap: wrap;
62
+ gap: 10px;
63
+ justify-content: center;
64
+ list-style: none;
65
+ padding: 0;
66
+ }
67
+
68
+ .class-item {
69
+ padding: 5px 10px;
70
+ border-radius: 5px;
71
+ background-color: #f4f4f4;
72
+ border: 1px solid #ccc;
73
+ cursor: pointer;
74
+ transition: all 0.3s ease;
75
+ }
76
+
77
+ .class-item:hover {
78
+ background-color: #ddd;
79
+ }
80
+
81
+ .class-item.active {
82
+ background-color: #4CAF50;
83
+ color: white;
84
+ border-color: #45a049;
85
+ }
86
+
87
+ #annotated-image {
88
+ display: block;
89
+ max-width: 100%;
90
+ margin: 20px auto;
91
+ border: 2px solid #4CAF50;
92
+ border-radius: 8px;
93
+ }
94
+
95
+ .status {
96
+ text-align: center;
97
+ margin-top: 10px;
98
+ font-weight: bold;
99
+ }
100
+
101
+ .status.success {
102
+ color: #4CAF50;
103
+ }
104
+
105
+ .status.error {
106
+ color: #f44336;
107
+ }
108
+
109
+ .image-container {
110
+ display: flex;
111
+ justify-content: center;
112
+ flex-wrap: wrap;
113
+ gap: 10px;
114
+ margin: 20px 0;
115
+ }
116
+
117
+ .image-item {
118
+ width: 150px;
119
+ height: 150px;
120
+ object-fit: cover;
121
+ border: 2px solid #ddd;
122
+ border-radius: 8px;
123
+ cursor: pointer;
124
+ transition: all 0.3s ease;
125
+ }
126
+
127
+ /* Limite la taille des images téléchargées */
128
+ .image-item img {
129
+ max-width: 100%; /* S'adapte à la taille du conteneur */
130
+ max-height: 100%; /* Empêche de dépasser le conteneur */
131
+ border-radius: 8px;
132
+ object-fit: cover; /* Maintient le rapport d'aspect */
133
+ }
134
+
135
+ /* Taille fixe des conteneurs pour les images */
136
+ .image-item {
137
+ width: 150px;
138
+ height: 150px;
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+ overflow: hidden; /* Coupe les parties excédentaires */
143
+ border: 2px solid #ddd;
144
+ border-radius: 8px;
145
+ cursor: pointer;
146
+ transition: all 0.3s ease;
147
+ }
148
+
149
+ .image-item:hover {
150
+ border-color: #4CAF50;
151
+ }
152
+
153
+ /* Ajout pour le conteneur général des images téléchargées */
154
+ .image-container {
155
+ display: flex;
156
+ justify-content: center;
157
+ flex-wrap: wrap;
158
+ gap: 10px;
159
+ margin: 20px 0;
160
+ }
161
+ </style>
162
+ </head>
163
+ <body>
164
+ <h1>Labélisation d'Images avec SAM</h1>
165
+
166
+ <!-- Section 1: Upload Images -->
167
+ <section class="upload-section">
168
+ <form method="post" enctype="multipart/form-data">
169
+ <label for="image">Télécharger des images :</label><br>
170
+ <input type="file" id="image" name="images" accept="image/*" multiple required>
171
+ <br>
172
+ <button type="submit">Télécharger les images</button>
173
+ </form>
174
+ </section>
175
+
176
+ {% if uploaded_images %}
177
+ <!-- Section 2: Images déjà téléchargées -->
178
+ <section>
179
+ <h2>Images téléchargées</h2>
180
+ <div class="image-container">
181
+ {% for image in uploaded_images %}
182
+ <div class="image-item" onclick="loadImage('{{ image }}')">
183
+ <img src="{{ url_for('static', filename='uploads/' + image) }}" alt="{{ image }}">
184
+ </div>
185
+ {% endfor %}
186
+ </div>
187
+ </section>
188
+
189
+ <!-- Section 3: Canvas for Image Annotation -->
190
+ <section>
191
+ <canvas id="image-canvas"></canvas>
192
+ </section>
193
+
194
+ <!-- Section 4: Annotated Image -->
195
+ <section>
196
+ <h2>Image Annotée</h2>
197
+ <img id="annotated-image" style="display: none;" alt="Image Annotée">
198
+ </section>
199
+
200
+ <!-- Section 5: Manage Classes -->
201
+ <section class="class-management">
202
+ <h3>Ajouter une classe :</h3>
203
+ <input type="text" id="class-name" placeholder="Entrez une classe">
204
+ <button id="add-class">Ajouter</button>
205
+ <h4>Classes disponibles :</h4>
206
+ <ul id="class-list" class="class-list"></ul>
207
+ </section>
208
+
209
+ <!-- Section 6: Controls -->
210
+ <section>
211
+ <button id="finish-button" disabled>Terminer l'annotation</button>
212
+ <button id="segment-button" disabled>Lancer la Segmentation</button>
213
+ </section>
214
+ {% endif %}
215
+
216
+ <script>
217
+ let canvas = document.getElementById('image-canvas');
218
+ let ctx = canvas ? canvas.getContext('2d') : null;
219
+ let points = [];
220
+ let currentClass = null;
221
+ let img = null;
222
+ let imgWidth = 0;
223
+ let imgHeight = 0;
224
+
225
+ {% if uploaded_images %}
226
+ function loadImage(imageName) {
227
+ // Réinitialiser le tableau des points
228
+ points = [];
229
+ document.getElementById('finish-button').disabled = false;
230
+ document.getElementById('segment-button').disabled = true;
231
+
232
+ // Charger l'image sélectionnée
233
+ img = new Image();
234
+ img.src = "{{ url_for('static', filename='uploads/') }}" + imageName;
235
+
236
+ img.onload = () => {
237
+ imgWidth = img.width;
238
+ imgHeight = img.height;
239
+ canvas.width = imgWidth;
240
+ canvas.height = imgHeight;
241
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
242
+ ctx.drawImage(img, 0, 0);
243
+ };
244
+ }
245
+
246
+ // Gestion des classes
247
+ document.getElementById('add-class').addEventListener('click', () => {
248
+ const className = document.getElementById('class-name').value.trim();
249
+ if (!className) return;
250
+
251
+ const li = document.createElement('li');
252
+ li.textContent = className;
253
+ li.classList.add('class-item');
254
+ li.onclick = () => {
255
+ document.querySelectorAll('.class-item').forEach(item => item.classList.remove('active'));
256
+ li.classList.add('active');
257
+ currentClass = className;
258
+ };
259
+ document.getElementById('class-list').appendChild(li);
260
+
261
+ document.getElementById('class-name').value = '';
262
+ });
263
+
264
+ // Ajouter un point sur le canvas
265
+ canvas.addEventListener('click', event => {
266
+ if (!currentClass) {
267
+ alert('Veuillez sélectionner une classe.');
268
+ return;
269
+ }
270
+
271
+ const rect = canvas.getBoundingClientRect();
272
+ const x = event.clientX - rect.left;
273
+ const y = event.clientY - rect.top;
274
+
275
+ points.push({ x, y, class: currentClass });
276
+
277
+ ctx.fillStyle = 'red';
278
+ ctx.beginPath();
279
+ ctx.arc(x, y, 5, 0, 2 * Math.PI);
280
+ ctx.fill();
281
+
282
+ // Activer le bouton Segmentation
283
+ document.getElementById('segment-button').disabled = points.length === 0;
284
+ });
285
+
286
+ // Terminer l'annotation
287
+ document.getElementById('finish-button').addEventListener('click', () => {
288
+ alert("Annotation terminée pour cette image.");
289
+ document.getElementById('finish-button').disabled = true;
290
+ });
291
+
292
+ // Lancer la segmentation
293
+ document.getElementById('segment-button').addEventListener('click', () => {
294
+ fetch('/segment', {
295
+ method: 'POST',
296
+ headers: { 'Content-Type': 'application/json' },
297
+ body: JSON.stringify({
298
+ image_names: ["{{ uploaded_image }}"], // Passer l'image actuelle
299
+ points: points
300
+ })
301
+ })
302
+ .then(response => response.json())
303
+ .then(data => {
304
+ if (data.success) {
305
+ document.getElementById('annotated-image').src = "{{ url_for('static', filename='') }}" + data.annotated_image;
306
+ document.getElementById('annotated-image').style.display = 'block';
307
+ } else {
308
+ alert("Erreur : " + data.error);
309
+ }
310
+ })
311
+ .catch(err => {
312
+ console.error('Erreur:', err);
313
+ });
314
+ });
315
+ {% endif %}
316
+ </script>
317
+ </body>
318
+ </html>
templates/v7_multi_segmentation.html ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Labélisation d'Images avec SAM</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
8
+ <style>
9
+ /* General Styles */
10
+ body {
11
+ font-family: Arial, sans-serif;
12
+ margin: 0;
13
+ padding: 0;
14
+ background-color: #f4f4f4;
15
+ }
16
+
17
+ header {
18
+ background-color: #4CAF50;
19
+ padding: 15px 0;
20
+ text-align: center;
21
+ color: white;
22
+ font-size: 24px;
23
+ font-weight: bold;
24
+ }
25
+
26
+ section {
27
+ margin: 20px auto;
28
+ max-width: 1200px;
29
+ padding: 20px;
30
+ background: white;
31
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
32
+ border-radius: 8px;
33
+ }
34
+
35
+ .upload-section {
36
+ text-align: center;
37
+ }
38
+
39
+ .upload-section input[type="file"] {
40
+ margin: 10px 0;
41
+ }
42
+
43
+ .image-container {
44
+ display: flex;
45
+ flex-wrap: wrap;
46
+ gap: 20px;
47
+ justify-content: center;
48
+ }
49
+
50
+ .image-item {
51
+ width: 150px;
52
+ height: 150px;
53
+ overflow: hidden;
54
+ border: 2px solid #ddd;
55
+ border-radius: 8px;
56
+ cursor: pointer;
57
+ transition: transform 0.3s ease, border-color 0.3s ease;
58
+ display: flex;
59
+ justify-content: center;
60
+ align-items: center;
61
+ background-color: #fff;
62
+ }
63
+
64
+ .image-item:hover {
65
+ border-color: #4CAF50;
66
+ transform: scale(1.05);
67
+ }
68
+
69
+ .image-item img {
70
+ max-width: 100%;
71
+ max-height: 100%;
72
+ object-fit: cover;
73
+ }
74
+
75
+ canvas {
76
+ border: 2px solid #ddd;
77
+ border-radius: 8px;
78
+ margin: 20px auto;
79
+ display: block;
80
+ }
81
+
82
+ .class-management {
83
+ text-align: center;
84
+ margin-bottom: 20px;
85
+ }
86
+
87
+ .class-management input[type="text"] {
88
+ padding: 8px;
89
+ font-size: 16px;
90
+ width: 300px;
91
+ margin-right: 10px;
92
+ }
93
+
94
+ .class-list {
95
+ display: flex;
96
+ justify-content: center;
97
+ flex-wrap: wrap;
98
+ gap: 10px;
99
+ list-style: none;
100
+ padding: 0;
101
+ }
102
+
103
+ .class-item {
104
+ padding: 5px 15px;
105
+ border-radius: 20px;
106
+ background-color: #f4f4f4;
107
+ border: 1px solid #ccc;
108
+ cursor: pointer;
109
+ transition: all 0.3s ease;
110
+ }
111
+
112
+ .class-item:hover {
113
+ background-color: #ddd;
114
+ }
115
+
116
+ .class-item.active {
117
+ background-color: #4CAF50;
118
+ color: white;
119
+ border-color: #45a049;
120
+ }
121
+
122
+ .controls {
123
+ text-align: center;
124
+ margin-top: 20px;
125
+ }
126
+
127
+ button {
128
+ background-color: #4CAF50;
129
+ color: white;
130
+ border: none;
131
+ padding: 10px 20px;
132
+ font-size: 16px;
133
+ cursor: pointer;
134
+ border-radius: 5px;
135
+ transition: background-color 0.3s ease;
136
+ margin: 0 10px;
137
+ }
138
+
139
+ button:hover {
140
+ background-color: #45a049;
141
+ }
142
+
143
+ button:disabled {
144
+ background-color: #ccc;
145
+ cursor: not-allowed;
146
+ }
147
+
148
+ .result-section img {
149
+ max-width: 100%;
150
+ margin: 20px auto;
151
+ display: block;
152
+ border: 2px solid #4CAF50;
153
+ border-radius: 8px;
154
+ }
155
+ </style>
156
+ </head>
157
+ <body>
158
+ <header>Labélisation d'Images avec SAM</header>
159
+
160
+ <!-- Section 1: Téléchargement d'images -->
161
+ <section class="upload-section">
162
+ <h2>Télécharger vos images</h2>
163
+ <form method="post" enctype="multipart/form-data">
164
+ <input type="file" id="image" name="images" accept="image/*" multiple required>
165
+ <br>
166
+ <button type="submit">Télécharger</button>
167
+ </form>
168
+ </section>
169
+
170
+ {% if uploaded_images %}
171
+ <!-- Section 2: Galerie des images téléchargées -->
172
+ <section>
173
+ <h2>Images téléchargées</h2>
174
+ <div class="image-container">
175
+ {% for image in uploaded_images %}
176
+ <div class="image-item" onclick="loadImage('{{ image }}')">
177
+ <img src="{{ url_for('static', filename='uploads/' + image) }}" alt="{{ image }}">
178
+ </div>
179
+ {% endfor %}
180
+ </div>
181
+ </section>
182
+
183
+ <!-- Section 3: Zone de travail -->
184
+ <section>
185
+ <canvas id="image-canvas"></canvas>
186
+ </section>
187
+
188
+ <!-- Section 4: Gestion des classes -->
189
+ <section class="class-management">
190
+ <h3>Ajouter une classe</h3>
191
+ <input type="text" id="class-name" placeholder="Nom de la classe">
192
+ <button id="add-class">Ajouter</button>
193
+ <ul id="class-list" class="class-list"></ul>
194
+ </section>
195
+
196
+ <!-- Section 5: Contrôles -->
197
+ <section class="controls">
198
+ <button id="finish-button" disabled>Terminer l'annotation</button>
199
+ <button id="segment-button" disabled>Lancer la segmentation</button>
200
+ </section>
201
+ {% endif %}
202
+
203
+ <script>
204
+ let selectedImage = null; // Image actuellement sélectionnée
205
+ let annotations = {}; // Stocke les annotations de chaque image (clé : image, valeur : points)
206
+ let currentClass = null; // Classe actuellement sélectionnée
207
+ const finishButton = document.getElementById('finish-button');
208
+ const segmentButton = document.getElementById('segment-button');
209
+
210
+ function loadImage(imageName) {
211
+ if (!imageName) {
212
+ alert("Veuillez sélectionner une image !");
213
+ return;
214
+ }
215
+
216
+ selectedImage = imageName; // Stockez le nom de l'image sélectionnée
217
+ console.log("Image sélectionnée :", selectedImage);
218
+
219
+ // Initialiser les annotations pour cette image si elles n'existent pas
220
+ if (!annotations[selectedImage]) {
221
+ annotations[selectedImage] = [];
222
+ }
223
+
224
+ const img = new Image();
225
+ img.src = `/static/uploads/${imageName}`;
226
+ img.onload = () => {
227
+ const canvas = document.getElementById('image-canvas');
228
+ const ctx = canvas.getContext('2d');
229
+ canvas.width = img.width;
230
+ canvas.height = img.height;
231
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
232
+ ctx.drawImage(img, 0, 0);
233
+
234
+ // Dessiner les points existants pour cette image
235
+ annotations[selectedImage].forEach(point => {
236
+ drawPoint(ctx, point.x, point.y, point.class);
237
+ });
238
+ };
239
+
240
+ finishButton.disabled = false;
241
+ }
242
+
243
+ function drawPoint(ctx, x, y, pointClass) {
244
+ ctx.fillStyle = pointClass === 'arbre' ? 'green' : 'red';
245
+ ctx.beginPath();
246
+ ctx.arc(x, y, 5, 0, 2 * Math.PI);
247
+ ctx.fill();
248
+ }
249
+
250
+ document.getElementById('add-class').addEventListener('click', () => {
251
+ const className = document.getElementById('class-name').value.trim();
252
+ if (!className) {
253
+ alert("Veuillez entrer un nom de classe !");
254
+ return;
255
+ }
256
+ const li = document.createElement('li');
257
+ li.textContent = className;
258
+ li.classList.add('class-item');
259
+ li.onclick = () => {
260
+ document.querySelectorAll('.class-item').forEach(item => item.classList.remove('active'));
261
+ li.classList.add('active');
262
+ currentClass = className;
263
+ console.log("Classe sélectionnée :", currentClass);
264
+ };
265
+ document.getElementById('class-list').appendChild(li);
266
+ document.getElementById('class-name').value = '';
267
+ });
268
+
269
+ const canvas = document.getElementById('image-canvas');
270
+ const ctx = canvas.getContext('2d');
271
+
272
+ canvas.addEventListener('click', (event) => {
273
+ if (!currentClass) {
274
+ alert("Veuillez sélectionner une classe avant d'ajouter des points !");
275
+ return;
276
+ }
277
+
278
+ if (!selectedImage) {
279
+ alert("Veuillez sélectionner une image avant d'ajouter des points !");
280
+ return;
281
+ }
282
+
283
+ const rect = canvas.getBoundingClientRect();
284
+ const x = event.clientX - rect.left;
285
+ const y = event.clientY - rect.top;
286
+
287
+ const newPoint = { x, y, class: currentClass };
288
+ annotations[selectedImage].push(newPoint);
289
+ console.log(`Point ajouté pour ${selectedImage}:`, newPoint);
290
+
291
+ drawPoint(ctx, x, y, currentClass);
292
+ });
293
+
294
+ finishButton.addEventListener('click', () => {
295
+ if (!selectedImage) {
296
+ alert("Veuillez sélectionner une image !");
297
+ return;
298
+ }
299
+
300
+ console.log(`Annotation terminée pour ${selectedImage}.`);
301
+ alert(`Annotation pour ${selectedImage} terminée !`);
302
+
303
+ finishButton.disabled = true;
304
+
305
+ // Vérifiez si toutes les annotations sont terminées
306
+ if (Object.keys(annotations).length > 0) {
307
+ segmentButton.disabled = false;
308
+ }
309
+ });
310
+
311
+ segmentButton.addEventListener('click', () => {
312
+ const dataToSend = Object.keys(annotations).map(imageName => ({
313
+ image_name: imageName,
314
+ points: annotations[imageName]
315
+ }));
316
+
317
+ console.log("Données envoyées :", dataToSend);
318
+
319
+ fetch('/segment', {
320
+ method: 'POST',
321
+ headers: { 'Content-Type': 'application/json' },
322
+ body: JSON.stringify(dataToSend)
323
+ })
324
+ .then(response => response.json())
325
+ .then(data => {
326
+ console.log("Réponse du backend :", data);
327
+ if (data.success) {
328
+ alert("Segmentation réussie !");
329
+ } else {
330
+ alert("Erreur : " + data.error);
331
+ }
332
+ })
333
+ .catch(err => console.error('Erreur lors de la segmentation :', err));
334
+ });
335
+ </script>
336
+ </body>
337
+ </html>
yolo_training.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ from pathlib import Path
3
+ pathlib.PosixPath = pathlib.WindowsPath
4
+ import sys
5
+ import os
6
+
7
+ # Ajoutez le chemin du répertoire YOLOv5 au sys.path pour pouvoir importer train.py
8
+ BASE_DIR = Path(__file__).resolve().parent
9
+ YOLOV5_DIR = BASE_DIR / "yolov5"
10
+ sys.path.append(str(YOLOV5_DIR))
11
+
12
+ from yolov5.train import main, parse_opt # Importation directe des fonctions nécessaires
13
+
14
+ # Définir les chemins et options
15
+ MODEL_PATH = BASE_DIR / "models/models--keizer77--samyolo2/snapshots/74c8cb12ae448ff0b8bae9ef522b54ec09b47c20/best.pt"
16
+ DATA_YAML_PATH = BASE_DIR / "labelid_image/data.yaml" #
17
+ OUTPUT_DIR = BASE_DIR / "weights"
18
+
19
+ def clear_cache(data_path):
20
+ """
21
+ Supprime les fichiers de cache de labels pour s'assurer que YOLOv5
22
+ recrée les caches à partir des fichiers d'annotation actuels.
23
+ """
24
+ subfolders = ['train', 'valid', 'test']
25
+ for folder in subfolders:
26
+ cache_file = os.path.join(data_path, folder, 'labels.cache')
27
+ if os.path.exists(cache_file):
28
+ print(f"Suppression du cache : {cache_file}")
29
+ os.remove(cache_file)
30
+
31
+ def train_yolo_direct():
32
+ # Nettoyer le cache avant l'entraînement
33
+ clear_cache("labelid_image")
34
+
35
+ # Préparer les options pour l'entraînement
36
+ opt = parse_opt()
37
+ opt.imgsz = 640
38
+ opt.batch_size = 8
39
+ opt.epochs = 10
40
+ opt.data = str(DATA_YAML_PATH)
41
+ opt.weights = str(MODEL_PATH)
42
+ opt.project = str(OUTPUT_DIR)
43
+ opt.name = "custom_model"
44
+ opt.device = "cpu" # Spécifier le périphérique (CPU ou GPU)
45
+
46
+ print("Lancement de l'entraînement YOLOv5...")
47
+ main(opt)
48
+
49
+ if __name__ == "__main__":
50
+ try:
51
+ train_yolo_direct()
52
+ except Exception as e:
53
+ print(f"Erreur lors de l'exécution de l'entraînement : {e}")
yolo_training_v1.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ from pathlib import Path
3
+ pathlib.PosixPath = pathlib.WindowsPath
4
+ import sys
5
+
6
+ # Ajoutez le chemin du répertoire YOLOv5 au sys.path pour pouvoir importer train.py
7
+ BASE_DIR = Path(__file__).resolve().parent
8
+ YOLOV5_DIR = BASE_DIR / "yolov5"
9
+ sys.path.append(str(YOLOV5_DIR))
10
+
11
+ from yolov5.train import main, parse_opt # Importation directe des fonctions nécessaires
12
+
13
+ # Définir les chemins et options
14
+ MODEL_PATH = BASE_DIR / "models/models--keizer77--samyolo2/snapshots/74c8cb12ae448ff0b8bae9ef522b54ec09b47c20/best.pt"
15
+ DATA_YAML_PATH = BASE_DIR / "labelid_image/data.yaml"
16
+ OUTPUT_DIR = BASE_DIR / "weights"
17
+
18
+ def train_yolo_direct():
19
+ # Préparer les options pour l'entraînement
20
+ opt = parse_opt()
21
+ opt.imgsz = 640
22
+ opt.batch_size = 16
23
+ opt.epochs = 10
24
+ opt.data = str(DATA_YAML_PATH)
25
+ opt.weights = str(MODEL_PATH)
26
+ opt.project = str(OUTPUT_DIR)
27
+ opt.name = "custom_model"
28
+ opt.device = "cpu" # Spécifier le périphérique (CPU ou GPU)
29
+
30
+ # Appeler directement la fonction d'entraînement
31
+ print("Lancement de l'entraînement YOLOv5...")
32
+ main(opt)
33
+
34
+ if __name__ == "__main__":
35
+ try:
36
+ train_yolo_direct()
37
+ except Exception as e:
38
+ print(f"Erreur lors de l'exécution de l'entraînement : {e}")