JPEG und RGB Farben

Status
Nicht offen für weitere Antworten.
S

Sven

Gast
ich versuche ein bild zu öffnen und zu bearbeiten. das bild liegt im jpeg format vor, welches grauwerte enthält. ich möchte nun einige bildbereich markieren, beispielsweise mit rot. dazu brauche ich die rgb informationen. ich habe schon verschiedene möglichkeiten ausprobiert, aber jedesmal werden die farben nur als grauwerte und nicht als echte rgb geladen

das ist die variante, die ich zur zeit verwende. als ich mir testweise das colormodel von bufferedImage angesehen habe, war dort "isRGB" auf false gesetzt. wie bekomme ich das bild mit rgb farbinformationen geladen?

Code:
String fileName = openDlg.getDirectory() + openDlg.getFile();
File file = new File(fileName);
InputStream in = new FileInputStream(file);
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in);
final BufferedImage bufferedImage = decoder.decodeAsBufferedImage();
in.close();
 

Marco13

Top Contributor
Ist zwar nicht direkt eine Antwort auf deine Frage, aber ... der JPEGImageDecoder ist nicht Teil der offiziellen Java API. Warum verwendest du nicht ImageIO ?
http://java.sun.com/j2se/1.4.2/docs/api/javax/imageio/ImageIO.html#read(java.io.File)
 
G

Guest

Gast
ImageIO habe ich auch schon versucht, mit dem gleichen ergebnis.

mein ziel ist einen bildbuffer zu haben und zu bearbeiten, der als int[] vorliegt. diesen hole ich mir wie folgt:

Code:
int[] pix = bufferedImage.getRaster().getPixels(0, 0, buferedImage.getWidth(), bufferedImage.getHeight(), (int[])null);

leider liegen die farben in diesem buffer nur im wertebereich 0 (schwarz) und 255 (weiß). wie gesagt, ich brauche rgb...
 

Marco13

Top Contributor
Ich gehe davon aus, das dort drei aufeinanderfolgende Werte aus dem Array jeweils EINEN Pixel codieren - eben R, G und B...
 

EgonOlsen

Bekanntes Mitglied
Marco13 hat gesagt.:
Ich gehe davon aus, das dort drei aufeinanderfolgende Werte aus dem Array jeweils EINEN Pixel codieren - eben R, G und B...
Wenn das Bild vom Typ RGB ist? Nein, dann liegt ein Pixel pro Element in dem Array. Rot ist dann (c>>16)&0xff; grün (c>>8)&0xff; und blau halt (c&0xff);
Das Problem, welches hier beschrieben wird, ist vermutlich, dass JPG auch das Speichern in 256 Graustufen unterstützt. Ansonsten, wenn ein farbiges Bild geladen wird, müssten die Pixel bereits wie eben beschrieben vorliegen.
 

Marco13

Top Contributor
Wenn man ein BufferedImage einfach so lädt, hat man nicht unbedingt Einfluß darauf, welches Format das hat. (Da war neulich mal ein Problem in einem anderen Thread, weil dort ein GIF eingelesen wurde, und das dann eben NICHT vom TYPE_INT_RGB war....). Vielleicht hast du recht, mit dem Graustufen-JPG (habe ich aber noch nie bewußt gesehen...)
 

EgonOlsen

Bekanntes Mitglied
Marco13 hat gesagt.:
Wenn man ein BufferedImage einfach so lädt, hat man nicht unbedingt Einfluß darauf, welches Format das hat.
Ja, deswegen meinte ich ja, dass man es in ein bewusst im korrekten Format erzeugtes BufferedImage reinmalen soll und dann damit arbeiten. Dann ist das Ursprungsformat egal.
 
G

Guest

Gast
EgonOlsen hat gesagt.:
Ja, deswegen meinte ich ja, dass man es in ein bewusst im korrekten Format erzeugtes BufferedImage reinmalen soll und dann damit arbeiten. Dann ist das Ursprungsformat egal.

Code:
final BufferedImage rgbImage = new BufferedImage(
		bufferedImage.getWidth(), bufferedImage.getHeight(),
		BufferedImage.TYPE_INT_ARGB);
			
Graphics2D graphic = rgbImage.createGraphics();
graphic.drawImage(bufferedImage, 0, 0, null);

ich schätze, das du das etwa so gemeint hast... funktioniert nur leider nicht. ich hab keine ahnung, warum, "isRGB" steht auf true, die offsets und bitmasken im colormodel sind korrekt: trotzdem nur grau :(
 
G

Guest

Gast
argh, ich habe die ursache gefunden:

Code:
int[] pix = bufferedImage.getRaster().getPixels(0, 0, buferedImage.getWidth(), bufferedImage.getHeight(), (int[])null);

diese zeile erzeugt ein int[] array mit einer größe von 262144 (256 x 256 x 4), wobei 256 x 256 die bildgröße ist. es wird also für jede 8-bit farbe ein eigener 32-bit datentyp verwendet... irgendwie suboptimal. ich komme zwar an meine farben ran, dennoch wäre es mir lieber, wenn pro pixel nur 1 int wert verwendet würde und nicht 4.

ich dachte zunächst, das es an BufferedImage.TYPE_INT_ARGB liegt und habe auch noch BufferedImage.TYPE_4BYTE_ABGR probiert, was augenscheinlich genau das gleiche macht. schätzungweise wird dieses format erst beim aufruf von bufferedImage.getRaster().getPixels() erzeugt, leider habe ich nichts gefunden, und dies zu beeinflussen um die daten in die benötigte form zu bringen.
 

EgonOlsen

Bekanntes Mitglied
Ich kann ehrlich gesagt nicht mehr so recht folgen...also z.B. das hier:

Code:
BufferedImage output = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);
int[] pixels = ((DataBufferInt) (output.getRaster().getDataBuffer()).getData();

liefert definitiv ein Element/Pixel mit allen Farben + Alpha in einem int. Was genau du jetzt mit "grau" meinst, erschließt sich mir nicht mehr. Natürlich wird ein graues Bild nicht bunt, aber ich vermute mal, das meinst du auch nicht!?
 

Marco13

Top Contributor
Anonymous hat gesagt.:
argh, ich habe die ursache gefunden:
...
diese zeile erzeugt ein int[] array mit einer größe von 262144 (256 x 256 x 4), wobei 256 x 256 die bildgröße ist. es wird also für jede 8-bit farbe ein eigener 32-bit datentyp verwendet...

Das war ja meine erste Vermutung ... es hängt tatsächlich davon ab, ob man z.B. ein GIF oder ein JPG lädt, und vermutlich auch davon, ob es so ein "Graustufen-JPG" ist, was EgonOlsen erwähnt hat. Aber ehrlich gesagt: Dass es beim TYPE_INT_RGB trotzdem so ein 4-Komponenten-Raster liefert, hat mich schon ein bißchen gewundert... ???:L

EDIT: @EgonOlsen: Hast du das mal getestet? Wie gesagt, mich hat das auch irritiert:
Code:
import javax.imageio.*;
import java.awt.image.*;
import java.awt.*;
import java.io.*;


class BufferedImageTest3
{
    public static void main(String args[]) throws Exception
    {
        BufferedImage bufferedImage = ImageIO.read(new File("bildB.jpg"));

        BufferedImage bufferedImage2 = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphic = bufferedImage2.createGraphics();
        graphic.drawImage(bufferedImage, 0, 0, null);
        int[] pix = bufferedImage2.getRaster().getPixels(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), (int[])null);

        int numPixels = bufferedImage.getWidth()*bufferedImage.getHeight();
        System.out.println("pixels          "+numPixels);
        System.out.println("rasterArraySize "+pix.length);
        System.out.println("size/pixels     "+pix.length / numPixels);
    }

}
Ausgabe:
Code:
pixels          306603
rasterArraySize 1226412
size/pixels     4

EDIT2: Ach so.... :shock: du hast beim Pixel-Holen einen anderen Weg eingeschlagen ... "DataBufferInt"... - hmja, wenn's damit funktioniert ist's ja OK....
 
G

Guest

Gast
@egon

genau, das was ich gesucht habe, du hast gerade mein problem gelöst ;-)

thx @ all
 
G

Guest

Gast
wenn ich euch verwirrt haben sollte, sorry :)

das mit den graustufen ergab ich aus den einzelnen int-werten, die ich im raster array (methode: image.getRaster().getPixels()) gefunden habe. da mir zu diesem zeitpunkt noch nicht die 4-fache größe aufgefallen war, nahm ich an, das die echten farbwerte in grauwerte runtergerechnet wurden, dabei handelte es sich bereits um die einzelnen farbkanäle... aber das nur nebenbei

ich hab nochmal ne frage :p

da ich jetzt ein ganz tolles int[] array habe, das die farben genauso enthält, wie ich sie möchte, versuche ich nun ein solches array als daten an ein Image-Objekt anzuhängen. sozusagen also:

Image -> int[]
int[] bearbeiten
int[] ->Image

ich habe zwar schon versucht über die methode image.getRaster().setPixels() zu gehen, aber dort wird anscheinend grundsätzlich erwartet das jeder farbwert pro pixel in einem eigenen int-wert vorliegt. diese methode erwartet also bei einem farbformat von ARGB ein int[] array mit einer länge von width * height * 4 (sprich: 4 int werte pro pixel... wer hat den mist verbrochen ^^). welche möglichkeiten gibt es noch?

ziel ist es ja ein bild zu laden, zu modifizieren und auf dem bildschirm anzuzeigen. ein image-objekt läßt sich ja nun extrem bequem zeichnen. ist es generell möglich bzw. sinnvoll den oben beschriebenen weg (Image -> int[] -> bearbeitetes int[] ->Image) zu gehen, oder sollte ich mir für mein int[] array eine eigene zeichenmethode schreiben?
 

EgonOlsen

Bekanntes Mitglied
Eigentlich übernimmt das BI automatisch die neuen Werte in dem int[]-Array. Du musst das nicht explizit neue setzen. Wenn du das Arrays holst, bearbeitest und dann wieder das BI zeichnest, sollten deine Änderungen im Array direkt durchschlagen.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben