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

VR Complete

parent fd06b0f1
No related branches found
No related tags found
No related merge requests found
// Importation des librairies
import processing.video.*; // Bibliotheque de controle camera
/*
L'espace des paramètres est quantifié (on discrétise r et theta) ● Pour chaque point de l'image binaire des contours
● Pour chaque possible theta
● Calculer le r correspondant
● Incrémenter la case Hough(r,theta)
● Rechercher les maximums locaux de Hough(r,theta)
On va rajouter l'implémentation de la transformation de Hough pour la détection de lignes
*/
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
// Parametres de taille de la capture video
final int widthCapture = 640; // largeur capture
final int heightCapture = 480; // hauteur capture
final int numPixels = widthCapture * heightCapture; // nombre de pixels d'une image video
final int fpsCapture = 30; // taux d’images/secondes
// Quelques couleurs...
final int noir = color(0,0,0);
final int blanc = color(255,255,255);
// Declaration des variables globales
String[] cameras; // Liste des cameras dispos
Capture webCam; // Declaration de la Capture par Camera
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
int rMax = (int) Math.sqrt(widthCapture * widthCapture + heightCapture * heightCapture);
int[][] hough = new int[rMax * 2 + 1][181];
ArrayList<Point> maxLocaux = new ArrayList<Point>();
//**********************************************************************
// Fonction d'initialisation de l'application - executee une seule fois
void setup() {
//Initialisation des parametres graphiques utilises
size(640,480); // Ouverture en mode normal 640 * 480
surface.setTitle("Exemple extraction de contours");
colorMode(RGB, 255,255,255);
noFill(); // pas de remplissage
background(noir); // couleur fond fenetre
//Recherche d'une webcam
cameras = Capture.list();
if (cameras.length == 0) {
println("Pas de Webcam sur cet ordinateur !");
exit();
} else {
// Initialisation de la webcam Video par defaut
webCam = new Capture(this, widthCapture, heightCapture, cameras[0], fpsCapture);
webCam.start(); // Mise en marche de la webCam
}
//Initialisation des images
img_lissee = createImage(webCam.width, webCam.height, RGB);
gradient = createImage(webCam.width, webCam.height, RGB);
contours = createImage(webCam.width, webCam.height, RGB);
gradnms = createImage(webCam.width, webCam.height, RGB);
} // Finde Setup
//** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// Fonction de re - tracage de la fenetre - executee en boucle
void draw() {
background(0);
hough = new int[rMax * 2 + 1][181];
if (webCam.available() == true) { // Verification de presence d'une nouvelle frame
webCam.read(); // Lecture du flux sur la camera... lecture d'une frame
image(webCam, 0, 0); // Restitution de l'image captee sur la webCam
// Calcul des gradients et contours : exemple avec seuillage simple sur gradient nms
compute_contours(webCam, img_lissee, gradient, gradnms, contours, 80);
if (mousePressed && (mouseButton == RIGHT)) { // Test clic droit de la souris...
// Affichage de l'image des gradients
image(gradnms,0,0);
}
else if (mousePressed && (mouseButton == LEFT)) {// Test clic gauche de la souris...
// Affichage de l'image des contours
image(contours,0,0);
}
else{
// Affichagede l'image de la Webcam
image(webCam,0,0);
}
}
// On explore les pixels
for (int x = 0; x < widthCapture; x++) {
for (int y = 0; y < heightCapture; y++) {
if (contours.get(x, y) == blanc) {
for (float theta = 0; theta < Math.PI; theta += 0.1) {
float r = x * cos(theta) + y * sin(theta);
hough[(int) (r + rMax)][radianToDegree(theta)]++;
}
}
}
}
// // On cherche les maximums locaux
// maxLocaux.clear();
// On calcule le maximum de la matrice et la moyenne
int max = 0;
int moyenne = 0;
int n = 0;
for (int r = 0; r < hough.length; r++) {
for (int theta = 0; theta < hough[0].length; theta++) {
if (hough[r][theta] > 10) {
if (hough[r][theta] > max) {
max = hough[r][theta];
}
moyenne += hough[r][theta];
n++;
}
}
}
moyenne /= n;
float seuil = moyenne + (max - moyenne) / 2;
// println("Seuil : " + seuil, "Moyenne : " + moyenne, "Max : " + max);
// On cherche les maximums locaux (au dessus du seuil)
maxLocaux.clear();
for (int r = 1; r < hough.length - 1; r++) {
for (int theta = 1; theta < hough[0].length - 1; theta++) {
if (hough[r][theta] > seuil) {
// On regarde dans un rayon de 15x15 si on a un maximum local
boolean maxLocal = true;
for (int r2 = r - 15; r2 < r + 15; r2++) {
for (int theta2 = theta - 15; theta2 < theta + 15; theta2++) {
if (r2 + rMax < 0 || r2 + rMax >= hough.length || theta2 < 0 || theta2 >= hough[0].length) {
continue;
}
if (hough[r][theta] > hough[r2][theta2]) {
maxLocal = false;
break;
}
}
if (!maxLocal) {
break;
}
}
if (maxLocal) {
maxLocaux.add(new Point(r, theta));
}
}
}
}
// On recherche s'il y a des teta qui sont proche, si oui, on regarde si les r sont proche, si oui, on les fusionne
for (int i = 0; i < maxLocaux.size(); i++) {
for (int j = i + 1; j < maxLocaux.size(); j++) {
if (abs(maxLocaux.get(i).y - maxLocaux.get(j).y) < 10) {
if (abs(maxLocaux.get(i).x - maxLocaux.get(j).x) < 10) {
maxLocaux.get(i).x = (maxLocaux.get(i).x + maxLocaux.get(j).x) / 2;
maxLocaux.get(i).y = (maxLocaux.get(i).y + maxLocaux.get(j).y) / 2;
maxLocaux.remove(j);
j--;
}
}
}
}
// On affiche les maximums locaux
for (Point p : maxLocaux) {
stroke(255, 0, 0);
if (p.y == 0) {
// Line vertical, cas d'erreur pour éviter la division par 0
line(0, p.x - rMax, widthCapture, p.x - rMax);
} else {
line(0, (p.x - rMax) / sin(degreeToRadian(p.y)), widthCapture, (p.x - rMax - widthCapture * cos(degreeToRadian(p.y))) / sin(degreeToRadian(p.y)));
}
}
}
int radianToDegree(float radian) {
return (int) (radian * 180 / Math.PI);
}
float degreeToRadian(int degree) {
return (float) (degree * Math.PI / 180);
}
\ No newline at end of file
//**********************************************************************
// Calcul du gradient de Sobel
// img : PImage image à traiter
// gradient : PImage image du résultat du gradient
//**********************************************************************
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);
}
}
gradient.updatePixels();
}
//**********************************************************************
// Calcul du gradient + nms
// img : PImage image à traiter
// gradient : PImage image du résultat du gradient
// gradnms : PImage image du résultat de la suppression de nom maxima
//**********************************************************************
void compute_gradient_nms(PImage img, PImage gradient, PImage gradnms) {
// A COMPLETER !
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 angle = 0;
float[] gradmag = new float[img.width*img.height];
float[] gradangle = new float[img.width*img.height];
float maxgrad = 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++ ) {
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;
}
angle = atan2(gradV,gradH);
loc = x + y*img.width;
gradmag[loc] = grad;
gradangle[loc] = angle;
}
}
//NMS
//Parcours des pixels de l'image
float pix1 = 0;
float pix2 = 0;
float curr_angle = 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];
// Seuil bas
if (grad>20){
gradient.pixels[loc]=color(int(255*grad/maxgrad));
//Gradient vertical
if ((-0.393<=curr_angle & curr_angle<0.393)||(-3.1416<=curr_angle&curr_angle<-2.749)||(2.749<=curr_angle&curr_angle<=3.1416)){
pix1 = gradmag[x+(y+1)*img.width];
pix2 = gradmag[x+(y-1)*img.width];
}
//Gradient horizontal
else if((1.178<=curr_angle & curr_angle<1.964)||(-1.964<=curr_angle&curr_angle<-1.178)){
pix1 = gradmag[x-1+y*img.width];
pix2 = gradmag[x+1+y*img.width];
}
//Gradient diagonal
else if((0.393<=curr_angle & curr_angle<1.178)||(-2.749<=curr_angle&curr_angle<-1.964)){
pix1 = gradmag[x-1+(y+1)*img.width];
pix2 = gradmag[x+1+(y-1)*img.width];
}
//Gradient diagonal
else {
pix1 = gradmag[x-1+(y-1)*img.width];
pix2 = gradmag[x+1+(y+1)*img.width];
}
// suppression des non max
if ((grad>=pix1)&(grad>=pix2)){
gradnms.pixels[loc]=color(int(255*grad/maxgrad));
}else {
gradnms.pixels[loc]=color(0);}
}else{
gradient.pixels[loc]=color(0);
gradnms.pixels[loc]=color(0);
}
}
}
gradient.updatePixels();
gradnms.updatePixels();
}
//**********************************************************************
// Seuillage simple
// img : PImage image à traiter
// imgSeuilleeimgSeuillee : PImage image du résultat du seuillage
// seuil : seuil utilisé pour le 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);
}
}
}
imgSeuillee.updatePixels();
}
//**********************************************************************
// Calcul des contours : séquence d'opérateurs
// img : PImage image à traiter
// img_lissee : PImage image du résultat du lissage (moyenneur ici)
// gradient : PImage image du résultat du gradient
// gradnms : PImage image du résultat de la suppression de nom maxima
// seuil : seuil utilisé pour le seuillage simple
// contours : PImage image du résultat de l'extraction de contours après seuillage
//**********************************************************************
void compute_contours(PImage img, PImage img_lissee, PImage gradient, PImage gradnms, PImage contours, int seuil) {
float[][] masque_lissage = { { 1./9., 1./9., 1./9. },
{ 1./9., 1./9., 1./9. },
{ 1./9., 1./9., 1/9. } };
image_convolution(img, masque_lissage, img_lissee);
//compute_gradient_sobel(img_lissee, gradient);
compute_gradient_nms(img_lissee, gradient, gradnms);
seuillage(gradnms, contours, seuil);
}
//************************************************************************
//***** Calcul de la combinaison linéaire avec les coefficient du masque *
//***** à la position x y dans l'image, 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)
{
float lum = 0.0;
// Parcours de l'image
for (int y = 0; y < img.height; y++) {
for (int x = 0; x < img.width; x++) {
// Parcours du masque
lum = apply_kernel_lum(x,y, kernel, img);
resultat.pixels[x + img.width*y]=color(lum);
}
}
resultat.updatePixels();
}
// // Importation des librairies
// import processing.video.*; // Bibliotheque de controle camera
// /*
// L'espace des paramètres est quantifié (on discrétise r et theta) ● Pour chaque point de l'image binaire des contours
// ● Pour chaque possible theta
// ● Calculer le r correspondant
// ● Incrémenter la case Hough(r,theta)
// ● Rechercher les maximums locaux de Hough(r,theta)
// On va rajouter l'implémentation de la transformation de Hough pour la détection de lignes
// */
// class Point {
// int x;
// int y;
// public Point(int x, int y) {
// this.x = x;
// this.y = y;
// }
// }
// // Parametres de taille de la capture video
// final int widthCapture = 640; // largeur capture
// final int heightCapture = 480; // hauteur capture
// final int numPixels = widthCapture * heightCapture; // nombre de pixels d'une image video
// final int fpsCapture = 30; // taux d’images/secondes
// // Quelques couleurs...
// final int noir = color(0,0,0);
// final int blanc = color(255,255,255);
// // Declaration des variables globales
// String[] cameras; // Liste des cameras dispos
// Capture webCam; // Declaration de la Capture par Camera
// 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
// int rMax = (int) Math.sqrt(widthCapture * widthCapture + heightCapture * heightCapture);
// int[][] hough = new int[rMax * 2 + 1][181];
// ArrayList<Point> maxLocaux = new ArrayList<Point>();
// //**********************************************************************
// // Fonction d'initialisation de l'application - executee une seule fois
// void setup() {
// //Initialisation des parametres graphiques utilises
// size(640,480); // Ouverture en mode normal 640 * 480
// surface.setTitle("Exemple extraction de contours");
// colorMode(RGB, 255,255,255);
// noFill(); // pas de remplissage
// background(noir); // couleur fond fenetre
// //Recherche d'une webcam
// cameras = Capture.list();
// if (cameras.length == 0) {
// println("Pas de Webcam sur cet ordinateur !");
// exit();
// } else {
// // Initialisation de la webcam Video par defaut
// webCam = new Capture(this, widthCapture, heightCapture, cameras[0], fpsCapture);
// webCam.start(); // Mise en marche de la webCam
// }
// //Initialisation des images
// img_lissee = createImage(webCam.width, webCam.height, RGB);
// gradient = createImage(webCam.width, webCam.height, RGB);
// contours = createImage(webCam.width, webCam.height, RGB);
// gradnms = createImage(webCam.width, webCam.height, RGB);
// } // Finde Setup
// //** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// // Fonction de re - tracage de la fenetre - executee en boucle
// void draw() {
// background(0);
// hough = new int[rMax * 2 + 1][181];
// if (webCam.available() == true) { // Verification de presence d'une nouvelle frame
// webCam.read(); // Lecture du flux sur la camera... lecture d'une frame
// image(webCam, 0, 0); // Restitution de l'image captee sur la webCam
// // Calcul des gradients et contours : exemple avec seuillage simple sur gradient nms
// compute_contours(webCam, img_lissee, gradient, gradnms, contours, 80);
// if (mousePressed && (mouseButton == RIGHT)) { // Test clic droit de la souris...
// // Affichage de l'image des gradients
// image(gradnms,0,0);
// }
// else if (mousePressed && (mouseButton == LEFT)) {// Test clic gauche de la souris...
// // Affichage de l'image des contours
// image(contours,0,0);
// }
// else{
// // Affichagede l'image de la Webcam
// image(webCam,0,0);
// }
// }
// // On explore les pixels
// for (int x = 0; x < widthCapture; x++) {
// for (int y = 0; y < heightCapture; y++) {
// if (contours.get(x, y) == blanc) {
// for (float theta = 0; theta < Math.PI; theta += 0.1) {
// float r = x * cos(theta) + y * sin(theta);
// hough[(int) (r + rMax)][radianToDegree(theta)]++;
// }
// }
// }
// }
// // // On cherche les maximums locaux
// // maxLocaux.clear();
// // On calcule le maximum de la matrice et la moyenne
// int max = 0;
// int moyenne = 0;
// int n = 0;
// for (int r = 0; r < hough.length; r++) {
// for (int theta = 0; theta < hough[0].length; theta++) {
// if (hough[r][theta] > 10) {
// if (hough[r][theta] > max) {
// max = hough[r][theta];
// }
// moyenne += hough[r][theta];
// n++;
// }
// }
// }
// moyenne /= n;
// float seuil = max - (max - moyenne) / 2;
// // println("Seuil : " + seuil, "Moyenne : " + moyenne, "Max : " + max);
// // On cherche les maximums locaux (au dessus du seuil)
// maxLocaux.clear();
// for (int r = 1; r < hough.length - 1; r++) {
// for (int theta = 1; theta < hough[0].length - 1; theta++) {
// if (hough[r][theta] > seuil) {
// maxLocaux.add(new Point(r, theta));
// }
// }
// }
// // On affiche les maximums locaux
// for (Point p : maxLocaux) {
// stroke(255, 0, 0);
// if (p.y == 0) {
// // Line vertical, cas d'erreur pour éviter la division par 0
// line(0, p.x - rMax, widthCapture, p.x - rMax);
// } else {
// line(0, (p.x - rMax) / sin(degreeToRadian(p.y)), widthCapture, (p.x - rMax - widthCapture * cos(degreeToRadian(p.y))) / sin(degreeToRadian(p.y)));
// }
// }
// }
// int radianToDegree(float radian) {
// return (int) (radian * 180 / Math.PI);
// }
// float degreeToRadian(int degree) {
// return (float) (degree * Math.PI / 180);
// }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment