This commit is contained in:
telereview
2023-03-27 09:16:56 +02:00
23 changed files with 74 additions and 40 deletions

View File

@@ -1,59 +0,0 @@
import cv2
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_face_mesh = mp.solutions.face_mesh
drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
cap = cv2.VideoCapture(0)
with mp_face_mesh.FaceMesh(
max_num_faces=1,
refine_landmarks=True,
min_detection_confidence=0.5,
min_tracking_confidence=0.5) as face_mesh:
while cap.isOpened():
success, image = cap.read()
if not success:
print("Ignoring empty camera frame.")
continue
# Initialize the face mesh model
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=False, max_num_faces=1, min_detection_confidence=0.5)
# Load the input image
# lecture de la vidéo
ret, frame = cap.read()
# conversion de l'image en RGB
image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Process the image and extract the landmarks
results = face_mesh.process(image)
if results.multi_face_landmarks:
landmarks = results.multi_face_landmarks[0]
# Define the landmark indices for the corners of the eyes and the tip of the nose
left_eye = [33, 133, 246, 161, 160, 159, 158, 157, 173, 133]
right_eye = [362, 263, 373, 380, 381, 382, 384, 385, 386, 362]
nose_tip = 4
# Calculate the distance between the eyes and the nose tip
left_eye_x = landmarks.landmark[left_eye[0]].x * image.shape[1]
right_eye_x = landmarks.landmark[right_eye[0]].x * image.shape[1]
nose_x = landmarks.landmark[nose_tip].x * image.shape[1]
eye_distance = abs(left_eye_x - right_eye_x)
nose_distance = abs(nose_x - (left_eye_x + right_eye_x) / 2)
# Determine the gender based on the eye and nose distances
if eye_distance > 1.5 * nose_distance:
gender = "Female"
else:
gender = "Male"
# Draw the landmarks on the image
cv2.putText(image, gender, (10, 50),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# affichage de la vidéo
cv2.imshow('Video', cv2.cvtColor(image, cv2.COLOR_RGB2BGR))
if cv2.waitKey(10) & 0xFF == ord('q'):
break
# libération de la caméra et des ressources
cap.release()
cv2.destroyAllWindows()

View File

@@ -1,88 +0,0 @@
import cv2
import numpy as np
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
def prodScalaire(V1,V2):
return V1[0]*V2[0]+V1[1]*V2[1]/(np.sqrt(V1[0]**2+V1[1]**2)*np.sqrt(V2[0]**2+V2[1]**2))
def reconnaissancePouce(handLandmarks):
etatDuPouce=["neutre","baissé","levé"]
i=0
j=0
for cpt in range (0,4):
V1=[handLandmarks[(4*cpt)+6][0]-handLandmarks[(4*cpt)+5][0],handLandmarks[(4*cpt)+6][1]-handLandmarks[(4*cpt)+5][1]]
V2=[handLandmarks[(4*cpt)+8][0]-handLandmarks[(4*cpt)+6][0],handLandmarks[(4*cpt)+8][1]-handLandmarks[(4*cpt)+6][1]]
j=np.dot(V1,V2)
if (j>0.005):
return etatDuPouce[0]
V1=[handLandmarks[4][0]-handLandmarks[1][0],handLandmarks[4][1]-handLandmarks[1][1]]
V2=[handLandmarks[2][0]-handLandmarks[1][0],handLandmarks[2][1]-handLandmarks[1][1]]
if((np.dot(V1,V2))>0 and (handLandmarks[4][1]>handLandmarks[2][1])):
i=1
elif(np.dot(V1,V2)>0 and handLandmarks[4][1]<handLandmarks[2][1]):
i=2
return etatDuPouce[i]
cap = cv2.VideoCapture(0)
with mp_hands.Hands(
model_complexity=0,
min_detection_confidence=0.5,
min_tracking_confidence=0.5) as hands:
while cap.isOpened():
success, image = cap.read()
if not success:
print("Ignoring empty camera frame.")
# If loading a video, use 'break' instead of 'continue'.
continue
# To improve performance, optionally mark the image as not writeable to
# pass by reference.
image.flags.writeable = False
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
results = hands.process(image)
# Draw the hand annotations on the image.
image.flags.writeable = True
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
mp_drawing.draw_landmarks(
image,
hand_landmarks,
mp_hands.HAND_CONNECTIONS,
mp_drawing_styles.get_default_hand_landmarks_style(),
mp_drawing_styles.get_default_hand_connections_style())
# Set variable to keep landmarks positions (x and y)
handLandmarks = []
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
# Fill list with x and y positions of each landmark
for landmarks in hand_landmarks.landmark:
handLandmarks.append([landmarks.x, landmarks.y])
cv2.putText(image, reconnaissancePouce(handLandmarks), (50, 450), cv2.FONT_HERSHEY_SIMPLEX, 3, (255, 0, 0), 10)
# Flip the image horizontally for a selfie-view display.
cv2.imshow('MediaPipe Hands', cv2.flip(image, 1))
if cv2.waitKey(5) & 0xFF == 27:
break
cap.release()
""" etatDuPouce=["neutre","baissé","levé"]
i=0
if results.multi_hand_landmarks:
if(results.multi_hand_landmarks.gestures.categories[0].categoryName==Thumb_Up):
cv2.putText(image, str(results.multi_hand_landmarks.gestures.categories[0].categoryName), (50, 450), cv2.FONT_HERSHEY_SIMPLEX, 3, (255, 0, 0), 10)
else:
cv2.putText(image, "raté", (50, 450), cv2.FONT_HERSHEY_SIMPLEX, 3, (255, 0, 0), 10)
"""

View File

@@ -1,113 +0,0 @@
Arrivée à 10h30 nous avons été accueillis très grossièrement une agente d'accueil de Securitas
(au niveau escalator montant vers richelieu) qui n'a pas regardé la carte handicapé de mon épouse
heureusement qui il y avait un responsable au dessus qui lui c'est rendu compte et est venu nous
faire accéder. Travaillant moi même dans la sécurité d'un public je trouve ça inadmissible
et lamentable à 1 an des JO de Paris.
//Beau musée,mais ne se renouvelle pas.
Ça fait 15 fois que j y vais depuis des années.
Belles pièces mais l orientation toujours aussi bordélique. Heureusement que des surveillants sympa sont là.
Ne pas oublier que le Louvre est un ancien Palais Royal et son histoire est un peu laissée de côté… dommage.
Parking un peu cher sous le Louvre.
Déçue dès boutique du carrousel.
//7h de visite non stop pour un musée extraordinaire. On apprécié les tableaux bien sûr mais aussi les plafonds,
les escaliers, les objets, les sculptures. Quelle grandeur ! Le musée reste très abordable pour ce qu'il renferme
comparé à d'autres musées dans le monde. Vive la France et vive Le Louvre !
//J'ai beaucoup apprécié les expositions de ce musée si réputé.Il n'a pas été possible de tout visiter en un seul jour.
Il y a trop d'escaliers et pas mal de pas pour accéder aux salles de visites,du coup trop de perte de temps.
Si non tout est fabuleux et émouvant.J'espère pouvoir y revenir.
//Je n'ai jamais pu visiter le musée du Louvre, et, en week-end avec des amies, on en a profiter,
surtout que c'était le premier week-end du mois, donc entrée gratuite.
Arrivée devant, incroyable, les pyramides sont magnifiques et le bâtiment les entourant l'est encore plus.
Malheureusement, on a vite déchanter quand un membre du personnel nous a annoncé que c'était gratuit uniquement jusqu'à 26 ans.
Quitte à ce que ce soit gratuit une fois dans le mois, autant que ça soit gratuit pour tout le monde,
ça changera pas grand chose au chiffre d'affaires.
Très déçue, c'est dommage.
//Le musée est magnifique, c'est un peu compliqué de s'orienter dedans. Plus d'indications ne serait pas de trop.
Ce qui a diminué la note est : le personnel. Très désagréable, s'attend à ce qu'on comprenne ce qu'ils veulent
sans ouvrir la bouche et formuler leur demande. Pas de bonjour, que des gestes ou ordres hurlés. De quoi miner une visite...
//Jai payé 2 entrées adultes au Musée du Louvre. Après maintes mails avec confirmation de la réservation,
nous navons pas reçu les billets par mail.
Nous avons dû payer encore une fois les billets pour réaliser la visite! Entrées 2 fois moins chères sur place!
Remboursement demandé, on va voir si la demande va aboutir !
//La multitude de touristes n'hésitant pas à faire longuement la queue avant d'entrer dans ce musée prestigieux
ne fait que confirmer, à juste titre, son incroyable attractivité, sans cesse renouvelée au fil des ans !
Plusieurs visites sont indispensables pour en profiter !
Une pure merveille !
//Expérience très désagréable au Louvre début janvier 2023 : beaucoup, beaucoup trop de monde, admis puisquil
faut réserver ( et payer) préalablement. File dattente interminable avant de passer le contrôle de sécurité,
file pour obtenir un casier, file pour valider son ticket, file pour voir certaines œuvres.
Deux adultes avec 3 enfants entre 5 et 11 ans et impossible de profiter un minimum car il faut se frayer un chemin,
ne pas perdre les enfants, admirer les œuvres dart. Nos enfants nont quasi rien retenu si ce nest la foule.
Dommage que ce haut lieu de culture cultive surtout la rentabilité !
//Quelques expositions- pas très bien indiqué- la seconde partie introuvable!
Il serait bon de mieux indiquer toutes les parties de lexposition- la recherche était fatigante!
//il est mon musée favori, j'adore ce lieu, vous pouvez très bien passer des heures devants un tableau
loin de tout ce qui est touristique tels que Mona lissa, il est franchement agréable a visiter.
//Des soucis pour s'orienter (changer de bâtiment est parfois compliqué). Grande richesse de la collection.
Personnel dans les salles très serviable.
//Tout simplement grandiose ! Allez-y même si vous ne connaissez rien à la culture… peintures, sculptures,
objets darts, rien ne manque
//Le titre se suffit à lui-même, l'art est précieux et admirable, mais il fait assez chaud et c'est très grand,
du genre, très très très grand: un conseil ne faites pas la queue devant la pyramide, entrez par le carroussel du louvre <3
//Superbe musée, passionnant , ce voyage dans l art et dans l histoire est un pure moment de poésie !
De nombreuses collections, avec une partie sur la Grèce antique et l Égypte très attractives pour les
jeunes enfants à partir de 4ans . Le musée est très grand , avec des enfants en bas âge ciblez ce que vous voulez
visiter car le faire entièrement sera difficile.
Un fabuleux moment
//Il faut plusieurs jours pour visiter ce musée, à moins de choisir une ou deux sections par visite.
Le musée est très bien entretenu.
Les plans communiqués sont compréhensibles.
Les collections vues sont tres intéressante.
//Magnifique musée.
Le seul souci est la désorganisation pour y rentrer.
Bien que ayant pris bien à l' avance nos billets sur le site, nous avons du faire presque 1h de queue malgres tout pour pouvoir y entrer.
C' est la raison pour laquelle, je ne mets pas la note maximale ainsi que le fait qu' à l interieur,
il y a peu d' indication pour s' orienter.
Mais la visite du musée était très positive pour nous.
//Un musée dune richesse exceptionnelle.
Il est difficile de se repérer malgré les plans papier fournis. Des plans précis affichés plus régulièrement
ainsi quune numérotation des salles plus lisibles seraient appréciés et faciliteraient les déplacements des visiteurs.
Il serait également opportun de disposer plus de bancs pour les enfants et personnes âgées.
//Lieu exceptionnel, collections très riches, à visiter.
Accessibilité sans faille mais quel dédale pour trouver les ascenseurs on doit bien faire le double de
distance que les valides pour la même visite. Le charme des vieilles pierres.
//Première visite au Louvre, nous avions réservé à 9h30, nous avons patienté environs 15/20min avant de rentrer,
il y avait énormément de monde. Les oeuvres et les structures sont magnifique, je pense que
c'est à visiter au moins une fois dans une vie. Il est a des restaurations à l'intérieur à un prix vraiment raisonnable.
Cependant, si on veut vraiment observer toute les oeuvres, il faut prévoir toute une moitié de journée voir plus,
car il y a énormément de chose à regarder et d'endroit à visiter.
//une très bonne expérience surtout pour une personne qui s'intéresse a l'art et aux cultures. je recommande.
//Première visite au Louvre, arrivé avec des billet pour 9h à l'entrée rue de Rivoli. Nous sommes entrée
directement sans faire de queue et avons pu profiter un cours instant d'une visite du musée entièrement vide.
Quel plaisir de pouvoir des œuvres comme la Vénus de Milo ou la Victoire de Samothrace sans une foule de touristes
devant ! Nous avons pu effectuer la suite de notre visite sans blocage dû à la masse des visiteurs et avons même
pu admirer la Joconde en même pas 5min de file d'attente. Merci le personnel du Louvre!
//Magnifique bâtiment. Un musée extraordinaire de part les œuvres et lintérieur des bâtiments
Une double visite
Pas de file dattente ( billet acheté avant sur internet) prévoir la journée ou en plusieurs fois pour arriver à tout voir

View File

@@ -1,160 +0,0 @@
from vaderSentiment_fr.vaderSentiment import SentimentIntensityAnalyzer
#Emplacements des fichiers contenants le lexique et les avis
lexiconPath = r"C:\Users\kesha\Desktop\TelecomParis\PACT\fr_lexicon.txt"
reviewPath = r"C:\Users\kesha\Desktop\TelecomParis\PACT\LouvreAvis.txt"
#Création d'une liste de listes ordonnée alphabétiquement pour ne pas
#avoir à chercher un mot d'un avis dans le lexique en entier à chaque fois.
#La dernière case correspond aux expressions n'étant pas des mots.
scoreWords = open(lexiconPath, "r")
scoreTable = [[] for i in range(27)]
line = scoreWords.readline()
#Fonction d'ajout d'une paire mot-score par ordre alphabétique avec les
#expressions n'étant pas des mots à la dernière case.
#L'indice de la bonne case est trouvée avec le code ASCII en minuscule
#(a vaut 97 et z vaut 122)
def add(scoreword):
if (ord(scoreword[0][0]) < 97 or ord(scoreword[0][0]) > 122):
scoreTable[26].append(scoreword)
else:
scoreTable[ord(scoreword[0][0])-97].append(scoreword)
#Ajout des paires mot-score dans scoreTable
while (line != ''):
line = line.strip().split("->")
add([line[0].lower(), float(line[1])])
line = scoreWords.readline()
scoreWords.close()
### Partie analyse d'avis ###
file = open(reviewPath, "r", encoding='UTF-8')
reviews = (file.read()).split('//')
#liste (partielle) de mots-clé pertinents pour un musée
keys=['attente', "d'attente", 'queue', 'patienter', 'patience', 'patient',
'patients', 'patiente', 'patientes', 'file', 'files',
'impolitesse' ,'impolie', 'impolies', 'impoli', 'impolis',
'gentillesse', 'amabilité', 'aimable', 'aimables','gentil', 'gentils',
'gentille', 'gentilles', 'personnel',
'sales', 'sale', 'saleté', 'propre', 'propres', 'propreté',
'acceuil', 'prix', 'cher', 'chers', 'chère', 'chères',
'onéreux', 'onéreuse', 'onéreuses', 'abordable',
'raisonnable', 'raisonnables', 'accessible', 'accessibilité',
'handicapé', 'handicapée', 'handicapés', 'handicapées', 'orienter','employé',
'employés', 'employées', 'employée', 'agent', 'agente',
'orientation', 'orienté', "s'orienter", 'dédale',
'désorienter', 'désorienté', 'désorientée', 'désorientés', 'désorientées',
'panneau', 'panneaux', 'signalétique', 'labyrinthe',
'perdu', 'perdus', 'perdue', 'perdues',
'toilettes',
'restaurant', 'restaurants', 'restauration', 'manger', 'mangé', 'déjeuner', 'déjeuné']
#Tableau de paires mots-clé, score associé
keyWords = []
#Score moyen d'un avis
averageScore = 0
vaderScore = {'neg': 0, 'neu': 0, 'pos': 0, 'compound': 0}
SIA = SentimentIntensityAnalyzer()
#Fonction de recherche d'un mot d'un avis parmis le lexique
def search(word):
if (len(word) != 0):
if (ord(word[0]) < 97 or ord(word[0]) > 122):
mots = list(e[0] for e in scoreTable[26])
if (word in mots):
return([word, scoreTable[26][mots.index(word)][1]])
else:
return(-1)
mots = list(e[0] for e in scoreTable[ord(word[0])-97])
if (word in mots):
return([word, scoreTable[ord(word[0])-97][mots.index(word)][1]])
return(-1)
#Fonction déterminant si une phrase contient une négation et renvoyant un booléen
def isNegative(sentence):
if (('ne' in sentence) or ("n'" in sentence) or ("pas" in sentence)):
return True
return False
vaderCriteria = ['neg', 'neu', 'pos', 'compound']
def ReviewAnalyzer(review):
reviewScore = 0
#miniKey donne les mots-clé contenus dans l'avis en train d'être analysé
miniKey = []
### Recherche de mots positifs/négatifs ###
#On découpe l'avis en une liste de phrases
sentences = Review.split('.')
for sent in sentences:
#On découpe la phrase en une liste de mots
sentence = list(e.strip(',.') for e in sent.split())
for Word in sentence:
#On met tout les mots en minuscule pour ne pas prendre en compte les majuscules
word = Word.lower()
temp = search(word)
#recherche d'un éventuel mot-clé associé à ce caractère positif/négatif
if (temp != -1):
#On change la valeur du score associé au mot-clé
#si la phrase contient une négation
if (isNegative(sentence)):
temp[1] = -temp[1]
for key in keys:
if (key in sentence):
#Récupération des mots-clés déjà détectés dans tous les avis
cles = list(e[0] for e in keyWords)
#En fonction de si key a déjà été détecté auparavant,
#et donc qu'il est dans keyWords avec un score associé,
#on augmente le score ou sinon, on crée une paire mot-clé score
if (key in cles):
keyWords[cles.index(key)][1] += temp[1]
else:
keyWords.append([key, temp[1]])
#Rajout du mot-clé key dans la liste des mots-clé trouvés dans cet avis
miniKey.append(key)
#Mise à jour du score de l'avis
reviewScore += temp[1]
#Caractéristiques de l'avis analysé
miniKey = set(miniKey)
return(miniKey, reviewScore)
for Review in reviews:
ReviewAnalayzer(Review)
#Ces 3 lignes sont pour comparer avec le score de VADER
score = SIA.polarity_scores(sent)
for criteria in vaderCriteria:
vaderScore[criteria] += score[criteria]
averageScore /= len(reviews)
print("Format: [[Mot-clé, score associé]]")
for e in keyWords:
print(e)
print('')
print("Nombre d'avis: ", len(reviews))
print("Score moyen d'un avis: ", averageScore)
for criteria in vaderCriteria:
vaderScore[criteria] /= len(reviews)
print("Score moyen de vader d'un avis: ", vaderScore)
file.close()

View File

@@ -1,268 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
"#pip install unidecode\n",
"#pip install dataclass\n",
"#pip install nltk\n",
"#import os\n",
"#from unidecode import unidecode\n",
"#import nltk\n",
"#from dataclasses import dataclass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Première partie : presentation du problème et du materiel\n",
"\n",
"Nous cherchons a attribuer à une liste d'avis laissés un score global de satisfaction, ainsi qu'un score de satisfaction concernant chaque point pour lequel il sera particulierement interessant de se pencher (par exemple le delais d'attente dans un parc d'attraction ou la propreté dans un hotel).\n",
"\n",
"Nous allons pour cela utiliser une base de mots français associés chacun a un score de positivité, ainsi qu'une liste d'avis concernant le musée du Louvre.\n"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [],
"source": [
"#Emplacmement du fichier contenant des mots francais associés a une score sous la forme\n",
"#mot1->son score\n",
"#mot2->son score\n",
"#mot3->son score ...\n",
"\n",
"lexiconPath = r\"fr_lexicon.txt\" \n",
"\n",
"\n",
"#Emplacmement du fichier contenant des des avis sur le musée du Louvre sous la forme\n",
"#Avis1\n",
"#//Avis2\n",
"#//Avis3 ...\n",
"\n",
"reviewPath = r\"LouvreAvis.txt\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nous créons une liste de listes ordonnée alphabétiquement pour ne pas avoir à chercher un mot d'un avis dans le lexique en entier à chaque fois. La dernière case correspond aux expressions n'étant pas des mots."
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [],
"source": [
"scoreWords = open(lexiconPath, \"r\")\n",
"scoreTable = [[] for i in range(27)]\n",
"line = scoreWords.readline()\n",
"\n",
"#Fonction d'ajout d'une paire mot-score par ordre alphabétique avec les\n",
"#expressions n'étant pas des mots à la dernière case.\n",
"#L'indice de la bonne case est trouvée avec le code ASCII en minuscule\n",
"#(a vaut 97 et z vaut 122)\n",
"\n",
"def add(scoreword):\n",
" if (ord(scoreword[0][0]) < 97 or ord(scoreword[0][0]) > 122):\n",
" scoreTable[26].append(scoreword)\n",
" else:\n",
" scoreTable[ord(scoreword[0][0])-97].append(scoreword)\n",
" \n",
"#Ajout des paires mot-score dans scoreTable\n",
"while (line != ''):\n",
" line = line.strip().split(\"->\")\n",
" add([line[0].lower(), float(line[1])])\n",
" line = scoreWords.readline()\n",
"scoreWords.close()\n"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['abandon', -2.4]\n",
"['abandonnant', -1.6]\n",
"['abandonne', -1.3]\n",
"['badass', 1.4]\n",
"['badin', 1.2]\n",
"['badine', 1.2]\n",
"['cachant', -1.2]\n",
"['cache', -0.7]\n",
"['cachent', -0.7]\n"
]
}
],
"source": [
"for i in range (3):\n",
" print(scoreTable[i][0])\n",
" print(scoreTable[i][1])\n",
" print(scoreTable[i][2])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Deuxieme partue : analyse d'avis"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [],
"source": [
"file = open(reviewPath, \"r\")\n",
"reviews = (file.read()).split('//')\n",
" \n",
"#liste (partielle) de mots-clé pertinents pour un musée\n",
"keys=['attente', \"d'attente\", 'queue', 'patienter', 'patience', 'patient',\n",
" 'patients', 'patiente', 'patientes',\n",
" 'impolitesse' ,'impolie', 'impolies', 'impoli', 'impolis',\n",
" 'gentillesse', 'amabilité', 'aimable', 'aimables','gentil', 'gentils',\n",
" 'gentille', 'gentilles', 'personnel',\n",
" 'sales', 'sale', 'saleté', 'propre', 'propres', 'propreté',\n",
" 'acceuil', 'prix', 'cher', 'chers', 'chère', 'chères',\n",
" 'onéreux', 'onéreuse', 'onéreuses', 'abordable',\n",
" 'raisonnable', 'raisonnables', 'accessible', 'accessibilité', 'orienter','employé',\n",
" 'employés', 'employées', 'employée',\n",
" 'orientation', 'orienté', \"s'orienter\",\n",
" 'désorienter', 'désorienté', 'désorientée', 'désorientés', 'désorientées',\n",
" 'panneau', 'panneaux', 'signalétique', 'labyrinthe',\n",
" 'perdu', 'perdus', 'perdue', 'perdues']\n",
"\n",
"#Tableau de paires mots-clé, score associé\n",
"keyWords = []\n",
"\n",
"#Score moyen d'un avis\n",
"averageScore = 0\n",
"\n",
"#Fonction de recherche d'un mot d'un avis parmis le lexique\n",
"def search(word):\n",
" if (len(word) != 0):\n",
" if (ord(word[0]) < 97 or ord(word[0]) > 122):\n",
" mots = list(e[0] for e in scoreTable[26])\n",
" if (word in mots):\n",
" return([word, scoreTable[26][mots.index(word)][1]])\n",
" else:\n",
" return(-1)\n",
" mots = list(e[0] for e in scoreTable[ord(word[0])-97])\n",
" if (word in mots):\n",
" return([word, scoreTable[ord(word[0])-97][mots.index(word)][1]])\n",
" return(-1)"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"for Review in reviews:\n",
" #print(Review)\n",
" reviewScore = 0\n",
" miniKey = []\n",
" #recherche de mots positifs/négatifs\n",
" review = list(e.strip(',.') for e in Review.split())\n",
" for Word in review:\n",
" word = Word.lower()\n",
" temp = search(word)\n",
" #recherche d'un éventuel mot-clé associé à ce caractère positif/négatif\n",
" if (temp != -1):\n",
" for key in keys:\n",
" if (key in review):\n",
" cles = list(e[0] for e in keyWords)\n",
" if (key in cles):\n",
" keyWords[cles.index(key)][1] += temp[1]\n",
" else:\n",
" keyWords.append([key, temp[1]])\n",
" miniKey.append(key)\n",
" reviewScore += temp[1]\n",
" averageScore += reviewScore\n",
" #Caractéristique de l'avis analysé\n",
" miniKey = set(miniKey)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Troisiere partie : affichage des resultats"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Format: [[Mot-clé, score associé]]\n",
"[['cher', -2.7], ['orientation', -2.7], ['abordable', 3.4000000000000004], ['personnel', -3.0999999999999996], [\"s'orienter\", -0.10000000000000053], ['queue', 1.0000000000000004], ['orienter', -0.30000000000000004], ['prix', 7.4], ['raisonnable', 7.4], [\"d'attente\", 0.9000000000000012]]\n",
"Nombre d'avis: 23\n",
"Score moyen d'un avis: 1.5652173913043481\n"
]
}
],
"source": [
"averageScore /= len(reviews)\n",
"print(\"Format: [[Mot-clé, score associé]]\")\n",
"print(keyWords)\n",
"print(\"Nombre d'avis: \", len(reviews))\n",
"print(\"Score moyen d'un avis: \", averageScore)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -119,7 +119,6 @@ def init_database():
if not os.path.isfile(os.path.join(data_dir, word)):
for file in os.listdir(os.path.join(data_dir,word)):
if os.path.isfile(os.path.join(data_dir, word,file)):
print(word,os.path.join(data_dir, word,file))
words.append(word)
files.append(os.path.join(data_dir, word,file))
return words,files
@@ -130,7 +129,23 @@ def get_word_metadata(word):
return data[word]
#Todo : detecte si pas de note donnée
def get_grade():
def record():
sr = 44100 # fréquence d'échantillonnage
duration = 6 # durée d'enregistrement en secondes
filename = "recording" # nom du fichier à enregistrer
record_audio(filename, duration, sr)
audio_query,sr = librosa.load(f'{filename}.wav', sr=sr)
return audio_query,sr
def analyze(audio_query,sr):
coupe_silence(audio_query)
words, files = init_database()
audio_train_list = [librosa.load(file, sr=sr)[0] for file in files]
recognized_word_index = recognize_speech(audio_query, audio_train_list, sr)
recognized_word = words[recognized_word_index]
return get_word_metadata(recognized_word)
def test():
sr = 44100 # fréquence d'échantillonnage
duration = 6 # durée d'enregistrement en secondes
filename = "recording" # nom du fichier à enregistrer

View File

@@ -1,13 +1,18 @@
import cv2
import mediapipe as mp
import numpy as np
import os
from dotenv import load_dotenv
load_dotenv()
class HandDetector():
def __init__(self):
self.camera_id = int(os.getenv("CAMERA_ID"))
self.mp_drawing = mp.solutions.drawing_utils
self.mp_drawing_styles = mp.solutions.drawing_styles
self.mp_hands = mp.solutions.hands
self.cap = cv2.VideoCapture(0)
self.cap = cv2.VideoCapture(self.camera_id)
self.hands = self.mp_hands.Hands(
model_complexity=0,
min_detection_confidence=0.5,
@@ -51,8 +56,9 @@ class HandDetector():
# To improve performance, optionally mark the image as not writeable to
# pass by reference.
image.flags.writeable = False
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
results = self.hands.process(image)
# print(results)
if results.multi_hand_landmarks:
handsPositions = []
for hand_landmarks in results.multi_hand_landmarks:

View File

@@ -1,5 +1,5 @@
from hand_detector import HandDetector
from audio_detector import get_grade
from audio_detector import record, analyze, test
from network import ApiClient, WebsocketServer
import time
@@ -57,23 +57,26 @@ class Manager():
state, coords, size, finalDecision = res
self.server.sendMessage({"type": "effects", "effects": [{"type": state, "x":coords[0], "y": coords[1], "width": size, "height": size}]})
self.isLastHandPacketEmpty = False
self.timeLastChange = time.time()
if(finalDecision != False):
self.avis["note"] = 10 if finalDecision == "thumbs_up" else 0
self.state = 2
self.timeLastChange = time.time()
self.server.sendMessage({"type": "state", "state": 2})
elif self.isLastHandPacketEmpty == False:
self.server.sendMessage({"type":"effects","effects":[]})
self.isLastHandPacketEmpty = True
def audio(self):
result = get_grade()
audio_query,sr = record()
self.server.sendMessage({"type":"recording_done"})
result = analyze(audio_query,sr)
# result = test()
if(result != False):
print("mot detecté : " + result["display"] + " avec une note de " + str(result["grade"]))
self.server.sendMessage({"type":"new_grade","word":result["display"]})
self.avis["notes_autres"]["test"] = result["grade"]
time.sleep(3)
self.state = 3
self.timeLastChange = time.time()
self.server.sendMessage({"type": "state", "state": 3})
def thankYou(self):

View File

@@ -4,6 +4,9 @@ import json
import os
import threading
import websockets
from dotenv import load_dotenv
load_dotenv()
class WebsocketServer(threading.Thread):
def __init__(self, onMessage, port=os.getenv("PORT"), host=os.getenv("HOST")):

View File

@@ -85,22 +85,22 @@ services:
# #Backend de la borne : scripts pythons de reconnaissances video et audio
# #Envoient les infos a l'interface de la borne par websocket pour mettre a jour l'interface rapidement
# #Met a jour les avis en faisant des requêtes a l'API
backend_reconnaissance:
build: ./backend_reconnaissance
container_name: backend_reconnaissance
restart: always
devices:
- /dev/video3:/dev/video0
- /dev/snd:/dev/snd
environment:
- PORT=5000
- HOST=backend_reconnaissance
- API_HOST=reviews_api
- API_PORT=8080
ports:
#Ce container est le serveur websocker dont le client est l'interface de la borne qui tourne dans le navigateur
- 5000:5000
user: root
# backend_reconnaissance:
# build: ./backend_reconnaissance
# container_name: backend_reconnaissance
# restart: always
# devices:
# - /dev/video3:/dev/video0
# - /dev/snd:/dev/snd
# environment:
# - PORT=5000
# - HOST=backend_reconnaissance
# - API_HOST=reviews_api
# - API_PORT=8080
# ports:
# #Ce container est le serveur websocker dont le client est l'interface de la borne qui tourne dans le navigateur
# - 5000:5000
# user: root
video_loopback:
build: ./video_loopback

View File

@@ -7,16 +7,21 @@ class AudioPage {
set enabled(isEnabled) {
this.isEnabled = isEnabled;
this.DOMElement.style.display = isEnabled ? "block" : "none";
document.getElementById("grade").innerHTML = "";
document.getElementById("audio_status").innerHTML = "Enregistrement...";
}
onRecordingDone() {
if(this.isEnabled) {
document.getElementById("audio_status").innerHTML = "Traitement...";
}
}
setGrade(grade) {
if(this.isEnabled) {
document.getElementById("grade").innerHTML = grade.toString();
document.getElementById("audio_status").innerHTML = grade;
}
}
reset() {
document.getElementById("grade").innerHTML = "";
document.getElementById("audio_status").innerHTML = "Enregistrement...";
}
}

View File

@@ -1,5 +1,5 @@
class WebsocketClient {
constructor(onNewEffects, onNewState, onNewGrade, onReset) {
constructor(onNewEffects, onNewState, onNewGrade, onReset, onRecordingDone) {
this.socket = new WebSocket("ws://localhost:5000");
this.socket.addEventListener("open", (event) => {
this.socket.send("connected");
@@ -13,10 +13,13 @@ class WebsocketClient {
}else if(msg.type == "state") {
onNewState(msg.state);
}else if(msg.type == "new_grade") {
onNewGrade(Number(msg.grade));
onNewGrade(msg.word);
}else if(msg.type == "reset") {
onReset();
}
else if(msg.type == "recording_done") {
onRecordingDone();
}
};
}
}

View File

@@ -21,6 +21,7 @@ class StateManager {
(state) => this.setState(state),
(grade) => this._audioPage.setGrade(grade),
() => this.reset(),
() => this._audioPage.onRecordingDone(),
);
this._sleepingPage.enabled = true;

View File

@@ -35,17 +35,15 @@
<div class="title">
<h1>Dites-nous en plus</h1>
</div>
<p>Donnez une note sur 10 au critère suivant</p>
<table>
<tr>
<th>Critère</td>
<th>Note / 10</td>
</tr>
<tr>
<td>Calme</td>
<td><span id="grade"></span>/10</td>
</tr>
</table>
<p>Comment avez vous trouvé l'exposition ... ?</p>
<p>Dites un mot parmis la liste suivante</p>
<ul>
<li>J'ai beaucoup aimé</li>
<li>génial</li>
<li>Ennuyant</li>
<li>Nul</li>
</ul>
<p>Mot détécté : <span id="audio_status"></span></p>
</div>
</div>
<div id="thank-you">