PDA

View Full Version : [C] Libreria filtri 2d per immagini


Cait Sith
30-03-2008, 19:15
Sto facendo un programma in java per gestire delle immagini come voglio io. In fase di anteprima devo fare il resize al volo di immagini fino a 5000 pixel. Il semplice draw delle immagini, seppure veloce, non rende bene le immagini perchè non sono opportunamente filtrate. Le funzioni classi interne di java sono troppo lente. La libreria java image non mi soddisfano perchè, oltre a non essere velocissima, sui grossi rescaling (10%) sono abbastanza scadenti.
A questo punto volevo chiamare del codice nativo in c per avere più efficienza e maggiore qualità.
Poichè la funzione draw del java è abbastanza veloce, credo che mi basti applicare un semplice filtro low pass alle immagini da riscalare. Un semplice filtro gaussiano dovrebbe bastare.
Qualcuno mi può suggerire una libreria adatta a questo scopo?

wizard1993
30-03-2008, 19:51
semmai c++, con le classi è già più semplice trovare qualcosa, hai guardato la libreria allegro?

Cait Sith
30-03-2008, 20:52
in realtà preferirei in c per semplicità: io pensavo a funzioni che operano su array di interi, non vorrei dover passare per la costruzioni di oggetti perchè ciò complicherebbe il discorso della chiamata al codice nativo

sto dando un occhiata alla libreria allegro, ma mi sembra orientata allo sviluppo dei videogame, non ci sono librerie un po' più essenziali?

banryu79
30-03-2008, 23:53
Sto facendo un programma in java per gestire delle immagini come voglio io. In fase di anteprima devo fare il resize al volo di immagini fino a 5000 pixel. Il semplice draw delle immagini, seppure veloce, non rende bene le immagini perchè non sono opportunamente filtrate. Le funzioni classi interne di java sono troppo lente. La libreria java image non mi soddisfano perchè, oltre a non essere velocissima, sui grossi rescaling (10%) sono abbastanza scadenti.
A questo punto volevo chiamare del codice nativo in c per avere più efficienza e maggiore qualità.
[...omissis...]


Ciao, premesso che non ho idea di quello che vuoi *esattamente* fare, prima di pensare di appoggiarti ad una libreria esterna ho pensato che forse anche con Java hai la possibilità di ottenere ciò che desideri, in termini anche di prestazioni.

Ho letto che usi la libreria "java image": presumo tu ti riferisca al package java.awt.image

Non so se ti possa interessare ma ti posto due link che ritengo utili per il tuo problema:

1) javadoc, package javax.imageio (http://java.sun.com/javase/6/docs/api/) (non so se questo package può tornarti utile, ma se non lo hai usato magari ti torna comodo darci un occhio)

2) chet haase blog on performance (http://weblogs.java.net/blog/chet/archive/performance/index.html)

Chet Haase è un ingegnere della Sun che lavora su Java da anni e mastica particolarmente bene proprio la gestione grafica e delle immagini in particolare: se non conoscevi questa risorsa allora considerala una miniera di informazioni e tecniche di programmazione utilissime per lavorare con le immagini in ambiente Java: da non perdere.

Buonanotte :)

tomminno
31-03-2008, 09:50
Qualcuno mi può suggerire una libreria adatta a questo scopo?

Intel OpenCV.

Cait Sith
31-03-2008, 20:15
Ciao, premesso che non ho idea di quello che vuoi *esattamente* fare, prima di pensare di appoggiarti ad una libreria esterna ho pensato che forse anche con Java hai la possibilità di ottenere ciò che desideri, in termini anche di prestazioni.

Ho letto che usi la libreria "java image": presumo tu ti riferisca al package java.awt.image

Non so se ti possa interessare ma ti posto due link che ritengo utili per il tuo problema:

1) javadoc, package javax.imageio (http://java.sun.com/javase/6/docs/api/) (non so se questo package può tornarti utile, ma se non lo hai usato magari ti torna comodo darci un occhio)

2) chet haase blog on performance (http://weblogs.java.net/blog/chet/archive/performance/index.html)

Chet Haase è un ingegnere della Sun che lavora su Java da anni e mastica particolarmente bene proprio la gestione grafica e delle immagini in particolare: se non conoscevi questa risorsa allora considerala una miniera di informazioni e tecniche di programmazione utilissime per lavorare con le immagini in ambiente Java: da non perdere.

Buonanotte :)

In effetti sono stato un po' spiccio perchè questo progetto l'avevo iniziato qualche mese fa, poi avevo piantato lì.
La libreria java che avevo usato a suo tempo era la JAI (http://java.sun.com/javase/technologies/desktop/media/jai/) che ha incluse alcune operazioni di resize, ma sugli scaling pesanti lasciano un po' a desiderare, senza contare che erano un po' lentine.
Ho provato anche il metodo getScaledInstance della classe image java, ma è lento pure lui.
Poichè il visualizzatore di immagini di windows è molto veloce e offre risultati molto buoni ho pensato che una funzione C avrebbe fatto al caso mio.

Purtroppo anche se conosco un po' l'elaborazione delle immagini, non conosco i metodi efficienti per ottenere determinati risultati (altrimenti la scriverei io la funzione in c).

Ora provo a guardare un po' le librerie della intel

banryu79
01-04-2008, 00:23
Tratto proprio dal link alla pagina del blog di Chet Haase:

Image Scaling: This is related to the "Old vs. New" topic above; some operations in our APIs are not obvious. Also, even when there are obvious methods in the API for accomplishing tasks, sometimes it is not clear how these methods work, or that the best ways of accomplishing the tasks are perhaps not related to the most obvious means. For example, Image.getScaledInstance() is not, in general, the best way to scale an image, either performance- or quality-wise. The Graphics.drawImage() methods are much better in general, but they are not necessarily obvious to developers new to the Graphics class. I would like to cover some of these areas and discuss the merits of the different approaches.


Magari ce la fai anche con Java: dagli una possibilità.

Mettila così: (ammesso che le prestazioni che vuoi ottenere siano raggiungibili nella pratica, e scommetto di sì se si usano sapientemente BufferedImage, Graphics e si imparano i "trucchi del mestiere", vedi blog di Chet) se ce la fai con Java non solo hai tutto in pure-Java (portabilità, in teoria) ma hai anche la soddisfazione di aver acquisito conoscenze maggiori e specifiche nell'ambito della manipolazione di immagini, un campo piuttosto interessante (manipolare bene, e con tutte le sottigliezze del caso le immagini può tornare molto utile per riutilizzare questa conoscenza anche in altri contesti più stuzzicanti, tipo la gestione degli sprites in un videogioco, per esempio)

Se non si è capito faccio il tifo per Java, e per te che lo usi: devi solo decidere di dedicare un po' di tempo allo studio delle info nel blog del tizio della Sun prima di scatenare le ditine sulla testiera :D

Faccio il tifo per te :)


@EDIT:

----------------------------------------------------------------------
Subject 3.05: How do I enlarge/sharpen/fuzz a bitmap?

Sharpening of bitmaps can be done by the following algorithm:

I_enh(x,y) = I_fuz(x,y)-k*Laplace(I_fuz(x,y))

or in words: An image can be sharpened by subtracting a positive
fraction k of the Laplace from the fuzzy image.

One "Laplace" kernel, approximating a Laplacian operator, is:
1 1 1
1 -8 1
1 1 1


The following library implements Fast Gaussian Blurs:

MAGIC: An Object-Oriented Library for Image Analysis by David Eberly

The library source code and the documentation (in Latex) are at
http://www.magic-software.com/
The code compiles on Unix systems using g++ and on PCs using
Microsoft Windows 3.1 and Borland C++. The fast Gaussian blurring
is based on a finite difference method for solving s u_s = s^2 \nabla^2 u
where s is the standard deviation of the Gaussian (t = s^2/2). It
takes advantage of geometrically increasing steps in s (rather than
linearly increasing steps in t), thus getting to a larger "time" rapidly,
but still retaining stability. Section 4.5 of the documentation contains
the algorithm description and implementation.

A bitmap is a sampled image, a special case of a digital signal,
and suffers from two limitations common to all digital signals.
First, it cannot provide details at fine enough spacing to exactly
reproduce every continuous image, nor even more detailed sampled
images. And second, each sample approximates the infinitely fine
variability of ideal values with a discrete set of ranges encoded
in a small number of bits---sometimes just one bit per pixel. Most
bitmaps have another limitation imposed: The values cannot be
negative. The resolution limitation is especially important, but
see "How do I display a 24 bit image in 8 bits?" for range issues.

The ideal way to enlarge a bitmap is to work from the original
continuous image, magnifying and resampling it. The standard way
to do it in practice is to (conceptually) reconstruct a continuous
image from the bitmap, and magnify and resample that instead. This
will not give the same results, since details of the original have
already been lost, but it is the best approach possible given an
already sampled image. More details are provided below.

Both sharpening and fuzzing are examples of filtering. Even more
specifically, they can be both be accomplished with filters which
are linear and shift invariant. A crude way to sharpen along a row
(or column) is to set output pixel B[n] to the difference of input
pixels, A[n]-A[n-1]. A similarly crude way to fuzz is to set B[n]
to the average of input pixels, 1/2*A[n]+1/2*A[n-1]. In each case
the output is a weighted sum of input pixels, a "convolution". One
important characteristic of such filters is that a sinusoid going
in produces a sinusoid coming out, one of the same frequency. Thus
the Fourier transform, which decomposes a signal into sinusoids of
various frequencies, is the key to analysis of these filters. The
simplest (and most efficient) way to handle the two dimensions of
images is to operate on first the rows then the columns (or vice
versa). Fourier transforms and many filters allow this separation.

A filter is linear if it satisfies two simple relations between the
input and output: scaling the input by a factor scales the output
by the same factor, and the sum of two inputs gives the sum of the
two outputs. A filter is shift invariant if shifting the input up,
down, left, or right merely shifts the output the same way. When a
filter is both linear and shift invariant, it can be implemented as
a convolution, a weighted sum. If you find the output of the filter
when the input is a single pixel with value one in a sea of zeros,
you will know all the weights. This output is the impulse response
of the filter. The Fourier transform of the impulse response gives
the frequency response of the filter. The pattern of weights read
off from the impulse response gives the filter kernel, which will
usually be displayed (for image filters) as a 2D stencil array, and
it is almost always symmetric around the center. For example, the
following filter, approximating a Laplacian (and used for detecting
edges), is centered on the negative value.
1/6 4/6 1/6
4/6 -20/6 4/6
1/6 4/6 1/6
The symmetry allows a streamlined implementation. Suppose the input
image is in A, and the output is to go into B. Then compute
B[i][j] = (A[i-1][j-1]+A[i-1][j+1]+A[i+1][j-1]+A[i+1][j+1]
+4.0*(A[i-1][j]+A[i][j-1]+A[i][j+1]+A[i+1][j])
-20.0*A[i][j])/6.0

Ideal blurring is uniform in all directions, in other words it has
circular symmetry. Gaussian blurs are popular, but the obvious code
is slow for wide blurs. A cheap alternative is the following filter
(written for rows, but then applied to the columns as well).
B[i][j] = ((A[i][j]*2+A[i][j-1]+A[i][j+1])*4
+A[i][j-1]+A[i][j+1]-A[i][j-3]-A[i][j+3])/16
For sharpening, subtract the results from the original image, which
is equivalent to using the following.
B[i][j] = ((A[i][j]*2-A[i][j-1]-A[i][j+1])*4
-A[i][j-1]-A[i][j+1]+A[i][j-3]+A[i][j+3])/16
Credit for this filter goes to Ken Turkowski and Steve Gabriel.

Reconstruction is impossible without some assumptions, and because
of the importance of sinusoids in filtering it is traditional to
assume the continuous image is made of sinusoids mixed together.
That makes more sense for sounds, where signal processing began,
than it does for images, especially computer images of character
shapes, sharp surface features, and halftoned shading. As pointed
out above, often image values cannot be negative, unlike sinusoids.
Also, real world images contain noise. The best noise suppressors
(and edge detectors) are, ironically, nonlinear filters.

The simplest way to double the size of an image is to use each of
the original pixels twice in its row and in its column. For much
better results, try this instead. Put zeros between the original
pixels, then use the blurring filter given a moment ago. But you
might want to divide by 8 instead of 16 (since the zeros will dim
the image otherwise). To instead shrink the image by half (in both
vertical and horizontal), first apply the filter (dividing by 16),
then throw away every other pixel. Notice that there are obvious
optimizations involving arithmetic with powers of two, zeros which
are in known locations, and pixels which will be discarded.



stralcio di una pagina di faq che ho scaricato tanto tempo fa e che ho ripescato proprio per caso or ora salvata nei meandri della mia cartella documenti (a lavoro mi hanno preso il portatile nuovo e stavo installando i vari software e trsbordando tutta la mia roba dal vecchio, un'ottima occasione per fare pulizia).

Purtroppo ho perso il link della pagina, ti allego direttamente tutto il file:
algorithms-faq (http://www.mediafire.com/?40dsof3gmwt)

Cait Sith
02-04-2008, 20:18
la funzione drawImage infatti la uso, ed è molto veloce, solo che se la si applica direttamente all'immagine originale produce uno strano effetto che io chiamo "brillantante", nel senso che i piccoli dettagli influenzano pesantemente l'immagine finale
è per questo che volevo applicare un filtro passabasso, tipo il gaussian blur:
in questo modo si eliminano i dettagli così quando si chiama drawImage la resa dovrebbe essere corretta
quello che dovrei fare io è trovare i coefficienti della matrice 3x3 o 5x5 per ottenere l'approssimazione migliore di un filtro con frequenza di taglio desiderata
su uno scalamento del 10%, la frequenza di taglio normalizzata dovrebbe essere 0.05, nota la frequenza di taglio posso determinare la varianza della gaussiana e posso trovare i coefficienti della matrice (in realtà mi basta un vettore e filtrare per righe e per colonne)
magari posso provare a scrivere io in java la funzione, ma non so se è sufficientemente veloce per fare un filtraggio al volo