Skip to content
Snippets Groups Projects
Commit 65201583 authored by Robin VAN DE MERGHEL's avatar Robin VAN DE MERGHEL :computer:
Browse files

Adding files I've forgotten to add ._.

parent bceee86f
No related branches found
No related tags found
No related merge requests found
Showing
with 1238 additions and 7 deletions
---
title: Cours algorithmique
author: VAN DE MERGHEL Robin
date: 2023
geometry: margin=1in
---
# Cours du 28 avril 2023
Correction suppression `(A,x)` :
![Correction suppression](./images/correction-suppression.jpg)
## Remarque
- Dans le cas 2.1, on se ramène aux [...]
## Exemple
![Exemple](./images/exemple.jpg)
- Sur le schémas ci-dessus, on a une rotation gauche sur $B$
## Exemple 2
![Exemple 2](./images/exemple2.jpg)
## Exemple 3
![Exemple 3](./images/exemple3.jpg)
## Exemple 4
![Exemple 4](./images/exemple4.jpg)
## Complexité de correction suppression
Le nombre d'itérations est borné par le nombre de fois où on a appliqué (2.2 + 2.1) + ($\leq1$ fois le Cas 2.3) + ($\leq1$ fois le Cas 2.4)
Comme à chaque fois que l'on applique 2.1, on se réduit aux cas 2.2 à 2.4 et ç chaque application du cas 2.2 on remonte dans l'arbre, le nombre d'itérations est bornée par $2\times h$. Comme chaque itération c'est en etemps $O(1)$ et hauteur : $O(log n)$, la complexité est en $O(log n)$.
# Application des arbres
- On utilise les arbres pour représenter tout objet avec une hiérarchie (arbre génélogique, arbre de décision, ...)
- Pour représenter des données sous forme hiérarchique pour une recherche plus rapide dans les données. Ex : texte, dictionnaire...
## TDA Dictionnaire
On y stocke des éléments et on est intéressé par les opérations suivantes : insérer, supprimer, et rechercher.
## TDA Gestion des partitions, ensemble disjoint
Si $E$ est un ensemble, alors $\{E_1, E_2, ..., E_k\}$ est une partition de $E$ si :
- $\bigcup_{1\leq i \leq j}^k E_i = E$
- $\forall l\neq k$, $E_l \cap E_k = \emptyset$
Le TDA ensemble disjoint nous permet de manipuler les partitions d'un ensemble. On a 3 opérations :
- `creeEnsDisjoint` : crée un ensemble disjoint à partir d'un ensemble donné où chaque partie est un singleton.
### Exemple
`creerEnsenbmeDisjoint({1,2,3,4,5})` doit créer la partition $\{\{1\},\{2\},\{3\},\{4\},\{5\}\}$
- `union(x,y)`:
- On recherche les parties de $x$ et de $y$ et on les fusionne.
### Exemple
`union({1,2,3,4,5},{1,2,3,4,5})` doit créer la partition $\{\{1,2,3,4,5\}\}$
On peut uiliser des listes pour implémenter le TDA ensemble disjoint (TD), mais la complexité en temps des opérations pas terrible.
## Théorème
Avec la représentation par la liste chaînée en supposant qu'à chaque appel à l'union, le représentant de la liste la plus longue est le nouveau représentant, une séquence de $m$ opérations nécessite un temps $O(m + n\log n)$.
## Tables de hachage
- Avec les tableaux, on a un accès direct aux valeurs. Mais, grossir un tableau est coûteux
- Toutes les valeurs sont contiguës en mémoire et on n'est même pas sûr d'avoir une telle possibilité en mémoire. Même s'il existe, il faut recopier les valeurs de l'ancien tableau
- Avec les listes, pas d'accès direct mais modification facile
Les tables de hachage c'est une solution de compromis entre les deux.
### Principe
- prendre une tableau ni trop petit ni trop grand. Comment choisir la taille du tableau ?
- Pour chaque valeur, choisir une case du tableau pour y stocker. Comment choisir la case ?
Comme la taille du tableau est plus petite que le nombre de données, il y aura forcément deux valeurs renvoyées à la même case. On appelle ça une collision.
#### Réponse à la question 3
Pour résoudre les collisions, comme on ne veut pas perdre de données, on stocke toutes les valeurs en collision dans une list, et l'index du tableau où toutes ces valeurs étaient renvoyées pointera sur cette liste.
Comme on veut réduire les temps d'accè il faut que ces listes ne soient pas trop grand : une bonne réponse aux Q1 et Q2.
#### Réponse à la question 1 et 2
La fonction qui a toute valeur associe un index dans le tableau est appelé fonction de hachage.
Supposons que le tableau est de taille $m$ : $h: U \rightarrow \{0,1,...,m-1\}$ est la fonction de hachahge. On dira que $h$ est simplement uniforme si pour tout $x\in U$, $x$ a la même probabilité d'être ahché dans chacune des cases 0 à $m-1$.
Avec cette hypothèse d'équi-probabilité, on peut avoir des borne sur les tailles des lites de collisions.
Notons $n_i$ la taille de la litste $T_i$.
##### Propriété
- $\sum n_i = |U|$
- Comme il y a équi-probabilité, l'espérance de la taille d'une liste est $\frac{|U|}{m}$
##### Théorème
Si $h$ est une fonction de hachage simplement uniforme et que $h(x)$ se calcule en temps $O(1) \forall x$, alors une recherche infructueuse nécessite en moyenne $O(1+\alpha)$ et une recherche réussie aussi en temps moyen $O(1+\alpha)$ où $\alpha = \frac{|U|}{m}$.
### Fonctions de hachage
Bonne fonction c'est une fonction simplement uniforme, mais difficile car :
- On ne sait pas comment les éléments sont distribués
- La distribution n'est pas forcéemnt uniforme : aucune raison que la probabilité de $h(x)=i$ est celle que $h(x)=j$ soit les mêmes
Il faut trouver des heuristiques pour s'en rapprocher.
#### Extraction
On prend la représentation binaire et ensuite $p$ bits dans cette représentation binaire. Si le choix des $p$ bits est uniforme, on a une fonction de hachage simplement uniforme.
#### Compression
On divise en blocs de $p$ bits et on fait une somme de ces blocs. Ensuite on applique un opérateur binaires (ou exclusif, ou, ...) pour avoir un nombre de $p$ bits. (ex : SHA)
#### Division
$h(x) = x\ mod\ m$
Comment choisir $m$ :
- $m\neq 2^k$ sinon on a choisi les $k$ bits de poids faible
- $m\neq 2^k-1$ car une permutation ne changerait rien sur le résultat (si $x$ est interprété en base $2^k$)
##### Donald knuth
Il a donné trois propriétés à satisfaire :
- $m$ premier
- $m sans diviseur premier$
- $m$ ne divise pas $r^k \pm a$ pour des petites valeurs de $a$ et $k$
(un ou l'autre)
##### Multiplication
$h(x) = \lfloor m\times (x\times A\ mod\ 1) \rfloor$ avec $0 < A < 1$, $xmod 1$ calcule la partie décimale
Multiplier par un petit nombre, récupérer la partie décimale et multiplier par $m$. On peut prendre $m=2^k$.
$A = \frac{S}{2^w}$, $w$ la taille d'un mot de l'oordinateur et $S$ un entier de $w$ bits.
### Ensemble universel de fonction de hachage
Il ne faut pas que la fonction de hachage dépende des données.
$H$ est une famille de fonctions universelle si $\forall x,y|\{h: h(x=h(y)\}| \leq \frac{|H|}{m}$ le nombre d'indices possibles.
Il existe des ensembles universels. Tout ensemble universel est un "vivier" de bonnes fonctions de hachage.
#### Exemple
$p>m$ premer très grand, $a,b\in\mathbb{Z}_p$ ($a\neq 0$), $h_{a,b}(x) = ((ax+b)\ mod\ p)\ mod\ m$
$$H_{p,m} = \{h_{a,b}: a,b\in\mathbb{Z}_p, a\neq 0\}$$
est un ensemble universel.
\ No newline at end of file
File added
# Global Navigation Satellite System (GNSS) and GPS
Il y a 4 GNSS :
- GPS (USA)
- GLONASS (Russie)
- Galileo (Europe)
- Beidou (Chine)
## Les enjeux
- Positions ± $3m$
- Navigation maritime (AIS)
- Usages militaires
- Logistique
- Le temps (± $3ns$, UTC ± $1\mu s$)
- Synchronisaation des réseaux de télécommunications
- Synchronisation des réseaux d'énergie
- NTP (Network Time Protocol)
- ...
## Puces
Les puces GPS font des corrélations de signaux pour déterminer la position. Elles sont donc très sensibles aux interférences. Les interférences peuvent être :
- Physiques
- Métal
- Eau
- Brouillage
- Logicielles
- Mauvaise calibration
- Mauvaise configuration
- Mauvaise utilisation
- ...
## Trames NMEA
Les trames NMEA sont des trames de données GPS. Elles sont composées de champs séparés par des virgules.
```
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
```
## Les menaces
- Brouillage
- Rejeu
- Relais
- Leurrage
\ No newline at end of file
# Les véhicules autonomes
## Vehicule autonome vs Vehicule intelligent
Un vehicule intelligent est un vehicule qui est capable de prendre des décisions (ex : ABS).
Un vehicule autonome est un vehicule qui est capable de prendre des décisions sans l'intervention de l'humain (ex : Tesla).
## L'histoire
En dehors de tout les modèles, l'émergence des challenges DARPA a permis de faire émerger les premiers véhicules autonomes.
## Intérêt
- Sur les 8 milliards d'être humains, il y a 1,3 milliards de conducteurs. S'il y a une transition vers les véhicules autonomes, pour les entreprises, cela représente un marché potentiel de 1,3 milliards de personnes.
- Ajouté à ça, on peut asussi rajouter les convois autonomes, les drones, les robots, etc.
- Améliorer la sécurité routière
- Efficacité énergétique
- Optimiser les systèmes de transport
- Assurer la mobilité des personnes
\ No newline at end of file
# Introduction
L'intelligence artificielle avec réseau de neurones provient d'une discussion entre un neuro-biologiste et un mathématicien.
On peut essayer de simuler le cerveau humain en utilisant des réseaux de neurones artificiels.
# Réseaux de neurones
On peut représenter un réseau de neurones par un graphe orienté. Les neurones sont les sommets et les connexions entre les neurones sont les arêtes.
On a attaché à chaque paire de neurones un poids noté $w_{ij}$ qui représente la force de la connexion entre les neurones $i$ et $j$.
On a donc une fonction $y=f_w(x)$.
On règle ces poids pour que à partir de notre entrée $x$, on obtienne la sortie $y$ désirée. C'est de l'apprentissage supervisé.
# Données
Pour l'apprentissage, on peut utiliser des données réelles ou des données simulées.
On peut avoir des données brutes (un chien, un chat) ou des données sémantiques (un chat qui boit du lait).
\ No newline at end of file
......@@ -54,7 +54,7 @@ specialite <- conference
@enduml
```
#### Question 1
#### Question 1 et 2
> **Donner les super-clés des tables `Spécialité`, et `AnneeConf`.**
......@@ -70,7 +70,7 @@ Les super-clés de `AnneeConf` sont :
- `idConf`, `annee`, `ville` et `pays`
#### Question 2
#### Question 3
> **On va considérer que la base de donnée est remplie comme suit :**
......@@ -88,13 +88,28 @@ Les super-clés de `AnneeConf` sont :
> |--------|-------|-------|------|
> | 0 | 2022 | Clermont-Ferrand | France |
##### Question 2.1
> **Donner les clés étrangères de ces 3 tables (`Specialite`, `Conference` et `AnneeConf`).**
- `idConf` est une clé étrangère de `AnneeConf`, elle référence `idConf` de `Conference`
- `idSpé` est une clé étrangère de `Conference`, elle référence `idSpé` de `Specialite`
- `Specialite` n'a pas de clé étrangère, car elle n'en référence pas d'autres
En effet on le voit sur le schéma suivant :
```mermaid
graph LR
AnneeConf --> Conference
Conference --> Specialite
```
##### Question 4.1
> **Que se passe-t-il avec : `INSERT INTO Specialite VALUES (0, 'maths')` ?**
Il y a une erreur car la contrainte de clé primaire est violée par cette insertion.
##### Question 2.2
##### Question 4.2
> **Que se passe-t-il avec : `INSERT INTO AnneConf VALUES (0, 2021, `Paris`, `France`)` ?**
......@@ -107,13 +122,13 @@ On obtient donc :
> | 0 | 2022 | Clermont-Ferrand | France |
> | 0 | 2021 | Paris | France |
##### Question 2.3
##### Question 4.3
> **Que se passe-t-il avec : `INSERT INTO AnneConf VALUES (1, 2022, `Sydney`, `Australie`)` ?**
L'insertion viole la clé étrangère de la table `AnneeConf` car il n'y a pas de `idConf` = 1 dans la table `Conference`.
##### Question 2.4
##### Question 4.4
> **Que se passe-t-il avec : `INSERT INTO Conference VALUES (1, `VLDB`, `VLDB`, `mondiale`, 0)` ?**
......@@ -126,7 +141,7 @@ On obtient donc :
> | 0 | BDA | BD annuelle | France | 0 |
> | 1 | VLDB | VLDB | mondiale | 0 |
##### Question 2.5
##### Question 4.5
> **Que se passe-t-il avec : `DELETE FROM Conference WHERE idConf = 0` ?**
......
import java.util.*;
// Images
PImage source; // Source image
PImage warpedmarker;
PImage img_lissee; // image lissée
PImage contours; //image seuillée des contours
PImage gradient; // image de la norme du gradient
PImage gradnms; // image du gradient après nms
String[] markersNames = {
"Marqueur_ISIMA2.jpg",
"Marqueur_ISIMA.jpg",
"Marqueur_ISIMA3.jpg",
"Marqueur_ISIMA4.jpg",
};
PImage[] markers = new PImage[markersNames.length];
// Paramètres hysteresis
int seuil_haut = 100;
int seuil_bas = 60;
// Paramètres hough
int thresholdHough = 80;
int stept = 1;
int stepr = 1;
// précalcul des sinus et cosinus pour gagner du temps :
int nt = int(180 / stept);
float[] costab = new float[nt];
float[] sintab = new float[nt];
//Taille marqueur
int markerWidth = 302;
int markerHeight = 302;
//**********************************************************
void setup() {
size(640, 480);
source = loadImage("./marqueur.jpg");
for (int i = 0; i < markersNames.length; i++) {
markers[i] = loadImage(markersNames[i]);
}
img_lissee = createImage(source.width, source.height, RGB);
gradient = createImage(source.width, source.height, RGB);
contours = createImage(source.width, source.height, RGB);
gradnms = createImage(source.width, source.height, RGB);
//Opencv
opencv = new OpenCV(this, source);
warpedmarker = createImage(markerWidth, markerHeight, ARGB);
//précalcul des sinus et cosinus pour gagner du temps
float theta = 0;
for (int idt = 0; idt < nt;idt++) {
theta = radians( -90 + idt * stept);
costab[idt] = cos(theta);
sintab[idt] = sin(theta);
}
}
//**********************************************************
void draw() {
image(source,0,0);
compute_contours(source, img_lissee, gradient, gradnms, contours);
//Transformée de Hough
int[][] tab = compute_hough(contours,1,1);
//Parcours de l'accumulateur pour récupérer les principales lignes
Vector<droite> lines = compute_hough_lines(tab, thresholdHough);
//********************************************
////Get the four contour lines
//********************************************
//A COMPLETER !
droite[] markerLines = new droite[4];
for (int k = 0;k < 4;k++) {
//look for best line
Iterator itr = lines.iterator();
droite my_line = lines.get(0);
markerLines[k] = my_line;
while(itr.hasNext()) {
my_line = (droite)itr.next();
// On récupère les 4 meilleures droites (on compare par leur accumulateur "acc")
if (my_line.acc > markerLines[k].acc) {
markerLines[k] = my_line;
}
}
//remove the line from the list
lines.remove(markerLines[k]);
color c = color(255, 0, 0);
markerLines[k].display(c, source.width, source.height);
}
//****************************************
//Compute intersections to get corners
//****************************************
//ArrayList<PVector> points = new ArrayList<PVector>
PVector[] corners = new PVector[4];
for (int k = 0;k < 4;k++) {
droite l1 = markerLines[k];
droite l2 = markerLines[(k + 1) % 4];
corners[k] = l1.intersection(l2);
}
// On affiche les coins
for (int k = 0;k < 4;k++) {
fill(255, 0, 0);
ellipse(corners[k].x, corners[k].y, 10, 10);
println(corners[k].x + " " + corners[k].y);
}
//*****************************************************************
//Calcul du warping :
//*****************************************************************
PVector[] arranged_corners = new PVector[4];
//A COMPLETER
// opencv.toPImage(warpPerspective(arranged_corners, markerWidth, markerHeight), warpedmarker);
// On a 4 points, on doit trouver les 4 coins dans l'ordre
// On cherche le coin en haut à gauche
for (int k = 0;k < 4;k++) {
if (corners[k].x < source.width / 2 && corners[k].y < source.height / 2) {
arranged_corners[1] = corners[k];
}
}
// On cherche le coin en haut à droite
for (int k = 0;k < 4;k++) {
if (corners[k].x > source.width / 2 && corners[k].y < source.height / 2) {
arranged_corners[0] = corners[k];
}
}
// On cherche le coin en bas à droite
for (int k = 0;k < 4;k++) {
if (corners[k].x > source.width / 2 && corners[k].y > source.height / 2) {
arranged_corners[3] = corners[k];
}
}
// On cherche le coin en bas à gauche
for (int k = 0;k < 4;k++) {
if (corners[k].x < source.width / 2 && corners[k].y > source.height / 2) {
arranged_corners[2] = corners[k];
}
}
opencv.toPImage(warpPerspective(arranged_corners, markerWidth, markerHeight), warpedmarker);
//*****************************************************************
//Affichage
//*****************************************************************
//Wechanged the pixels in destination
gradient.updatePixels();
contours.updatePixels();
// if (mousePressed && (mouseButton == RIGHT)) { // Si clic droit de la souris
// // Affiche le marqueur redressé
// image(contours,0,0);
// }
// else if (mousePressed && (mouseButton == LEFT)) { //Si clic gauche de la souris
// // Affiche les contours, les 4 droites principales et les coins
// image(warpedmarker,0,0);
// // ACOMPLETER
// }
warpedmarker = convertBNW(warpedmarker, 128);
// On va comparer les différents marqueurs avec warpedmarker
// On doit d'abord retailler les autres images pour qu'elles aient la même taille que warpedmarker
for (int i = 0; i < 4; i++) {
markers[i].resize(warpedmarker.width, warpedmarker.height);
markers[i] = convertBNW(markers[i], 128);
}
// On va comparer les différents marqueurs avec warpedmarker
PImage bestMarker = markers[0];
float bestScore = 0;
int index = 0;
for (int i = 0; i < 4; i++) {
float score = compareImages(warpedmarker, markers[i]);
if (score < bestScore || bestScore == 0) {
bestScore = score;
bestMarker = markers[i];
index = i;
}
}
if (bestScore < 10) {
// On affiche
image(bestMarker, 0, 0);
// On affiche le marqueur redressé
image(warpedmarker, bestMarker.width, 0);
println("Marqueur trouvé : " + bestScore + " " + markersNames[index]);
}
}
PImage convertBNW(PImage im, int seuil) {
PImage im1 = createImage(im.width, im.height, RGB);
for (int i = 0; i < im.width; i++) {
for (int j = 0; j < im.height; j++) {
int c = im.get(i, j);
int r = (int) (0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c));
im1.set(i, j, color(r, r, r));
}
}
return seuil(im1, seuil);
}
PImage seuil(PImage im1, int seuil) {
for (int i = 0; i < im1.width; i++) {
for (int j = 0; j < im1.height; j++) {
int c = im1.get(i, j);
if (red(c) > seuil) {
im1.set(i, j, color(255, 255, 255));
}
else {
im1.set(i, j, color(0, 0, 0));
}
}
}
return im1;
}
float compareImages(PImage im1, PImage im2) {
// On calcule la différence entre les deux images
// Les deux images sont en noir et blanc
// On va calculer la moyenne des pixels dans une zone de 10x10
float diff = 0;
float moyenne = 0;
float valIm1 = 0;
float valIm2 = 0;
for (int i = 5; i < im1.width - 5; i++) {
for (int j = 5; j < im1.height - 5; j++) {
moyenne = 0;
for (int x = -5; x < 5; x++) {
for (int y = -5; y < 5; y++) {
valIm1 = red(im1.get(i + x, j + y));
valIm2 = red(im2.get(i + x, j + y));
moyenne += sqrt(sq(valIm1 - valIm2));
}
}
diff += moyenne / 100;
}
}
diff = diff / (im1.width * im1.height);
return diff;
}
\ No newline at end of file
//**********************************************************************
// Calcul du gradient simple (Roberts)
void compute_gradient_simple(PImage img, PImage gradient) {
int loc = 0, topLoc = 0, leftLoc = 0;
float gradH = 0, gradV = 0, grad = 0;
// Parcours de l'image en ignorant le bord
for (int x = 1; x < img.width; x++) {
for (int y = 1; y < img.height; y++ ) {
// Pixel courant
loc = x + y*img.width;
color pix = img.pixels[loc];
// Pixel de gauche
leftLoc = (x-1) + y*img.width;
color leftPix = img.pixels[leftLoc];
// Pixel du haut
topLoc = x + (y-1)*img.width;
color topPix = img.pixels[topLoc];
// Calcul du gradient
gradH = abs(brightness(pix) - brightness(leftPix));
gradV = abs(brightness(pix) - brightness(topPix));
grad = sqrt(gradH*gradH+gradV*gradV);
gradient.pixels[loc] = color(grad);
}
}
}
//**********************************************************************
// Calcul du gradient de Sobel
void compute_gradient_sobel(PImage img, PImage gradient) {
float[][] filtreSobelH = { { -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 } };
float[][] filtreSobelV = { { 1, 2, 1 },
{ 0, 0, 0 },
{ -1, -2, -1 } };
float grad = 0;
float gradH = 0;
float gradV = 0;
int loc = 0;
//Parcours des pixels de l'image
for (int x = 1; x < img.width-1; x++) {
for (int y = 1; y < img.height-1; y++ ) {
gradV = 0; gradH = 0;
//Calcul du résultat de la convolution par les 2 masques :
gradH = apply_kernel_lum(x, y, filtreSobelH, img);
gradV = apply_kernel_lum(x, y, filtreSobelV, img);
//Calcul de la norme du gradient :
grad = sqrt(gradH*gradH+gradV*gradV);
//Stockage dans une PImage (valeur entre 0 et 255)
loc = x + y*img.width;
gradient.pixels[loc] = color(grad);
}
}
}
//**********************************************************************
// Calcul du gradient et de l'orientation
void compute_gradient_Sobel_or(PImage img, PImage gradient, PImage orientation) {
float[][] filtreSobelH = { { -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 } };
float[][] filtreSobelV = { { 1, 2, 1 },
{ 0, 0, 0 },
{ -1, -2, -1 } };
float grad = 0, theta = 0;
int loc = 0;
float maxgrad = 0;
float[] gradmag = new float[img.width*img.height];
//Parcours des pixels de l'image
for (int x = 1; x < img.width-1; x++) {
for (int y = 1; y < img.height-1; y++ ) {
float gradV = 0, gradH=0;
//Calcul du résultat de la convolution par les 2 masques :
gradH = apply_kernel_lum(x, y, filtreSobelH, img);
gradV = apply_kernel_lum(x, y, filtreSobelV, img);
//Calcul de la norme du gradient :
grad = sqrt(gradH*gradH+gradV*gradV);
gradmag[x+y*img.width] = grad;
if (grad>maxgrad) {
maxgrad = grad;
}
theta = atan2(gradV, gradH);
loc = x + y*img.width;
orientation.pixels[loc] = color(theta*255./(float)Math.PI);//scaled to 0 255
gradient.pixels[loc] = color(grad);
}
}
//Rescale entre 0 et 255
for (int k = 0; k < gradmag.length; k++)
{
gradmag[k] = 255*gradmag[k]/maxgrad;
gradient.pixels[k] = color(int(gradmag[k]));
}
}
//*****************************************************************
// **************** Non max suppression ***************************
void compute_grad_nms(PImage img, PImage gradient, PImage resultat) {
float[][] filtreSobelH = { { -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 } };
float[][] filtreSobelV = { { 1, 2, 1 },
{ 0, 0, 0 },
{ -1, -2, -1 } };
float grad = 0, theta = 0;
int loc = 0;
float maxgrad = 0;
float[] gradmag = new float[img.width*img.height];
float[] gradangle = new float[img.width*img.height];
//Parcours des pixels de l'image
for (int x = 1; x < img.width-1; x++) {
for (int y = 1; y < img.height-1; y++ ) {
float gradV = 0, gradH=0;
//Calcul du résultat de la convolution par les 2 masques :
gradH = apply_kernel_lum(x, y, filtreSobelH, img);
gradV = apply_kernel_lum(x, y, filtreSobelV, img);
//Calcul de la norme du gradient :
grad = sqrt(gradH*gradH+gradV*gradV);
if (grad>maxgrad) {
maxgrad = grad;
}
theta = atan2(gradV, gradH);
loc = x + y*img.width;
gradmag[loc] = grad;
gradangle[loc] = theta;
}
}
//NMS
float curr_angle = 0;
float avant = 0; float apres = 0;
for (int x = 1; x < img.width-1; x++) {
for (int y = 1; y < img.height-1; y++ ) {
loc = x + y*img.width;
curr_angle = gradangle[loc];
grad = gradmag[loc];
gradient.pixels[loc]=color(int(255*grad/maxgrad));
//calcul des voisins
if ((-0.3927<=curr_angle & curr_angle<0.3927)||(-3.1415927<=curr_angle&curr_angle<-2.7488)||(2.7488<=curr_angle&curr_angle<=3.1415927)){
avant = gradmag[x+(y+1)*img.width];
apres = gradmag[x+(y-1)*img.width];
}else if ((1.1781<=curr_angle & curr_angle<1.9636)||(-1.9636<=curr_angle&curr_angle<-1.1781)){
avant = gradmag[x-1+(y)*img.width];
apres = gradmag[x+1+(y)*img.width];
}else if ((0.3927<=curr_angle & curr_angle<1.1781)||(-2.7488<=curr_angle&curr_angle<-1.9636)){
avant = gradmag[x-1+(y+1)*img.width];
apres = gradmag[x+1+(y-1)*img.width];
}else {//if ((-1.1781<=curr_angle & curr_angle<-0.3927)||(1.9636<=curr_angle&curr_angle<2.7488)){
avant = gradmag[x-1+(y-1)*img.width];
apres = gradmag[x+1+(y+1)*img.width];
}
// suppression des non max
if ((grad>=avant) & (grad>=apres)){
resultat.pixels[loc]=color(int(255*grad/maxgrad));
}else {
resultat.pixels[loc]=color(0);}
}
}
}
//**********************************************************************
// Calcul des contours
void compute_contours(PImage img, PImage img_lissee, PImage gradient, PImage gradnms, PImage contours) {
float[][] lissage = { { 1./9., 1./9., 1./9. },
{ 1./9., 1./9., 1./9. },
{ 1./9., 1./9., 1/9. } };
image_convolution(img, lissage, img_lissee);
img_lissee.updatePixels();
compute_grad_nms(img_lissee, gradient, gradnms);
gradient.updatePixels();
gradnms.updatePixels();
//seuillage(gradnms, contours, seuil_haut);
seuillage(gradnms, contours, seuil_bas, seuil_haut);
contours.updatePixels();
}
//**********************************************************************
//***** Convolution à la position x y, sur la luminance uniquement *****
float apply_kernel_lum(int x, int y, float[][] kernel, PImage img)
{
float lum = 0.0;
int kernel_size = kernel.length;
int m = kernel_size / 2;
// Parcours du masque
for (int i = 0; i < kernel_size; i++){
for (int j= 0; j < kernel_size; j++){
int xloc = x+i-m;
int yloc = y+j-m;
// Contraint la valeur dans les bornes de l'image
xloc = constrain(xloc,0,img.width-1);
yloc = constrain(yloc,0,img.height-1);
//Calcul de l'indice linéaire du pixel
int loc = xloc + img.width*yloc;
// Calcul de la multiplication avec le masque
lum += (brightness(img.pixels[loc]) * kernel[i][j]);
}
}
// Renvoie la valeur résultante
return lum;
}
//**********************************************************************
// Convolution d'une image par un masque (kernel)
void image_convolution(PImage img, float[][] kernel, PImage resultat)
{
// Parcours de l'image
for (int y = 0; y < img.height; y++) {
for (int x = 0; x < img.width; x++) {
float lum = apply_kernel_lum(x,y, kernel, img);
resultat.pixels[x + img.width*y]=color(lum);
}
}
}
Realite Virtuelle/Exos/2023-04-05/TD_warping_etu/data/Marqueur_ISIMA.jpg

6.56 KiB

Realite Virtuelle/Exos/2023-04-05/TD_warping_etu/data/Marqueur_ISIMA2.jpg

4.62 KiB

Realite Virtuelle/Exos/2023-04-05/TD_warping_etu/data/Marqueur_ISIMA3.jpg

4.97 KiB

Realite Virtuelle/Exos/2023-04-05/TD_warping_etu/data/Marqueur_ISIMA4.jpg

5.27 KiB

Realite Virtuelle/Exos/2023-04-05/TD_warping_etu/data/marqueur.jpg

34.4 KiB

public class droite {
public float r;
public float theta;
public int acc; // valeur de l'accumulateur
// constructor
droite() {
this.r = 0;
this.theta = 0;
this.acc = 0;
}
// Copy constructor
public droite(droite line) {
this.r = line.r;
this.theta = line.theta;
this.acc = line.acc;
}
droite copyline (droite line){
droite l = new droite();
//for all properties in FOo
l.r = line.r;
l.theta = line.theta;
l.acc = line.acc;
return l;
}
// Display the line in current image, from x = 0 (needs to be adapted if the frame is not at 0 position)
// h : image height; w = image width
void display(color c, int w, int h){
float x1,y1,x2,y2;
stroke(c);
if (sin(radians(this.theta))!=0){
x1 = 0;
x2 = w-1;
y1 = (this.r-x1*cos(radians(this.theta)))/sin(radians(this.theta));
y2 = (this.r-x2*cos(radians(this.theta)))/sin(radians(this.theta));
line(x1,y1,x2,y2);
}
else{
line(this.r,0,this.r,h-1);
}
}
PVector intersection(droite line){
PVector point = new PVector();
if (this.theta == line.theta){
println("Warning : droites paralleles !");
return null;
}
else{
float c1 = cos(radians(this.theta));
float c2 = cos(radians(line.theta));
float s1 = sin(radians(this.theta));
float s2 = sin(radians(line.theta));
if((s1!=0)&&(s2!=0)){
point.x = (line.r/s2-this.r/s1)/(c2/s2-c1/s1);
point.y = (this.r-point.x*c1)/s1;
}
else if(s1==0){//droite 1 verticale
point.x = this.r;
point.y = (line.r-point.x*c2)/s2;
}
else{//droite 2 verticale
point.x = line.r;
point.y = (this.r-point.x*c1)/s1;
}
}
return point;
}
}
// calcul de l'accumulateur sur l'image im de contours binaires
// theta : -90:stept:90 -> idx = theta + 90 : 0 -> 180
// r : -r_max:stepr:r_max
int [][] compute_hough(PImage im, float stept, float stepr){
int rmax = (int) sqrt(im.height*im.height+im.width*im.width);
float r = 0; int loc = 0;
int nt = int(180/stept);
int nr = int(2*rmax/stepr);
int [][] tab = new int[nt][nr];
//précalcul des sinus et cosinus (pourrait être fait une seule fois
float[] costab = new float[nt];
float[] sintab = new float[nt];
float theta=0;
for (int idt = 0; idt<nt;idt++){
theta = radians(-90+idt*stept);
costab[idt] = cos(theta);
sintab[idt] = sin(theta);
}
//Calcul de l'accumulateur
for (int x = 0; x < im.width; x++) { //Parcours de colonnes
for (int y = 0; y < im.height; y++ ) { //parcours des lignes
// Pixel location
loc = x + y*im.width;
if (im.pixels[loc] == color(255)) {
for (int idt = 0; idt<nt;idt++){ //Parcours des theta
r = x*costab[idt]+y*sintab[idt]; //calcul de r
tab[idt][round((r+rmax)/stepr)]++; //incrémentation de l'accumulateur
}
}
}
}
return tab;
}
// Calcul des lignes principales (accumulateur supérieur au seuil)
Vector<droite> compute_hough_lines(int [][] tab, int seuil_hough){
Vector<droite> lines = new Vector<droite>();
int nt=tab.length;
int nr=tab[0].length;
int rmax = (int)sqrt(height*height+width*width);
float stept = 180/float(nt);
float stepr = 2*rmax/float(nr);
int count = 0;
for (int idt = 0; idt<nt;idt++){ //Parcours des theta
for (int idr = 0; idr<nr;idr++){
if (tab[idt][idr] > seuil_hough){
droite my_line = new droite();
my_line.acc = tab[idt][idr];
my_line.theta = -90+idt*stept;
my_line.r = idr*stepr - rmax;
lines.addElement(my_line);
count++;
}
}
}
println("lignes détectées : ", count);
return lines;
}
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
//**********************************************************************
//Ajout d'une équivalence dans la map
//eqm : equivalence map
//on suppose ici label0> label1
//on stocke toujours du label le plus grand vers le plus petit
void storeEquivalence(int label0, int label1, Map<Integer, Integer> eqm) {
if ((eqm.containsKey(label0))&& !eqm.containsKey(label1)) {
if (eqm.get(label0)<label1) {eqm.put(label1, eqm.get(label0));}
else if (eqm.get(label0)>label1) {eqm.put(eqm.get(label0),label1);}
}
else if ((eqm.containsKey(label0))&& eqm.containsKey(label1)){
if (eqm.get(label0)<eqm.get(label1)) {eqm.put(eqm.get(label1), eqm.get(label0));}
else if (eqm.get(label0)>eqm.get(label1)) {eqm.put(eqm.get(label0),eqm.get(label1));}
}
else {
eqm.put(label0, label1);
}
}
//**********************************************************************
//find root recursively in the equivalence map
int get_root_label(int label, Map<Integer, Integer> eqm) {
int root = 0;
if (eqm.containsKey(label)) {
root = get_root_label(eqm.get(label),eqm);
}
else root = label;
return root;
}
//**********************************************************************
//**********************************************************************
// Segmentation en composantes connexes (régions)
// bImg : image binaire à segmenter en régions connexes
// labels : image résultante avec une teinte par région connexe de points blancs
// min_size : nb de pixel minimum d'une région
// maxsize : nb de pixels maximum d'une région
//**********************************************************************
//**********************************************************************
void labelling(PImage bImg, PImage labels, int min_size, int max_size){
// Initialisation
HashMap<Integer,Integer> eqm = new HashMap<Integer,Integer>();
int[][] labtab = new int[bImg.width][bImg.height];
int current_label = 1;
int toplabel = 0;
int leftlabel = 0;
//Parcours des pixels de l'image
for (int y = 1; y < bImg.height-1; y++ ){
for (int x = 1; x < bImg.width-1; x++) {
int loc = x + y*bImg.width;
//Check neighbors
if (bImg.pixels[loc] == color(255)){//point à classer
toplabel = labtab[x][y-1];
leftlabel = labtab[x-1][y];
// nouveau label :
if ((toplabel==0)&&(leftlabel==0)){
labtab[x][y] = current_label;
current_label++;
}
else if ((toplabel!=0)&&(leftlabel==0)){
labtab[x][y] = toplabel;
}
else if ((toplabel==0)&&(leftlabel!=0)){
labtab[x][y] = leftlabel;
}
else if ((toplabel!=0)&&(leftlabel!=0)&&(toplabel==leftlabel)){
labtab[x][y] = toplabel;
}
// Sinon on mémorise l'équivalence :
else if ((toplabel!=0)&&(leftlabel!=0)&&(toplabel!=leftlabel)){
if (toplabel<leftlabel){
storeEquivalence(leftlabel,toplabel,eqm);
labtab[x][y] = toplabel;
}
else{
storeEquivalence(toplabel,leftlabel,eqm);
labtab[x][y] = leftlabel;
}
}
}//Fin du traitement du pixel blanc
}
}
//***************************************************
//********** Reorganize equivalence map
HashMap<Integer,Integer> eqm_clean = new HashMap<Integer,Integer>();
for (int i : eqm.keySet()) {
//println(i, "->", eqm.get(i));
int label = get_root_label(i,eqm);
if (label!=i) storeEquivalence(i, label, eqm_clean);
}
//***************************************************
// Deuxième passe : compte des pixels par région
int label=0;
//sizecomp : stocke la taille de chaque composante
HashMap<Integer,Integer> sizecomp = new HashMap<Integer,Integer>();
for (int y = 1; y < height-1; y++ ){
for (int x = 1; x < width-1; x++) {
int loc = x + y*bImg.width;
if (bImg.pixels[loc] == color(255)){//point à classer
if (eqm_clean.containsKey(labtab[x][y])){
label = eqm_clean.get(labtab[x][y]);}
else {label = labtab[x][y];}
if (sizecomp.containsKey(label)){
sizecomp.put(label, sizecomp.get(label)+1);
}
else{
sizecomp.put(label, 1);
}
}
}
}
//***************************************************
// Filtrage des régions en fonction de leur taille
// Numérotation des régions
int n=0;
HashMap<Integer,Integer> dico = new HashMap<Integer,Integer>();
for (Map.Entry<Integer,Integer> element : sizecomp.entrySet()) {
if ((element.getValue()>min_size)&&(element.getValue()<max_size)){
n++;
dico.put(element.getKey(),n);
}
}
println("Nb de composants après filtrage : ", dico.size());
////*****************************************************
// Troisème passe : remplissage de l'image des composantes
for (int y = 1; y < height-1; y++ ){
for (int x = 1; x < width-1; x++) {
int loc = x + y*bImg.width;
if (bImg.pixels[loc] == color(255)){//point à classer
if (eqm_clean.containsKey(labtab[x][y])){
label = eqm_clean.get(labtab[x][y]);}
else {label = labtab[x][y];}
if (dico.containsKey(label)){
labels.pixels[loc] = color(dico.get(label)*255/dico.size());
}
else{
labels.pixels[loc] = color(0);
bImg.pixels[loc] = color(0);
}
}
else{labels.pixels[loc] = color(0);}
}
}
}
//**********************************************************************
// Seuillage simple
void seuillage(PImage img, PImage imgSeuillee, int seuil){
int loc = 0;
for (int x = 0; x < img.width; x++) {
for (int y = 0; y < img.height; y++ ) {
// Pixel courant
loc = x + y*img.width;
color pix = img.pixels[loc];
if (brightness(pix) > seuil) {
imgSeuillee.pixels[loc] = color(255);
} else {
imgSeuillee.pixels[loc] = color(0);
}
}
}
}
//**********************************************************************
// Seuillage hysteresis
void seuillage(PImage img, PImage imgSeuillee, int s_bas, int s_haut) {
int loc = 0;
for (int x = 0; x < img.width; x++) {
for (int y = 0; y < img.height; y++ ) {
// Pixel courant
loc = x + y*img.width;
color pix = img.pixels[loc];
imgSeuillee.pixels[loc] = color(0);
if (brightness(pix) > s_haut) {
imgSeuillee.pixels[loc] = color(255);
} else if (brightness(pix) > s_bas) {
imgSeuillee.pixels[loc] = color(127);
}
}
}
// Iterations jusqu'à ne plus avoir de sélection parmi les pixels indécis
boolean done = false;
while (done == false) {
done = true;
for (int x = 1; x < img.width-1; x++) {
for (int y = 1; y < img.height-1; y++ ) {
// Pixel location and color
loc = x + y*imgSeuillee.width;
color pix = imgSeuillee.pixels[loc];
if (pix == color(127)) {//contour possible
imgSeuillee.pixels[loc] = color(0);
for (int k = -1; k<2; k++) {
for (int l = -1; l<1+1; l++) {
if (imgSeuillee.pixels[x+k + (y+l)*imgSeuillee.width]==color(255)) {
imgSeuillee.pixels[loc] = color(255);
done = false;
}
}
}
}
}
}
}
}
import gab.opencv.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.core.Mat;
import org.opencv.core.CvType;
import org.opencv.core.Scalar;
OpenCV opencv;
//*************************************
// Calcule la transformation entre les coordonnées des points de l'image de départ et de l'image d'arrivée.
// Calcul à partir d'une liste de points et de la taille de template.
// Attention à l'ordre des 4 points !
Mat getPerspectiveTransformation(PVector[] inputPoints, int w, int h) {
Point[] canonicalPoints = new Point[4];
canonicalPoints[0] = new Point(w, 0);
canonicalPoints[1] = new Point(0, 0);
canonicalPoints[2] = new Point(0, h);
canonicalPoints[3] = new Point(w, h);
MatOfPoint2f canonicalMarker = new MatOfPoint2f();
canonicalMarker.fromArray(canonicalPoints);
Point[] points = new Point[4];
for (int i = 0; i < 4; i++) {
points[i] = new Point(inputPoints[i].x, inputPoints[i].y);
}
MatOfPoint2f marker = new MatOfPoint2f(points);
return Imgproc.getPerspectiveTransform(marker,canonicalMarker);
}
//*************************************
// Calcule la transformation entre les coordonnées des points de l'image de départ et de l'image d'arrivée.
// Calcul à partir de 2 listes de points qui se correspondent
Mat getPerspectiveTransformation(PVector[] inputPoints, PVector[]outputPoints) {
Point[] inpoints = new Point[4];
Point[] outpoints = new Point[4];
for (int i = 0; i < 4; i++) {
inpoints[i] = new Point(inputPoints[i].x, inputPoints[i].y);
outpoints[i] = new Point(outputPoints[i].x, outputPoints[i].y);
}
MatOfPoint2f outputmarker = new MatOfPoint2f(outpoints);
MatOfPoint2f inputMarker = new MatOfPoint2f(inpoints);
return Imgproc.getPerspectiveTransform(inputMarker, outputmarker);
}
//*************************************
// Applique la transformation de l'image opencv vers l'image transformedImage
Mat warpPerspective(PVector[] inputPoints, int w, int h) {
Mat transform = getPerspectiveTransformation(inputPoints, w, h);
//println("transform matrix:\n" + transform.dump());
Mat transformedImage = new Mat(w, h, CvType.CV_8UC1);
Imgproc.warpPerspective(opencv.getColor(), transformedImage, transform, new Size(w,h));
return transformedImage;
}
//*************************************
// Applique la transformation de l'image opencv vers l'image transformedImage de taille wxh
Mat warpPerspective(Mat transform, int w, int h) {
Mat transformedImage = new Mat(w, h, CvType.CV_8UC1);
Imgproc.warpPerspective(opencv.getColor(), transformedImage, transform, new Size(w,h));
return transformedImage;
}
Java2UML @ 04f269ae
Subproject commit 04f269ae5afbafcd160185c15266b8f4e9198f19
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment