import streamlit as st
import cv2
import numpy as np
from PIL import Image
from io import BytesIO
import barcode
from barcode.writer import ImageWriter
import qrcode
import tempfile
def image_to_bytes(img):
pil_image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
buffer = BytesIO()
pil_image.save(buffer, format="PNG")
return buffer.getvalue()
def generate_barcode(link):
code128 = barcode.get_barcode_class('code128')
barcode_image = code128(link, writer=ImageWriter())
buffer = BytesIO()
barcode_image.write(buffer)
return Image.open(buffer)
def generate_qrcode(link):
qr = qrcode.QRCode(
version=2,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=4,
border=2,
)
qr.add_data(link)
qr.make(fit=True)
qr_image = qr.make_image(fill_color="black", back_color="white")
small_qr_image = qr_image.resize((512, 512), Image.Resampling.LANCZOS)
buffer = BytesIO()
small_qr_image.save(buffer, format="PNG")
return Image.open(buffer)
def add_custom_css():
css = """
"""
st.markdown(css, unsafe_allow_html=True)
def add_custom_js():
js = """
"""
st.markdown(js, unsafe_allow_html=True)
def main():
st.set_page_config(page_title="ADS VISOR - Un autre regard", layout="wide")
add_custom_css()
add_custom_js()
logo_path = "logo.jpg"
logo = Image.open(logo_path)
st.image(logo, width=150, caption="ADS VISOR")
st.title("ADS VISOR - Un autre regard")
st.sidebar.header("Chargement de l'image")
if "default_image" not in st.session_state:
st.session_state["default_image"] = None
uploaded_file = st.sidebar.file_uploader("Charge une image", type=["png", "jpg", "jpeg"])
if uploaded_file is not None:
image = Image.open(uploaded_file)
st.session_state["default_image"] = np.array(image)
st.sidebar.image(image, caption="Image par défaut", use_container_width=True)
if st.session_state["default_image"] is None:
st.sidebar.warning("Veuillez charger une image pour commencer.")
return
st.sidebar.header("Fonctionnalités")
menu_option = st.sidebar.selectbox(
"Choisissez une fonctionnalité",
["Accueil", "Niveaux de couleurs", "Cropping", "Rotation", "Floutage", "Contours", "Génération de Code-barres et QR Code", "Détection Faciale", "À propos de nous"],
format_func=lambda x: {
"Accueil": "🏠 Accueil",
"Niveaux de couleurs": "🖼️ Niveaux de couleurs",
"Cropping": "✂️ Cropping",
"Rotation": "🔄 Rotation",
"Floutage": "🌫️ Floutage",
"Contours": "🔍 Contours",
"Génération de Code-barres et QR Code": "📇 Codes numériques",
"Détection Faciale": "🙂 Détection Faciale",
"À propos de nous": "👨💻 À propos de nous"
}.get(x, x)
)
image_np = st.session_state["default_image"]
if menu_option == "Accueil":
st.header("Bienvenue sur ADS VISOR")
st.markdown(
"""
ADS VISOR est une application innovante pour analyser, transformer et explorer vos images. 🖼️✨
Que vous soyez un professionnel ou un passionné, découvrez un large éventail de fonctionnalités interactives !
- Transformations d'image : Couleurs, niveaux de gris, etc.
- Découpage & Rotation : Ajustez vos images à la perfection.
- Détection Faciale : Identifiez les visages automatiquement.
- Codes-barres & QR Codes : Génération rapide pour vos projets.
""",
unsafe_allow_html=True
)
# Niveaux de couleurs
elif menu_option == "Niveaux de couleurs":
st.subheader("Niveaux de couleurs")
# Instructions générales sur les niveaux de couleurs
st.markdown("""
### Légende : Fonctionnement des niveaux de couleurs
- **Les niveaux de couleurs** permettent de manipuler les différentes composantes d'une image : **Rouge**, **Vert**, **Bleu**.
- L'édition des canaux colorimétriques permet de visualiser une image en mettant en valeur une couleur spécifique.
### Options disponibles :
- **Niveaux de Gris** : Convertit l'image en une seule nuance de gris, supprimant les informations de couleur.
- **Rouge** : Filtre l'image pour ne conserver que la composante rouge.
- **Vert** : Filtre l'image pour ne conserver que la composante verte.
- **Jaune** : Combine les composantes rouge et verte pour donner une teinte jaune.
### Exemple :
- Si vous choisissez l'option **Rouge**, vous obtiendrez une image où seules les nuances rouges sont visibles, les autres couleurs étant supprimées.
""")
# Création des onglets pour afficher les images dans différentes couleurs
tab1, tab2, tab3, tab4 = st.tabs([
"Gris 🖤", "Rouge ❤️", "Vert 💚", "Jaune 💛"
])
# Onglet 1 : Gris
with tab1:
gray_image = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)
st.image(gray_image, caption="Image en Niveaux de Gris", use_container_width=True)
st.download_button(
label="Télécharger l'image en gris",
data=image_to_bytes(gray_image),
file_name="image_gris.png",
mime="image/png"
)
# Onglet 2 : Rouge
with tab2:
red = image_np.copy()
red[:, :, 1:] = 0 # On met les canaux vert et bleu à zéro
st.image(red, caption="Image Rouge", use_container_width=True)
st.download_button(
label="Télécharger l'image rouge",
data=image_to_bytes(red),
file_name="image_rouge.png",
mime="image/png"
)
# Onglet 3 : Vert
with tab3:
green = image_np.copy()
green[:, :, [0, 2]] = 0 # On met les canaux rouge et bleu à zéro
st.image(green, caption="Image Verte", use_container_width=True)
st.download_button(
label="Télécharger l'image verte",
data=image_to_bytes(green),
file_name="image_verte.png",
mime="image/png"
)
# Onglet 4 : Jaune
with tab4:
yellow = image_np.copy()
yellow[:, :, 0] = 0 # On supprime la composante bleue
st.image(yellow, caption="Image Jaune", use_container_width=True)
st.download_button(
label="Télécharger l'image jaune",
data=image_to_bytes(yellow),
file_name="image_jaune.png",
mime="image/png"
)
elif menu_option == "Cropping":
st.subheader("Cropping - Recadrage d'Image")
# Explications pour les paramètres
st.markdown(
"""
### Légende : Fonctionnement du recadrage
Le recadrage d'une image consiste à extraire une portion rectangulaire de celle-ci. Pour cela, nous définissons les coordonnées des coins du rectangle :
- **`x1` (Coordonnée x du coin supérieur gauche)** : Position horizontale du début du rectangle (0 ≤ `x1` < largeur-1).
- **`y1` (Coordonnée y du coin supérieur gauche)** : Position verticale du début du rectangle (0 ≤ `y1` < hauteur-1).
- **`x2` (Coordonnée x du coin inférieur droit)** : Position horizontale de la fin du rectangle (1 ≤ `x2` ≤ largeur).
- **`y2` (Coordonnée y du coin inférieur droit)** : Position verticale de la fin du rectangle (1 ≤ `y2` ≤ hauteur).
### Exemple illustratif :
Imaginons que vous avez une image de 300x300 pixels. Si vous entrez `x1=50`, `y1=50`, `x2=200`, et `y2=200`, l'image sera recadrée en un rectangle de taille 150x150 pixels, commençant à partir du pixel (50, 50) jusqu'à (200, 200).
### Étapes :
1. Saisissez les coordonnées du rectangle que vous souhaitez extraire.
2. Vous verrez une prévisualisation de la zone sélectionnée avant de la confirmer.
3. Téléchargez l'image recadrée.
"""
)
# Entrée des coordonnées
try:
x1 = st.number_input("x1 (Coordonnée x du coin supérieur gauche)", 0, image_np.shape[1] - 1, step=1)
y1 = st.number_input("y1 (Coordonnée y du coin supérieur gauche)", 0, image_np.shape[0] - 1, step=1)
x2 = st.number_input("x2 (Coordonnée x du coin inférieur droit)", 1, image_np.shape[1], step=1)
y2 = st.number_input("y2 (Coordonnée y du coin inférieur droit)", 1, image_np.shape[0], step=1)
# Validation des coordonnées
if x1 >= x2:
st.error("`x2` doit être strictement supérieur à `x1`. Veuillez corriger vos entrées.")
elif y1 >= y2:
st.error("`y2` doit être strictement supérieur à `y1`. Veuillez corriger vos entrées.")
else:
# Calcul des dimensions du recadrage
cropped_width = x2 - x1
cropped_height = y2 - y1
# Bouton pour générer l'image recadrée
if st.button("Générer le Recadrage"):
# Recadrage de l'image
cropped = image_np[int(y1):int(y2), int(x1):int(x2)]
# Affichage de l'image recadrée
st.image(cropped, caption="Image Croppée", use_container_width=True)
# Affichage des informations sur la taille du rectangle
st.write(f"Le rectangle recadré mesure {cropped_width} pixels de large et {cropped_height} pixels de haut.")
# Bouton de téléchargement pour l'image recadrée
st.download_button(
label="⬇️ Télécharger l'image croppée",
data=image_to_bytes(cropped),
file_name="image_cropped.png",
mime="image/png"
)
except Exception as e:
st.error(f"Une erreur est survenue : {e}")
# Rotation
elif menu_option == "Rotation":
st.subheader("Rotation")
# Instructions sur la rotation
st.markdown("""
### Légende : Fonctionnement de la rotation
- La **rotation** d'une image consiste à tourner l'image autour de son centre selon un angle défini.
- Vous pouvez choisir un angle prédéfini pour faire pivoter l'image à gauche ou à droite.
### Options disponibles :
- Choisissez un angle parmi les options proposées : **45°, 90° ou 180°**.
- L'image sera ensuite tournée dans le sens des aiguilles d'une montre.
### Exemple :
- Si vous choisissez un angle de **90°**, l'image sera pivotée de 90 degrés dans le sens des aiguilles d'une montre par rapport à son centre.
""")
# Sélection de l'angle de rotation
angle = st.selectbox("Angle de rotation", [45, 90, 180])
# Calcul des dimensions et application de la rotation
rows, cols, _ = image_np.shape
rotation_matrix = cv2.getRotationMatrix2D((cols / 2, rows / 2), angle, 1)
rotated = cv2.warpAffine(image_np, rotation_matrix, (cols, rows))
# Affichage de l'image après rotation
st.image(rotated, caption=f"Image Rotée de {angle} degrés", use_container_width=True)
# Bouton de téléchargement pour l'image rotée
st.download_button(
label="Télécharger l'image rotée",
data=image_to_bytes(rotated),
file_name=f"image_rotated_{angle}.png",
mime="image/png"
)
# Floutage
elif menu_option == "Floutage":
st.subheader("Floutage")
# Instructions sur le floutage
st.markdown("""
### Légende : Fonctionnement du floutage
- Le **floutage** est utilisé pour adoucir une image en réduisant les détails fins, ce qui est utile pour l'anonymisation ou pour appliquer des effets esthétiques.
- Vous pouvez ajuster l'intensité du flou en fonction du niveau choisi.
### Options disponibles :
- Le **Niveau de flou (k)** détermine l'intensité du flou appliqué. Plus la valeur est élevée, plus l'image sera floutée.
- Les valeurs sont comprises entre 1 (très léger flou) et 51 (flou maximal), et doivent être des nombres impairs.
### Exemple :
- Si vous choisissez **k = 15**, l'image sera floutée de manière modérée, et vous pourrez voir l'effet de réduction de détails.
""")
# Sélection du niveau de flou
blur_level = st.slider("Niveau de flou (k)", min_value=1, max_value=51, step=2, value=15)
# Application du flou sur l'image
blurred = cv2.GaussianBlur(image_np, (blur_level, blur_level), 0)
# Affichage de l'image floutée
st.image(blurred, caption=f"Image Floutée (k={blur_level})", use_container_width=True)
# Bouton de téléchargement pour l'image floutée
st.download_button(
label="Télécharger l'image floutée",
data=image_to_bytes(blurred),
file_name=f"image_blurred_k{blur_level}.png",
mime="image/png"
)
# Détection des contours
elif menu_option == "Contours":
st.subheader("Contours")
# Instructions sur la détection des contours
st.markdown("""
### Légende : Fonctionnement de la détection de contours
- La **détection de contours** consiste à identifier les bords distincts de l'image, ce qui permet de mieux comprendre les structures présentes.
- Elle est souvent utilisée dans des traitements d'image avancés comme la reconnaissance d'objets ou l'analyse d'images.
### Options disponibles :
- L'image sera convertie en niveaux de gris, et ensuite un algorithme de détection de contours (Canny) sera appliqué pour extraire les bords de l'image.
- Cela permet de visualiser les contours dans des images complexes.
### Exemple :
- Après l'application de l'algorithme Canny, l'image ne contient que les contours des objets, ce qui peut être utilisé pour détecter des formes, des objets ou d'autres détails visuels importants.
""")
# Conversion de l'image en niveaux de gris pour la détection des contours
gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200)
# Affichage de l'image avec les contours détectés
st.image(edges, caption="Contours de l'Image", use_container_width=True)
# Bouton de téléchargement pour l'image avec contours
st.download_button(
label="Télécharger l'image avec contours",
data=image_to_bytes(edges),
file_name=f"image_edges.png",
mime="image/png"
)
elif menu_option == "Génération de Code-barres et QR Code":
st.subheader("Génération de Code-barres et QR Code")
# Légende pour guider l'utilisateur
st.markdown(
"""
🔄 **Instructions :**
1. Saisis un lien ou un texte dans le champ ci-dessous.
2. Accède à l'onglet souhaité pour générer un **Code-barres** 📊 ou un **QR Code** 📱.
3. Clique sur le bouton **"Générer"** pour voir le résultat et utilise le bouton **⬇️ Télécharger** pour sauvegarder l'image.
"""
)
# Gestion de l'entrée utilisateur avec sauvegarde dans session_state
if "link" not in st.session_state:
st.session_state["link"] = ""
# Entrée utilisateur
link = st.text_input("🔗 Entre un lien ou un texte pour générer les codes", value=st.session_state["link"])
if link:
st.session_state["link"] = link
# Création des onglets
tab1, tab2 = st.tabs(["📊 Code-barres", "📱 QR Code"])
# Onglet Code-barres
with tab1:
st.header("📊 Génération de Code-barres")
if st.button("Générer le Code-barres"):
if st.session_state["link"]:
try:
# Génération du code-barres
barcode_image = generate_barcode(st.session_state["link"])
st.image(barcode_image, caption="Code-barres généré", use_container_width=True)
# Bouton de téléchargement avec icône
barcode_buffer = BytesIO()
barcode_image.save(barcode_buffer, format="PNG")
barcode_buffer.seek(0)
st.download_button(
label="⬇️ Télécharger le Code-barres",
data=barcode_buffer,
file_name="barcode.png",
mime="image/png"
)
except Exception as e:
st.error(f"Une erreur est survenue lors de la génération : {e}")
else:
st.warning("⚠️ Veuillez entrer un lien ou un texte valide.")
# Onglet QR Code
with tab2:
st.header("📱 Génération de QR Code")
if st.button("Générer le QR Code"):
if st.session_state["link"]:
try:
# Génération du QR Code
qrcode_image = generate_qrcode(st.session_state["link"])
st.image(qrcode_image, caption="QR Code généré", use_container_width=True)
# Bouton de téléchargement avec icône
qrcode_buffer = BytesIO()
qrcode_image.save(qrcode_buffer, format="PNG")
qrcode_buffer.seek(0)
st.download_button(
label="⬇️ Télécharger le QR Code",
data=qrcode_buffer,
file_name="qrcode.png",
mime="image/png"
)
except Exception as e:
st.error(f"Une erreur est survenue lors de la génération : {e}")
else:
st.warning("⚠️ Veuillez entrer un lien ou un texte valide.")
elif menu_option == "Détection Faciale":
st.subheader("Détection Faciale")
# Sélectionner la source de l'image
source_option = st.radio("Choisissez la source", ("Image Importée", "Autre Image", "Webcam", "Vidéo"))
# Charger le classificateur de visages pré-entrainé de OpenCV
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
if source_option == "Image Importée":
if st.session_state["default_image"] is not None:
img = image_np
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# Dessiner des rectangles autour des visages
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
st.image(img, caption="Image avec Visages Détectés", use_container_width=True)
elif source_option == "Autre Image":
uploaded_file_2 = st.file_uploader("Charge une autre image", type=["png", "jpg", "jpeg"])
if uploaded_file_2 is not None:
image_2 = Image.open(uploaded_file_2)
img = np.array(image_2)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# Dessiner des rectangles autour des visages
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
st.image(img, caption="Autre Image avec Visages Détectés", use_container_width=True)
elif source_option == "Webcam":
stframe = st.empty()
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
st.write("Erreur dans la lecture de la webcam.")
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# Dessiner des rectangles autour des visages
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
# Affichage dans le streamlit
stframe.image(frame, channels="BGR", use_container_width=True)
if cv2.waitKey(1) & 0xFF == ord("q"): # Quitter avec la touche 'q'
break
cap.release()
elif source_option == "Vidéo":
video_file = st.file_uploader("Charge une vidéo", type=["mp4", "avi", "mov"])
if video_file is not None:
video_bytes = video_file.read()
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
tmp_file.write(video_bytes)
video_path = tmp_file.name
cap = cv2.VideoCapture(video_path)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# Dessiner des rectangles autour des visages
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
st.image(frame, caption="Vidéo avec Visages Détectés", use_container_width=True)
cap.release()
elif menu_option == "À propos de nous":
st.header("À propos de nous")
st.markdown(
"""
Notre équipe
Nous sommes une équipe passionnée travaillant sur des solutions innovantes.
""",
unsafe_allow_html=True
)
if __name__ == "__main__":
main()