1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
| import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
public class MainPanel {
private static final String MSG_ERR_MOTIF_TROP_ETROIT = "Le motif n'est pas assez large";
final static int MOTIF_LARGEUR_MIN = 10;
public static void main(String[] args)
{
// On charge la depthmap (carte de profondeur : "qui est loin, qui est proche ?")
BufferedImage depthmap = loadDepthMap();
// On charge le motif
BufferedImage motif = loadMotif(depthmap);
BufferedImage autostereogramme = makeItStereo(depthmap, motif);
saveAutostereogram(autostereogramme);
}
private static void saveAutostereogram(BufferedImage image)
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.setSelectedFile(new File("stereo.jpg"));
if (JFileChooser.APPROVE_OPTION==fileChooser.showSaveDialog(null))
{
File selectedFile = fileChooser.getSelectedFile();
try {
ImageIO.write(image, "jpg", selectedFile);
}
catch (IOException e) {
System.out.printf("Erreur à l'enregistrement du fichier ["+e+"]");
}
}
}
private static BufferedImage makeItStereo(BufferedImage depthmap, BufferedImage motif) {
int largeurDepthMap = depthmap.getWidth();
int hauteurDepthMap = depthmap.getHeight();
int largeurMotif = motif.getWidth();
int hauteurMotif = motif.getHeight();
System.out.printf("\nlargeurDepthMap : "+largeurDepthMap);
System.out.printf("\nhauteurDepthMap : "+hauteurDepthMap);
System.out.printf("\nlargeurMotif : "+largeurMotif);
System.out.printf("\nhauteurMotif : "+hauteurMotif);
BufferedImage autostereogramme = new BufferedImage(largeurDepthMap, hauteurDepthMap, motif.getType());
// L'amplitude conseillée est de 25% de la largeur du motif
double amplitudeDefault = largeurMotif*.25;
System.out.printf("\n\n amplitudeDefault : ["+amplitudeDefault+"]");
for(int y = 0; y<hauteurDepthMap; y++)
{
for(int x=0; x<largeurDepthMap; x++)
{
// D = L - ( P / 256 ) * A
int currentPixel = 0xFF & (depthmap.getRGB(x, y)); //depthMapPixels[(x+y*largeurDepthMap];
int deplacement = (int) (largeurMotif - ((amplitudeDefault*currentPixel)/256))/2;
int motifPixel = motif.getRGB(x%largeurMotif, y%hauteurMotif);
if((x-deplacement >= 0) && (x+deplacement < largeurDepthMap))
{
autostereogramme.setRGB(x-deplacement, y, motifPixel);
autostereogramme.setRGB(x+deplacement, y, motifPixel);
}
}
}
return autostereogramme;
}
private static BufferedImage loadDepthMap()
{
BufferedImage image = null; // Image que l'on va charger
JFileChooser fileChooser = new JFileChooser();
boolean ok = false; // booleen pour gerer la sortie de la boucle d'ouverture du fichier
while(!ok)
{
// Si l'utilisateur valide son fichier, on regarde si il est compatible
if(JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(null))
{
File fichierImage = fileChooser.getSelectedFile();
if(null != (image=getImage(fichierImage)))
{
ok = true;
}
}
// Si l'utilisateur annule ou qu'on rencontre un problème on n'insiste pas
else
{
ok = true;
}
}
return image;
}
// Et oue, j'ai pas mis loadPattern, je fais ce que je veux
private static BufferedImage loadMotif(BufferedImage depthmap)
{
BufferedImage image = null; // Image que l'on va charger
JFileChooser fileChooser = new JFileChooser();
boolean ok = false; // booleen pour gerer la sortie de la boucle d'ouverture du fichier
while(!ok)
{
// Si l'utilisateur valide son fichier, on regarde si il est compatible
if(JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(null))
{
File fichierImage = fileChooser.getSelectedFile();
if(null != (image=getImage(fichierImage)))
{
// Remarque : Pour un confort de visualisation la largeur ne devrait pas être supérieure à 5 cm.
// Pour disposer d'un espace suffisant de codage, une largeur de 1 cm est un minimum.
// On décide arbitrairement d'une largeur minimale
if(MOTIF_LARGEUR_MIN > depthmap.getWidth())
{
System.out.printf("\n["+fichierImage+"] "+MSG_ERR_MOTIF_TROP_ETROIT);
image = null;
}
ok = true;
}
}
// Si l'utilisateur annule ou qu'on rencontre un problème on n'insiste pas
else
{
ok = true;
}
}
return image;
}
private static BufferedImage getImage(File fichierImage)
{
String fileName = fichierImage.getName();
BufferedImage image = null;
try
{
image = ImageIO.read(fichierImage);
}
catch (IOException e1)
{
System.out.printf("\nIOException : ["+e1+"]");
return null;
}
System.out.printf("\n["+fileName+"] Type : "+image.getType());
return image;
}
}
/*
Je pars de l'hypothèse que l'on dispose d'une image de base où le relief est codé sous la forme d'une image en dégradés de gris pour laquelle :
la couleur la plus éloignée est la plus sombre (couleur 0, en général le fond de l'image)
la couleur la plus proche est le blanc (dont le code de couleur est 255)
En premier lieu, il vous faut déterminer, pour l'ensemble de l'image à coder, les paramètres suivants :
Largeur du motif à répéter en pixel : L
Amplitude de séparation maximum : A, avec A inférieur à L
L'image à coder est traitée ligne par ligne. Chaque pixel de l'image de départ doit être codé deux fois dans l'image codée, le tout en utilisant un motif de codage.
Il vous faut donc ensuite disposer d'un motif à répéter. Ce motif est une ligne de pixels qui peut être en noir et blanc ou en couleurs. Le motif peut être aléatoire ou extrait d'une texture.
Supposons que pour une ligne 'n', le motif à répéter soit stocké dans un tableau du type Motif:array[1..L] of bytes (notation pascal).
Les paramètres à implémenter sont les suivants :
Pour chaque point à coder, déterminer la valeur de profondeur à coder : P
Pour chaque point à coder la valeur de déplacement sera :
D = L - ( P / 256 ) * A
Le point correspondant du motif de codage sera peint sur l'écran à l'endroit courant et à l'endroit courant + D.
Et ainsi de suite pour tous les autres points.
Il faut choisir des valeurs raisonnables pour L, c'est à dire pour la largeur du motif à répéter. En effet, vos yeux vont devoir fusionner ce motif. Pour un confort de visualisation la largeur ne devrait pas être supérieure à 5 cm. Pour disposer d'un espace suffisant de codage, une largeur de 1 cm est un minimum.
L'amplitude de séparation A est normalement de 25 % de la largeur. Une valeur au-dessus risquerait d'aboutir à des recouvrements.
Plus l'amplitude est grande, plus la résolution du relief est fine.
*/ |
Partager