Transformée de hough

Description

Ce petit code permet d'éffectuer la transformée de Hough sur une image.
Il prend en entrée une image du type (png / jpeg ou gif) qui est séléctionnée au début du programme
Cette image ne doit contenir que le contour des formes (cf "filetre de sobel" par exemple).
Il crée deux images. 1 contenant tout les pixel luent, l'autres contenant les pixels luent + la droite dominante de l'image trouvée.

Plusieurs améliorations peuvent etre apportée surtout dans la recherche du / des maximas.
Il est possible également de l'étendre à plusieurs droites dans l'image ...

Source / Exemple :


package houghTransform;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;

/**

  • @author Zolotaya
  • /
public class Hough { int[][] accu; static int maxRho; /** Constructeur */ public Hough() { // TODO Auto-generated constructor stub JFileChooser choix = new JFileChooser(); if (choix.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { String filename = choix.getSelectedFile().getAbsolutePath(); try { BufferedImage bi = loadImage(filename); Applyhough(bi); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** Fonction d'application de la transformée de Hough */ public void Applyhough(BufferedImage bi){ int compt = 0; int maxRho = (int)(Math.sqrt( (bi.getWidth()*bi.getWidth()) + (bi.getHeight()*bi.getHeight()) ) + 0.5); Hough.maxRho = maxRho; // création du "conteneur" de données accu = new int [360][2*maxRho]; for (int i = 0; i < accu.length ; i++){ for (int j = 0 ; j < accu[i].length ; j++){ accu[i][j] = 0; } } // création d'une image avec en bleu les pixels luent, en rouge les droites trouvée (cf plus loin) BufferedImage dst = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_ARGB); // On parcour toute l'image for (int x = 0 ; x < bi.getWidth() ; x++) { for (int y = 0 ; y < bi.getHeight() ; y++){ // Si le pixel n'appartient pas au fond (n'est pas noir) int rgb = bi.getRGB(x, y); rgb = rgb & 0xFF; if (rgb > 0){ for (int angle = 0 ; angle < 360 ; angle ++){ double theta = Math.toRadians(angle); double rho = x*Math.cos(theta) + y*Math.sin(theta); int indexAngle = (int) (angle); int indexRho = (int)(rho+maxRho + 0.5); accu[indexAngle][indexRho]++; } dst.setRGB(x, y, rgb); compt++; } } } try { SaveImage(dst, new FileOutputStream("PixelRead.png")); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } int[] droite = maxi(); try { dst = tracerDroite(droite, dst); SaveImage(dst, new FileOutputStream("droite.png")); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** Fonction de recherche des maximums */ public int[] maxi(){ int maxi = 0; int[] droite = new int[3]; // On parcours tout l'accumulateur pour trouver le maximum for (int i = 0 ; i < accu.length ; i++){ for (int j = 0 ; j < accu[i].length ; j++){ if ( maxi < accu[i][j]){ maxi = accu[i][j]; droite[0] = i; // angle droite[1] = j; // distance droite[2] = maxi; // peut servir pour la recherche des maximas suivant } } } return droite; } /** Fonction de tracage des droites + calcul de leur équation */ private static BufferedImage tracerDroite(int[] droite, BufferedImage src){ int angle = droite[0]; int rho = droite[1] - maxRho; // droite de la forme ax +by + c = 0 --> // si b != 0 y = (-ax + c)/b // sinon droite verticale double a = Math.cos(Math.toRadians(angle)); double b = Math.sin(Math.toRadians(angle)); double c = rho; // On fixe 2 nombre : int x0 = -src.getWidth(); int x1 = src.getWidth(); double y0 , y1; // On calcul les deux droites : // SI la droite n'est pas verticale if (b != 0){ y0 = (-a*x0 + c)/b; y1 = (-a*x1 + c)/b; // On affiche l'équation de la droite System.out.println("droite : y = "+a+"*x + "+b ); // On trace les droites trouvées Graphics g = src.getGraphics(); g.setColor(Color.red); g.drawLine(x0, (int)(y0 + 0.5), x1, (int)(y1 + 0.5)); } else { x0 = rho; y0 = 0; x1 = rho; y1 = src.getHeight(); // On affiche l'équation de la droite System.out.println("droite : y = "+a+"*x + "+b ); // On trace les droites trouvées Graphics g = src.getGraphics(); g.setColor(Color.red); g.drawLine(x0, (int)(y0 + 0.5), x1, (int)(y1 + 0.5)); } // On retourne l'image source return src; } /** Fonction de sauvegarde d'image */ public static void SaveImage(BufferedImage imBW, OutputStream os) throws Exception { Graphics g = imBW.createGraphics(); g.drawImage(imBW, 0, 0, null); g.dispose(); ImageIO.write(imBW, "png", os); os.close(); imBW = null; os = null; } // Fonction d'ouverture des images (.jpeg / .gif / .png) public BufferedImage loadImage(String f) throws Exception { Image im2 = null; java.awt.MediaTracker mt2 = null; java.io.FileInputStream in = null; byte[] b = null; int size = 0; in = new java.io.FileInputStream(f); if (in != null) { size = in.available(); b = new byte[size]; in.read(b); im2 = java.awt.Toolkit.getDefaultToolkit().createImage(b); in.close(); } mt2 = new java.awt.MediaTracker(new Canvas()); if (im2 != null) { if (mt2 != null) { mt2.addImage(im2, 0); mt2.waitForID(0); } } BufferedImage input = new BufferedImage(im2.getWidth(null), im2 .getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics g = input.createGraphics(); g.setColor(Color.white); g.fillRect(0, 0, im2.getWidth(null), im2.getHeight(null)); g.drawImage(im2, 0, 0, null); g.dispose(); g = null; return input; } /** Point d'entrée */ public static void main(String[] args) { // TODO Auto-generated method stub new Hough(); } }

Conclusion :


J'essairais de rejouter d'autres options (quand j'aurais le temps) sur la détéction des contours d'une image, améliorations de la séléctions des maximas, séléction du nombre de droites... En gros essayer de faire un petit soft sympa ;-).

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.