28 votes

ImageIO lisant des valeurs RVB légèrement différentes des autres méthodes

J'ai trouvé que je reçois des différents RVB lors de l'utilisation de Java (& en fait paint.NET) que je suis en utilisant ImageMagick, Gimp, Python, et Octave. Les 4 derniers tous d'accord avec eachother et donc je suis en supposant que correcte.

Pour ces exemples, je suis en utilisant ce test de l'image: http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg

Test de pixel x=4144 y=2768

               R    G    B
Java        = (125, 107, 69)
Paint.NET   = (125, 107, 69)
ImageMagick = (128, 106, 67)
Python      = (128, 106, 67)
Octave      = (128, 106, 67)
Gimp        = (128, 106, 67)

Ce qui donne?

Voici un test rapide en utilisant imagemagick:

convert image.jpg -crop 1x1+4144+2768 -depth 8 txt:

sortie:

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (32896,27242,17219)  #806A43  srgb(128,106,67)

Voici quelques java et le code python qui montre également le problème:

import org.apache.commons.io.FileUtils;
import org.junit.Test;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;

public class ImageIOTest {
    @Test
    public void can_read_file() throws IOException, InterruptedException, URISyntaxException {
        File tempFile = File.createTempFile("image", "jpg");
        FileUtils.copyURLToFile(new URL("http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg"), tempFile);

        BufferedImage image = ImageIO.read(tempFile);

        int javaRGB = image.getRGB(4144, 2768);
        int javaRed = (javaRGB >> 16) & 0xFF;
        int javaGreen = (javaRGB >> 8) & 0xFF;
        int javaBlue = (javaRGB >> 0) & 0xFF;
        System.out.printf("rgb: (%d, %d, %d)", javaRed, javaGreen, javaBlue);
    }
}

Et voici le correspondant script python:

from PIL import Image
import sys, urllib, cStringIO

file = cStringIO.StringIO(urllib.urlopen("http://farm3.static.flickr.com/2811/9177301733_9836174725_o.jpg").read())

im = Image.open(file)
pix = im.load()
print pix[4144, 2768]

J'ai essayé d'utiliser cette 12monkeys de la bibliothèque dans l'espoir de le guérir, mais pas de dés. Toutes les autres idées de comment je peux extraire de corriger les valeurs RVB à l'aide de java? Je ne suis sûrement pas la première personne à avoir ce problème!

Mise à jour

J'ai essayé d' getRaster().getSample() , mais il a obtenu le même résultat invalide: System.out.println(raster.getSample(4144, 2768, 0)+","+ raster.getSample(4144, 2768, 1)+","+ raster.getSample(4144, 2768, 2)); sortie: 125,107,69

Plus d'infos

Voici une sortie qui montre ce que les valeurs RVB sont décodés par trois outils différents pour la première 9 (3x3 de carrés de pixels en haut à gauche de l'image. Comme vous pouvez le voir, Python et ImageMagick sont à l'unisson. Java parfois matchs. J'ai mis un X à l'endroit où java n'est pas d'accord...:

Tool          [x, y] = (R , G , B )
ImageIO     : [0, 0] = (86, 90, 93)
Python      : [0, 0] = (86, 90, 93)
ImageMagick : [0, 0] = (86, 90, 93)

ImageIO     : [1, 0] = (86, 90, 93)
Python      : [1, 0] = (86, 90, 93)
ImageMagick : [1, 0] = (86, 90, 93)

ImageIO     : [2, 0] = (90, 91, 95) X
Python      : [2, 0] = (88, 92, 95)
ImageMagick : [2, 0] = (88, 92, 95)

ImageIO     : [0, 1] = (85, 93, 95)
Python      : [0, 1] = (85, 93, 95)
ImageMagick : [0, 1] = (85, 93, 95)

ImageIO     : [1, 1] = (85, 93, 95) X
Python      : [1, 1] = (87, 92, 95)
ImageMagick : [1, 1] = (87, 92, 95)

ImageIO     : [2, 1] = (87, 92, 95)
Python      : [2, 1] = (87, 92, 95)
ImageMagick : [2, 1] = (87, 92, 95)

ImageIO     : [0, 2] = (83, 93, 94)
Python      : [0, 2] = (83, 93, 94)
ImageMagick : [0, 2] = (83, 93, 94)

ImageIO     : [1, 2] = (83, 93, 94) X
Python      : [1, 2] = (84, 92, 94)
ImageMagick : [1, 2] = (84, 92, 94)

ImageIO     : [2, 2] = (83, 91, 93)
Python      : [2, 2] = (83, 91, 93)
ImageMagick : [2, 2] = (83, 91, 93)

Pourquoi Java donner des valeurs différentes pour certains pixels? Sinon, est-il une autre (rapide) de façon à générer des valeurs correctes à l'aide du code Java natif?

Mise à JOUR 2016-09-26:

J'ai commis mon code qui illustre ce problème et l'a poussé à github (imageio-test), de sorte que j'ai facilement pu le tester sur des machines différentes. Il s'avère que Java a été cohérents dans les deux OSX et Ubuntu Linux, mais il a été Python, ImageMagick et Octave qui ne l'était pas. En d'autres termes, sous Linux, tous les outils d'accord les uns avec les autres, et donc, je suis en train de penser que java a toujours été la bonne, et c'est aux autres outils de donner des résultats incorrects sur OSX! Je ne comprends vraiment pas pourquoi et je n'ai pas de preuve concrète que les valeurs sont les bonnes, mais je suis quelque part...

18voto

haraldK Points 5751

En fait, je voudrais tourner le problème autour de, et de dire que je suis surpris que tant de différentes plates-formes et des outils réellement produire les mêmes valeurs. :-)

JPEG avec perte est

Tout d'abord, le format JPEG est une perte de compression d'image de la méthode. Cela signifie que reproduire les données exactes de l'original n'est pas possible. Ou, si vous le souhaitez, plusieurs valeurs de pixels peuvent tous être "correct" en quelque sorte.

La technique de raisons de ne pas tous les JPEG logiciel produire exactement les mêmes valeurs à partir du même fichier source, est en général différente de l'arrondi/serrage de valeurs, ou un entier approximations des opérations en virgule flottante pour de meilleures performances. D'autres variantes peuvent provenir de différents algorithmes d'interpolation appliquée à la restauration de la sous-échantillonné les valeurs de chrominance, par exemple (c'est à dire. une image plus douce peut paraître plus agréable à l'œil, mais n'est pas nécessairement plus correct).

Une autre excellente réponse à une question similaire, stipule que "La norme JPEG n'exige pas que le décodeur implémentations de produire bit identique images de sortie", et cite le Wikipedia JPEG entrée:

[...] exigences de précision pour la decodage [...]; la sortie de l'algorithme de référence ne doit pas dépasser:

  • un maximum d'un peu de différence pour chaque pixel composant
  • faible erreur quadratique moyenne de plus de 8×8 pixels du bloc
  • très faible erreur moyenne de plus de 8×8 pixels du bloc
  • très faible erreur quadratique moyenne sur l'ensemble de l'image
  • extrêmement faible erreur moyenne sur l'ensemble de l'image

(Notez que le ci-dessus parle de l' implémentation de référence uniquement).

Cependant, avec un peu de chance, il semble que l'ensemble de vos logiciels/outils à utiliser (une version de) libjpeg. Parce qu'ils utilisent tous libjpeg, la source des différences que vous voyez est probablement pas lié au décodage JPEG.

Les Espaces De Couleur

Même si tous vos logiciel convertit les fichier JPEG à une représentation à l'aide de valeurs RVB, il pourrait y avoir des différences dans la couleur de l'espace qu'ils utilisent à cette représentation.

Il semble que tous les logiciels que vous utilisez réellement affiche les valeurs RVB dans l' espace colorimétrique sRGB. C'est probablement le plus standard et le plus largement utilisé l'espace de couleur utilisé dans le courant dominant de l'informatique, de sorte que n'est pas une surprise, après tout. Comme l'espace de couleur est toujours sRGB, la source des différences que vous voyez est probablement pas la couleur de l'espace.

Les profils ICC et de correspondance des couleurs

La prochaine source possible des différences de couleur, est que la correspondance des couleurs (comme le fait par une Couleur Correspondant Module CMM ou Système de Gestion des Couleurs, CMS) n'est pas 100% exacte de la science (voir par exemple ce document sur la compensation du point noir ou de lire quelques-uns des plus des fonctions techniques de la Little CMS de blog).

Probablement le logiciel fonctionne sur Mac OS X, à l'aide d'Apple CMM, alors que Java est à l'aide de Little CMS toujours (à partir de OpenJDK 7 ou Oracle JDK/JRE 8), et la plupart des logiciels sur la plate-forme Linux sera probablement également utiliser l'open source Little CMS (selon le Petit CMS page d'accueil", Vous pouvez trouver Peu de la CMS dans la plupart des distributions Linux"). Logiciel sur Windows sera susceptible de s'écarter légèrement (je n'ai pas été en mesure de vérifier si Paint.Net utilise Peu de CMS, Windows intégré dans la CMM ou autre chose). Et bien sûr, à l'aide d'Adobe CMM (ie. Photoshop) sera susceptible de s'écarter ainsi.

Encore une fois, avec un peu de chance, beaucoup de logiciels que vous avez testé utilise le même CMM ou CMS moteur, Little CMS, donc encore une fois, vous aurez beaucoup de l'égalité des résultats. Mais il semble que certains des logiciels que vous avez testé différents usages de la Gmao, et est une source probable de les légères différences de couleur.

En résumé

Les différentes valeurs de pixel que vous voyez sont tous les "correcte". Les différences proviennent de différentes implémentations ou des approximations des algorithmes de logiciel, mais cela ne veut pas nécessairement dire qu'une valeur est correcte et que les autres sont mauvais.

PS: Si vous avez besoin de reproduire exactement les mêmes valeurs à travers de multiples plates-formes, utilisez le même outil/pile mêmes algorithmes sur toutes les plateformes.

7voto

ndtreviv Points 1201

Comme pour mon commentaire, la différence majeure entre les différentes applications et les bibliothèques que vous avez utilisé pour récupérer les pixels de la couleur de la valeur, c'est qu'ils sont tous en utilisant différentes versions de libjpeg - au moins sur Mac OSX.

Lorsque vous découvrez votre projet Github sur certaines versions d'Ubuntu, vous verrez que toutes les valeurs sont rapportées dans l'ensemble du conseil d'administration. Dans ces cas, python ImageMagick et la Java JDK/JRE à utiliser le même libjpeg mise en œuvre.

Sur le Mac, si vous avez installé jpeg par homebrewou Pillow par pip ensuite, vous remarquerez qu'ils sont à l'aide de libjpeg v9 (libjpeg.9.dylib), alors que Java 7 et 8 Jdk viennent avec leur propre libjpeg groupés qui sont tout à fait différents.

Octave dresse la liste de ses jpeg dépendances comme libjpeg8-dev.

GIMP, Inkscape, Scribus, etc également livrés avec leur propre. Dans mon cas, GIMP est livré avec la même version de python et de ImageMagick, ce qui pourrait expliquer les valeurs sont similaires (ex: /Applications/GIMP.app/Contents/Resources/lib/libjpeg.9.dylib)

Si vous voulez garantir les valeurs étant le même dans les applications, vous avez le choix:

  1. Bâton de la même plate-forme/pile (comme suggéré par @haraldk) - Bâton à l'établissement et à l'exécution de vos contenus sur les plates-formes Linux qui garantit à tous d'entre eux utilisent la même version libjpeg
  2. Lier votre code Java à la même version que les autres applications utilisez - ie: load libjpeg.9.dylib et l'utiliser à partir de votre application Java. Je ne suis pas 100% sûr de la façon que vous feriez cela.
  3. Recompilez votre JDK pour utiliser la bonne option, référencé par cette réponse est d'utiliser openjdk et le compiler à l'encontre de la version souhaitée de libjpeg, ce qui semble plus réalisable.

Je vais vous avouer que les options 2 et 3 sont vraiment plus difficile versions de l'option 1!

Note:
Je ne suis certainement jusqu'à droit de vote @haraldk de répondre parce que sa conclusion est à peu près la même.

J'ai aussi joué avec l'aide de différents profils icc, et ils se donnent totalement différentes réponses. Donc il vaut mieux se méfier de cela.

Je voulais juste ajouter une réponse qui a ajouté plus l'accent sur la libjpeg mise en œuvre, parce que je crois que c'est ce qui est la capture de vous dans votre cas précis.

Mise à jour

En fait, il y a une autre différence majeure est noté dans @haraldk de réponse, soit la diff entre la CMM et de Little CMS. Comme il le dit: Java utilise Peu de la CMS, qui est également utilisé par Ubuntu

En fait, je pense que c'est plus susceptible d'être la réponse ici.

5voto

Gigantic Points 4447

L'uniformité des couleurs et les Profils ICC

Java ne respecte pas le profil de couleur lors de l'upload d'une image. Aussi différents OS sont différemment poignée de couleurs RVB.

Voici ce que Oracle écrit à propos de import java.awt.color:

En général, une Couleur ou un modèle colorimétrique serait associée à un Profil ICC qui est soit une entrée, un écran ou un profil de sortie. Il existe d'autres types de Profils ICC, par exemple abstrait des profils, des profils de liaison de périphérique, et l'a nommé les profils de couleur, qui ne contiennent pas d'informations appropriées pour la représentation de l'espace de couleur d'une couleur, une image, ou d'un dispositif. La tentative de créer une ICC_ColorSpace objet à partir d'un inappropriée Profil ICC est une erreur.

Les Profils ICC représentent des transformations de l'espace de couleur du profil (par exemple, un moniteur) pour un Profil de Connexion de l'Espace (PC). Profils de l'intérêt pour le marquage des images ou des couleurs qui ont un PC qui est un appareil espaces indépendants (un CIEXYZ l'espace et les deux CIELab espaces) défini dans le Profil ICC de Spécification de Format. La plupart des profils d'intérêt soit inversible transformations ou de spécifier explicitement les transformations dans les deux directions. Si un ICC_ColorSpace objet être utilisé dans une méthode nécessitant une conversion à partir du PC sur le profil du natif de l'espace et il n'y a pas suffisamment de données pour effectuer correctement la conversion, la ICC_ColorSpace objet de produire une sortie dans le type de l'espace de couleur (par exemple, TYPE_RGB, TYPE_CMYK, etc.), mais la couleur spécifique des valeurs des données de sortie ne sera pas défini.

Les détails de l' ICC_ColorSpace de la classe ne sont pas importants pour la simple applets, qui puisent dans une couleur par défaut de l'espace ou de manipuler et d'afficher des images importées avec un espace de couleur. Tout au plus, ces applets aurait besoin pour obtenir un de la couleur par défaut des espaces par ColorSpace.getInstance(). (extrait de l'docs.oracle.com) https://docs.oracle.com/javase/7/docs/api/java/awt/color/ICC_ColorSpace.html

Palette Transformations en Java

Palette transformations sont contrôlés par le type de destination pour la lecture et l'écriture de l'image. Lorsque les Rasters sont en lecture, pas de palette transformation est effectuée, et tout type de destination est ignoré. Un avertissement est envoyé à tous les auditeurs si un type de destination est indiqué dans ce cas. Lorsque les Rasters sont écrites, tout type de destination est utilisée pour interpréter les bandes. Ceci peut entraîner un JFIF ou Adobe en-tête en cours d'écriture, ou autre composant identifiants d'être écrite dans le cadre et l'analyse des en-têtes. Si les valeurs présentes dans un objet de métadonnées ne correspond pas au type de destination, le type de destination est utilisée, et une alerte est envoyée à tous les auditeurs. (extrait de l'docs.oracle.com) https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html

Liens utiles

Regardez info toucher de conversion RGB. Il y a quelques questions sur normalisé float/int composants de la couleur par Rolf W. Rasmussen:

http://opensource.apple.com/source/gcc3/gcc3-1041/libjava/java/awt/image/ColorModel.java

Lire The Sad Story of PNG Gamma "Correction" (Le problème est le suivant: JPEG et TIFF souffrent de la même "maladie").

https://hsivonen.fi/png-gamma/

Regarder S. O. post. Il y a la solution pour vous:

En Java conversion d'une image en sRGB rend l'image trop lumineuse

Si vous avez encore incompatible couleurs d'après toutes les tentatives, d'essayer de convertir les images de profil sRGB, mais ne les intègre pas:

https://imageoptim.com/color-profiles.html

Aussi, j'espère que le livre par Kenny Chasse pourrait être utile.

enter image description here

...et le code suivant (publié au www.physicsforums.com) vous permet de voir comment les différents RVB de ressembler à:

import java.awt.*; 
import javax.swing.*; 

public class RGB { 
    public static void main(String[] args) { 
        JFrame frame = new JFrame("RGB"); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        RGBpanel panel = new RGBpanel(); 
        frame.getContentPane().add(panel); 
        frame.pack(); 
        frame.setVisible(true); 
    } 
} 

class RGBpanel extends JPanel { 
    public RGBpanel() { 
        setPreferredSize(new Dimension(300,300)); 
        int red = Integer.parseInt(JOptionPane.showInputDialog("Enter red value")); 
        int green = Integer.parseInt(JOptionPane.showInputDialog("Enter green value")); 
        int blue = Integer.parseInt(JOptionPane.showInputDialog("Enter blue value")); 
        Color colour = new Color(red,green,blue); 
        setBackground(colour); 
    } 
}

Recap

Le problème de la couleur de l'incohérence provient de profils de couleurs. Essayez d'attribuer une couleur uniforme profil à toutes les images que ce soit manuellement (dans Photoshop) ou par programmation (en Java).

4voto

TylerY86 Points 3135

Voir ici: WARNING: Color space tagged as sRGB, without an embedded color profile. Windows and Mac browsers and apps treat the colors randomly.

Edit: autant Que les erreurs d'arrondi et de mise en œuvre de la variance par version; ils sont tout simplement pas le cas de cette image. Il y a quelque chose de magique se passe avec le Mac qui rend le bleu et le vert brillant sur une correspondance des couleurs de la courbe. Corriger la couleur de l'espace, la correspondance des couleurs donnent le même résultat. I-voté Andy Fedoroff réponse, mais j'ai aussi un avis personne n'a vraiment de vous donner une solution... Vous êtes venu à la conclusion que Java est correct. Aller avec qui. Libjpeg n'a pas changé dans un temps long. Il est stable et reproduit les couleurs de manière fiable à travers de nombreuses plates-formes et environnements. Significative (en quelque sorte) les changements n'ont pas été faites pour le décodage de l'âge standard jpeg.

Edit 2: Allons essayer de créer un exemple qui produit les mêmes valeurs que le Mac profil selon votre type de projet. Besoin de votre Mac, l'usine du profil ICC d' Library/ColorSync/Profiles.

Voici où j'en suis. Voici un exemple avec le sRGB ICC v4 profil appliqué. C'est techniquement l'application sRGB sur sRGB, mais c'est expliquer le concept.

private ICC_Profile cp = ICC_Profile.getInstance("src/test/resources/sRGB_ICC_v4_Appearance.icc");
private ICC_ColorSpace cs = new ICC_ColorSpace(cp);

private int[] getRGBUsingImageIO2(File file, int x, int y) throws IOException {
    BufferedImage image = ImageIO.read(file);
    ColorConvertOp cco = new ColorConvertOp( cs, null );
    BufferedImage result = cco.filter( image, null );
    int javaRGB = result.getRGB(x, y);
    int javaRed = (javaRGB >> 16) & 0xFF;
    int javaGreen = (javaRGB >> 8) & 0xFF;
    int javaBlue = (javaRGB >> 0) & 0xFF;

    return new int[]{javaRed, javaGreen, javaBlue};
}
Image IO 1 : [0, 0] = [145, 146, 164] 
Image IO 2 : [0, 0] = [145, 147, 165] 
Image IO 1 : [1, 0] = [137, 138, 156] 
Image IO 2 : [1, 0] = [137, 139, 157] 
Image IO 1 : [2, 0] = [148, 147, 161] 
Image IO 2 : [2, 0] = [148, 148, 162] 
Image IO 1 : [0, 1] = [150, 153, 168] 
Image IO 2 : [0, 1] = [150, 154, 169] 
Image IO 1 : [1, 1] = [138, 141, 156] 
Image IO 2 : [1, 1] = [138, 142, 157] 
Image IO 1 : [2, 1] = [145, 147, 159] 
Image IO 2 : [2, 1] = [145, 148, 160] 
Image IO 1 : [0, 2] = [154, 160, 172] 
Image IO 2 : [0, 2] = [154, 161, 173] 
Image IO 1 : [1, 2] = [146, 152, 164] 
Image IO 2 : [1, 2] = [146, 153, 165] 
Image IO 1 : [2, 2] = [144, 148, 157] 
Image IO 2 : [2, 2] = [144, 149, 158] 

Pourriez-vous valider votre profil de couleur à votre imageio-test repo?

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