4 votes

Java 2D et redimensionnement

J'ai un vieux code Java 2D que je veux réutiliser, mais je me demandais si c'était la meilleure façon d'obtenir des images de la plus haute qualité.

    public static BufferedImage getScaled(BufferedImage imgSrc, Dimension dim) {

    //  This code ensures that all the pixels in the image are loaded.
    Image scaled = imgSrc.getScaledInstance(
            dim.width, dim.height, Image.SCALE_SMOOTH);

    // This code ensures that all the pixels in the image are loaded.
    Image temp = new ImageIcon(scaled).getImage();

    // Create the buffered image.
    BufferedImage bufferedImage = new BufferedImage(temp.getWidth(null), 
            temp.getHeight(null), BufferedImage.TYPE_INT_RGB);

    // Copy image to buffered image.
    Graphics g = bufferedImage.createGraphics();
    // Clear background and paint the image.
    g.setColor(Color.white);
    g.fillRect(0, 0, temp.getWidth(null),temp.getHeight(null));
    g.drawImage(temp, 0, 0, null);
    g.dispose();

    // j2d's image scaling quality is rather poor, especially when
    // scaling down an image to a much smaller size. We'll post filter  
    // our images using a trick found at 
    // http://blogs.cocoondev.org/mpo/archives/003584.html
    // to increase the perceived quality....
    float origArea = imgSrc.getWidth() * imgSrc.getHeight();
    float newArea = dim.width * dim.height;
    if (newArea <= (origArea / 2.)) {
        bufferedImage = blurImg(bufferedImage);
    }

    return bufferedImage;
}

public static BufferedImage blurImg(BufferedImage src) {
    // soften factor - increase to increase blur strength
    float softenFactor = 0.010f;
    // convolution kernel (blur)
    float[] softenArray = {
            0,              softenFactor,       0, 
            softenFactor, 1-(softenFactor*4), softenFactor, 
            0,              softenFactor,       0};

    Kernel kernel = new Kernel(3, 3, softenArray);
    ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
    return cOp.filter(src, null);
}

4voto

David Koelle Points 10363

Chris Campbell a rédigé un excellent article détaillé sur la mise à l'échelle des images. cet article .

Chet Haase et Romain Guy ont également rédigé un article détaillé et très instructif sur la mise à l'échelle des images dans leur livre, Des clients très riches .

3voto

Riyad Kalla Points 6064

J'ajoute ici quelques informations pour clarifier les choses.

Non, ce n'est pas le meilleur pour obtenir une image à l'échelle en Java. L'utilisation de getScaledInstance et de l'AreaAveragingScaleFilter sous-jacent est dépréciée par l'équipe Java2D en faveur de méthodes plus avancées.

Si vous cherchez simplement à obtenir une vignette de bonne qualité, la méthode de Chris Campbell, suggérée par David, est la meilleure solution. Pour ce que cela vaut, j'ai implémenté cet algorithme ainsi que deux autres méthodes plus rapides dans une bibliothèque Java de mise à l'échelle des images appelée imgscalr (licence Apache 2). L'objectif de la bibliothèque était de répondre spécifiquement à cette question dans une bibliothèque hautement optimisée et facile à utiliser :

BufferedImage thumbnail = Scalr.resize(srcImg, 150);

Pour obtenir la meilleure instance mise à l'échelle possible en Java, l'appel de méthode ressemblerait à ceci :

BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 
                                       150, 100, Scalr.OP_ANTIALIAS);

La bibliothèque met à l'échelle l'image d'origine en utilisant l'approche de mise à l'échelle incrémentielle recommandée par l'équipe Java2D, puis, pour rendre l'image encore plus belle, une légère convolution est appliquée à l'image, ce qui a pour effet de l'anticréneler légèrement. C'est vraiment bien pour les petites vignettes, moins important pour les grandes images.

Si vous n'avez jamais travaillé avec des convolveops auparavant, c'est BEAUCOUP de travail juste pour obtenir le noyau parfait pour que l'op soit bien dans tous les cas d'utilisation. La constante OP définie sur la classe Scalr est le résultat d'une semaine de collaboration avec un site de réseau social au Brésil qui avait déployé imgscalr pour traiter les photos de profil de ses membres. Nous avons fait des allers-retours et essayé une dizaine de noyaux différents jusqu'à ce que nous en trouvions un qui soit suffisamment subtil pour ne pas rendre l'image douce ou floue, tout en adoucissant les transitions entre les valeurs des pixels afin que l'image n'ait pas l'air "nette" et bruyante à petite échelle.

Si vous voulez le meilleur résultat Si vous avez besoin d'une image mise à l'échelle indépendamment de la vitesse, suivez la suggestion de Juha d'utiliser la bibliothèque java-image-scaling. Il s'agit d'une collection très complète d'Ops Java2D et elle inclut la prise en charge de l'option Algorithme de Lanczsos qui vous donnera le meilleur résultat possible.

Je m'éloignerais de JAI, non pas parce qu'il est mauvais, mais parce qu'il s'agit simplement d'un outil différent/plus large que ce que vous essayez de résoudre. L'une ou l'autre des trois approches mentionnées précédemment vous permettra d'obtenir de superbes vignettes sans avoir à ajouter une toute nouvelle plateforme d'imagerie à votre projet, et ce, en moins de lignes de code.

2voto

JeffFoster Points 354

Vous pouvez utiliser JAI (Java Advanced Imaging) pour obtenir des options de redimensionnement d'image plus sophistiquées. Voir https://jai.dev.java.net/ . Ceux-ci vous permettent beaucoup plus de flexibilité que le paquetage java.awt.image.

1voto

Juha Syrjälä Points 11475

Vous pouvez également vous pencher sur java-image-scaling bibliothèque.

1voto

DareDevil Points 1760

Vous pouvez redimensionner une image à l'aide d'une bibliothèque Open Source Entrez la description du lien ici

J'ai utilisé la fonction "Grande image à petite image" et le résultat est excellent, tout en conservant le rapport d'aspect.

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import org.imgscalr.*;
import org.imgscalr.Scalr.Method;

public class ImageScaller {
static String SRC_FILES_PATH = "I:\\BigGreen\\";
static String IMAGE_FILE_PATH = "I:\\Resized\\";
public ImageScaller() {         
}   
public static void main(String[] args) {
    // TODO Auto-generated method stub
    try
    {
        ResizeLoad(SRC_FILES_PATH);
    }
    catch(Exception ex)
    {
        System.out.println(ex.toString());
    }
}
public static int ResizeLoad(String path)
{
    String file;
    File folder ;
    File[] listOfFiles = null;       
    listOfFiles = null;
    try
    {           
        folder = new File(path);
        listOfFiles = folder.listFiles();   

        for (int i = 0; i < listOfFiles.length; i++)                    
        {                   
            if (listOfFiles[i].isFile())
            {
                file = listOfFiles[i].getName();
                ScalledImageWrite(listOfFiles[i].getPath(),file);                                   
                //System.out.println(file);
                }
            }
        System.out.println("All Resized");
        }

    catch (Exception e) 
      {
          JOptionPane.showMessageDialog(null,e.toString(),"Resize & Load :Exception",JOptionPane.WARNING_MESSAGE);                
      }
    return listOfFiles.length;
}
private static File ScalledImageWrite(String path,String fileName) 
  {
      try
      {
          BufferedImage img = ImageIO.read(new File(path));            
          BufferedImage scaledImg = Scalr.resize(img, Method.AUTOMATIC, 24, 24);                 
          File destFile = new File(IMAGE_FILE_PATH + fileName);      
          ImageIO.write(scaledImg, "png", destFile);                  
          //System.out.println("Done resizing");
          return destFile;
      }
      catch (Exception e) 
      {
          JOptionPane.showMessageDialog(null,e.toString(),"Scalled Images Write: Exception",JOptionPane.WARNING_MESSAGE);
          return null;
      }
  }

}

Voici la sortie sous forme d'image de ce code. enter image description here

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X