[Java] RGB thresholding

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 09:21

Tjeerd

Be Original, Be Yourself.

Topicstarter
Ik ben op zoek naar de meest optimale methode om een plaatje in Swing te kunnen "thresholden" op zijn R, G en B-waarden.

Dus ik heb drie schuifjes waarmee je het minimale/maximale rood, groen en blauwbereik kunt afstellen. Ik kom verschillende oplossingen tegen. Waaronder het implementeren van je eigen RGBfilter. Het punt is dat hierbij een Image-klasse wordt gebruikt uit de Toolkit om iets met een plaatje te doen. Ik zou het liefst direct een filter willen toepassen op een BufferedImage. Het probleem is dat je niet een Image kunt casten naar een BufferedImage, ik kom daar alleen weer stukken code tegen om via een omweg een Image om te zetten naar een BufferedImage.

Ik weet van het bestaan van de JAI (Java Advanced Imaging bibliotheken), waarbij je ParameterBlocks kunt maken en op die manier ook het een en ander kunt toepassen om AND/OR/Sharpening/Erode toe te passen, maar ik weet niet hoe ik in JAI iets kan doen zoals RGB-thresholding.

Iemand die hier ervaring mee heeft en/of tips heeft?

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik weet niks over de betreffende libraries, maar kun je niet gewoon een loop over alle pixels doen en daar je filter op los laten?

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd


Acties:
  • 0 Henk 'm!

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 09:21

Tjeerd

Be Original, Be Yourself.

Topicstarter
Die heb ik inderdaad al naar gekeken en gebruikt als inspiratie, maar het komt zo primitief over om zelf door alle pixels heen te moeten lopen en dan de RGB-waarden te zetten. Het werkt trouwens wel, maar ik vroeg me dus af of er optimalere mogelijkheden zijn in Java. Misschien dat er een soort "native" Java-klassen zijn die veel sneller dit soort dingen kunnen doen. En daarbij ondersteunt JAI multiplatform-hardwareacceleratie.

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 22-09 14:14

Matis

Rubber Rocket

Tjeerd schreef op maandag 16 maart 2009 @ 10:23:
[...]
Die heb ik inderdaad al naar gekeken en gebruikt als inspiratie, maar het komt zo primitief over om zelf door alle pixels heen te moeten lopen en dan de RGB-waarden te zetten. Het werkt trouwens wel, maar ik vroeg me dus af of er optimalere mogelijkheden zijn in Java. Misschien dat er een soort "native" Java-klassen zijn die veel sneller dit soort dingen kunnen doen. En daarbij ondersteunt JAI multiplatform-hardwareacceleratie.
Ik weet niet met wat voor snelheid of rekenkracht je het programma moet uitvoeren, maar wat je eventueel zou kunnen doen is het frame in je geheugen laden en alleen de pixels zetten die ook echt veranderd moeten worden.
De overige pixels kun je gewoon *blind* kopieren naar je outputbuffer.

Daarnaast weet ik ook niet hoe je het frame wilt weergeven (wegschrijven als BMP of weergeven in een GUI).

Ikzelf heb bij beeldbewerking altijd gekozen om eerst het plaatje in te laden en alleen te wijzigen wat echt nodig is.

[ Voor 3% gewijzigd door Matis op 16-03-2009 10:38 ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 21-09 02:21

Janoz

Moderator Devschuur®

!litemod

Ikzelf gebruik altijd het volgende stukje code:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    /**
     * Ensures that an image is a BufferedImage or creates a 
     * BufferedImage version of image. 
     * @param image the source image.
     * @return image if it was already a BufferedImage or a new BufferedImage.
     */
    public static BufferedImage toBufferedImage(Image image){
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        } else {
            int type=BufferedImage.TYPE_INT_RGB;
            if (hasAlpha(image)){
                type=BufferedImage.TYPE_INT_ARGB;
            }
            BufferedImage newImage=new BufferedImage(image.getWidth(null),image.getHeight(null),type);
            Graphics g = newImage.getGraphics();
            g.drawImage(image,0,0,null);
            g.dispose();
            return newImage;
        }
    }


Bedenk trouwens dat een Image een superclass van BufferedImage is. Hierdoor kun je dus overal waar Image gebruikt wordt ook gewoon een BufferedImage gebruiken.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 09:21

Tjeerd

Be Original, Be Yourself.

Topicstarter
@Janoz: waarschijnlijk wordt het dan in combinatie met jouw code, als volgt:

Java:
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
    class MyFilter extends RGBImageFilter {
        public MyFilter() {
            canFilterIndexColorModel = true;
        }
    
        // This method is called for every pixel in the image
        public int filterRGB(int x, int y, int rgb) {
            //nog te implementeren code
            if (x == -1) {
                // The pixel value is from the image's color table rather than the image itself
            }
            // Return only the red component
            return rgb & 0xffff0000;
        }
    }

    // Get image
    Image image = new ImageIcon("image.gif").getImage();
    
    // Create the filter
   MyFilter filter = new MyFilter();
    FilteredImageSource filteredSrc = new FilteredImageSource(image.getSource(), filter);
    
    // Create the filtered image
    image = Toolkit.getDefaultToolkit().createImage(filteredSrc);

   BufferedImage bi = toBufferedImage(image);

Maar ik kom tegen dat FilteredImageSource(...) een erg trage methode is, te lezen hier:
The problem won't bite you unless you're accessing the pixels of an image in order to do some image processing, and it won't bite unless you're also drawing with Graphics. It's the combination of the two which really cause it, but you may find other slowdowns if you access an image's pixels. The methods which causes an image to become unaccelerated are getDataBuffer() and getSubImage(). If you call this method, your image is forever after doomed to work like treacle. Avoiding getDataBuffer is not sufficient as it's called internally by other methods. These are the things I've found which trigger the problem. I'm sure there are others:

* Raster.getDataBuffer()
* BufferedImage.getRGB()/setRGB()
* BufferedImage.getSubImage()
* Attaching an ImageObserver to a BufferedImage
* Filtering a BufferedImage with FilteredImageSource

[ Voor 27% gewijzigd door Tjeerd op 16-03-2009 11:03 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 21-09 02:21

Janoz

Moderator Devschuur®

!litemod

De opmerking slaat waarschijnlijk op het rechtstreeks gebruiken op een Form. In dat geval zal het filter bij elke redraw van je applicatie opnieuw worden toegepast. Zeker wanneer er een per pixel actie uitgehaald wordt kan dit nogal duur worden. Aangezien die acties elke keer uitgevoerd moeten worden is het niet mogelijk om versnelling toe te kunnen passen.

Om dit te voorkomen is het handiger om het filteren maar 1x te doen en het resultaat niet weg te schrijven naar het scherm, maar naar een aparte image. Deze aparte image gebruik je vervolgens om op het scherm te zetten. Feitelijk is dat ook wat er nu ongeveer gebeurt, mits het resultaat van de FilteredImage niet stiekem toch een BufferedImage is natuurlijk :).

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 09:21

Tjeerd

Be Original, Be Yourself.

Topicstarter
Het lijkt me inderdaad het beste om dit in een "offscreen" plaatje te doen, anders is het te rekenintensief.

Ondertussen heb ik nog wat gevonden in oude listserv-groepen van Sun (:|). Het kan waarschijnlijk met een "threshold" operator die in de JAI-bibliotheek zit.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Set up the operation parameters.
PlanarImage src, dst;
Integer [] low, high, map;
int bands;

low  = new Integer[bands];
high = new Integer[bands];
map  = new Integer[bands];

for (int i = 0; i < bands; i++) {
low[i]  = new Integer(args[1]);
high[i] = new Integer(args[2]);
map[i]  = new Integer(args[3]);
}

// Create the threshold operation.
pb = new ParameterBlock();
pb.addSource(src);
pb.add(low);
pb.add(high);
pb.add(map);
RenderedImage dst = JAI.create("threshold", pb);
Plaatjes die met JAI.create zijn gemaakt bevatten ook methoden om het plaatje als BufferedImage terug te krijgen, dus ik ga dit vanavond eens proberen :)

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


Acties:
  • 0 Henk 'm!

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 12:33

voodooless

Sound is no voodoo!

Check anders eens RGBImageFilter :) Daar zit een methode in om pixels te kunnen filteren. Het grove werk wordt dat voor je gedaan, je hoeft alleen aan te geven wat er met een pixel moet gebeuren.

Do diamonds shine on the dark side of the moon :?

Pagina: 1