Distanza fra due colori RGBA

Aperto da Cid89, Agosto 20, 2010, 19:04:56

Discussione precedente - Discussione successiva

Cid89

Ciao, scrivo qui perché non so in quale altra sezione dovrei farlo :o

Per un mio piccolo script mi serve quantizzare (esiste come parola, in italiano? :blink: ) delle immagini: un'immagine deve essere modificata in modo che tutti i suoi pixel siano di un colore presente in una data palette.

Per ogni pixel dell'immagine, controllo che il suo colore appartenga alla palette; nel caso non sia così, allora scelgo il colore della palette più vicino al colore del pixel.
Ho usato quindi l'algoritmo del colore più vicino (http://en.wikipedia.org/wiki/Color_quantization).

Calcolare la distanza fra due colori è una cosa di questo tipo (in ruby)

class Colour

  def distance other
     Math.sqrt(
        (@r - other.r)**2 +
        (@g - other.g)**2 +
        (@b - other.b)**2 +
        (@a - other.a)**2
     )
  end

end

Tuttavia mi sono reso conto che forse non è una cosa molto intelligente trattare il canale alpha come tutti gli altri  :pensieroso:
a = Colour.new 0,0,0,0 # nero completamente trasparente
b = Colour.new 255,255,255,0 # bianco completamente trasparente
c = Colour.new 0,0,0,255 # nero completamente opaco

a.distance b
=> 441.6729559300637
irb(main):010:0> a.distance c
=> 255.0

a e b sono entrambi completamente trasparenti, ma risultano LONTANISSIMI pur avendo,intuitivamente, distanza 0...


Pensavo di far sì che la componente alpha avesse un peso maggiore quando questa è più vicina a 0, ma non sono molto sicuro sul come agire... Qualcuno ha una brillante idea? :idea:
Grazie a tutti, ciao! B)

Phoenix

Ho trovato questo articolo in cui discutono del tuo algoritmo (semplice distanza euclidea se non ho capito male) e come può essere migliorato, applicando la distanza euclidea pesata.

articolo

purtroppo non discute del canale alpha.

Credo cmq che il tuo problema sia principalmente il fatto che include il canale alpha nel calcolo della distanza euclidea. Alla fin fine la vicinanza tra due colori dipende esclusivamente dalle loro componenti RGB. La trasparenza non influenza in alcun modo il colore in sé. Credo quindi tu debba calcolare la distanza solo sulle componenti RGB e prenderti l'alpha della palette così com'è.

Credo che ne dia conferma ancje quanto riportato dalla documentazione JPEG:


[...]A more reasonable approach is to store an alpha channel (transparency
percentage) as a separate color component in a JPEG image.  That could work
since a small error in alpha makes only a small difference in the result.
The problem is that a typical alpha channel is exactly the sort of image
that JPEG does very badly on: lots of large flat areas and sudden jumps.
You'd have to use a very high quality setting for the alpha channel.  It
could be done, but the penalty in file size is large.  A transparent JPEG
done this way could easily be double the size of a non-transparent JPEG.
(questo credo perché il canale alpha andrà messo nell'indice del pixel e non nella palette)
That's too high a price to pay for most uses of transparency.[...]


Secondo me l'idea sarebbe usare il canale alpha associato a ogni indice come spiegato sopra però questi livelli li metti a parte e non accanto a ogni indice e comprimi la maschera con un algoritmo LRE. E' probabile (credo) che pixel adiacenti abbiano stesso canale alpha e quindi ti aiuterebbe.

O ancora meglio, è probabile che pixel adiacenti abbiano un livello alpha vinico, e quindi è possibile calcolare una media di una serie di livelli alpha e usare il valore medio per blocchi di pixel corrispondenti.

Non so se è chiara l'idea...
Phoenix
****************
membro di SadNES cITy
I gruppo italiano di traduzione ROM
http://www.sadnescity.it
*****************************

Cid89

Grazie mille per la risposta, e anche per il link! Francamente non ci avevo proprio pensato a dare pesi diversi ai colori :blink:
CitazioneCredo cmq che il tuo problema sia principalmente il fatto che include il canale alpha nel calcolo della distanza euclidea. Alla fin fine la vicinanza tra due colori dipende esclusivamente dalle loro componenti RGB. La trasparenza non influenza in alcun modo il colore in sé. Credo quindi tu debba calcolare la distanza solo sulle componenti RGB e prenderti l'alpha della palette così com'è.
È quello che volevo evitare, in un certo senso.
# Mantenendo alpha nel calcolo:
a = Colour.new 0,0,0,0
b = Colour.new 0,0,0,255
c = Colour.new 1,1,1,1
a.distance b
=> 255.0
a.distance c
=> 2.0
# Ha senso: a e c sono praticamente lo stesso colore

# Senza mantenere alpha nel calcolo:
a = Colour.new 0,0,0,0
b = Colour.new 0,0,0,255
c = Colour.new 1,1,1,1
a.distance b
=> 0.0    # Hey! <----
a.distance c
=> 1.7320508075688772


La mia situazione è questa: ho dei file grafici .txp, roba della Nippon Ichi Software per psp: gemini tempo fa mi ha sbrogliato qualche matassa a riguardo e ne approfitto per ringraziarlo ancora :lol:
Presentano palette a 16 o 256 colori RGBA, e non sono facilmente modificabili con gli editor grafici che ho provato: così ho creato una conversione txp→png, che mi permette di modificare le immagini con i vari gimp e amici. La riconversione png→txp, però, può funzionare solo se nel png non ci sono colori presenti nella palette del txp, ovviamente. Da lì la genesi di tutto questo discorso sulla quantizzazione-o-come-si-chiama.

In effetti mi rendo conto che questo mio problema abbia molte soluzioni pratiche (primo fra tutti, potrei farmi un editor su misura che gestisca il formato su cui sto lavorando :idea: ma mi sono accostato solo da poco a wxwidgets e per ora sarebbe troppo complicato)... Mi chiedevo però se qualcuno avesse mai incontrato le mie stesse perplessità.
Ho trovato ora questo, dalla documentazione di imagemagick: http://www.imagemagick.org/Usage/quantize/#color_trans
Citazionecolor quantization that involves transparency was modified so as to treat all fully-transparent colors as being the same color. This is a linear modification, so colors which are only half-transparent are also thought to be closer together than if they were fully opaque.
Assomiglia a quello che avevo pensato io, ma devo capire bene come funziona

Per quanto riguarda la codifica dell'immagine, la LRE, ecc ti ringrazio ma esula un po' da quello su cui sto lavorando (non devo scegliere come codificare l'immagine, voglio solo gestire i colori).
Comunque prendo appunti, gentilissimo :D  

Phoenix

Allora mi sa che non ti serve convertire in png, tilemolester permette la modifica di immagini rgba se non sbaglio caricando una palette esterna.

E cmq non vedo il problema. Una volta che modifichi la png ottenendo una nuova palette, il tuo tool non può semplicemente convertire di nuovo la png in txp e "copiare" la palette png nel file in uscita?

Se non sbaglio molti editor grafici permettono di mantenere la profondità in bit dell'immagine originale, quantizzando quindi i colori automaticamente.
Phoenix
****************
membro di SadNES cITy
I gruppo italiano di traduzione ROM
http://www.sadnescity.it
*****************************

Cid89

CitazioneSe non sbaglio molti editor grafici permettono di mantenere la profondità in bit dell'immagine originale, quantizzando quindi i colori automaticamente.
Il problema è che GIMP non mantiene le informazioni sulla trasparenza dei png indicizzati con 8bpp ç_ç Quando apro un'immagine del genere con GIMP, la trasparenza "sparisce" e diventa tutto opaco.
Ho letto un po' in giro e pare che proprio GIMP non supporti quel tipo di immagini... Per questo mi ero rassegnato a salvare l'immagine png in truecolor (in quel caso GIMP non "impazzisce" col canale alpha), per poi riconvertirla in txp gestendo io la quantizzazione. Da quel che vedo, poi, non solo gimp soffre di questi problemi :S E comunque vorrei usare un programma free :lol:

PS: con Tile Molester c'erano un po' di problemi, dato che le immagini sono organizzate a tile 32x8 o 16x8 (il che si traduceva in immagini schiacciate, http://www.romhacking.it/forum/index.php?showtopic=1464, http://img401.imageshack.us/img401/4608/deskwx.jpg). Forse potrei semplicemente modificare i txp per renderli leggibili da tile molester, per poi rimetterli a posto una volta finito :o

Odio le immagini :ph34r:

Phoenix

Puoi usare Paint .NET. E' free ed è pieno di plugin. Io ad esempio ho trovato una plugin per modificare i vecchi bmp a 16 bit. Per tile molester si risolve facilmente, basta usare feidian, è un tool a riga di comando che permette di gestire immagini con tile a dimensione variabile.

-EDIT- La plugin si chiama LowColor e supporta anche il salvataggio di png a 16 colori, 256 e addirittura un numero di colori custom:

Plugin

Per salvare in low color, nella finestra di salvataggio, scegli il formato PNG (low color).

Phoenix
****************
membro di SadNES cITy
I gruppo italiano di traduzione ROM
http://www.sadnescity.it
*****************************

Cid89

Mmh,  mi sa che feidian è la soluzione più semplice (anche se ho brutti ricordi, tempo fa non riuscivo nemmeno a farlo partire)

Grazie mille per i consigli, renderò noto il mio modo di procedere per eventuali futuri nipponiciani :D

Cid89

Paint .NET + LowColor sembra proprio essere la soluzione giusta! :clomax mode:
Con quel plugin riesco a gestire png coi chunk che mi interessano (PLTE e tRNS), cosa che con gimp e soci non ero assolutamente riuscito a fare.

Ora dovrò fare un po' di esperimenti (tutto il materiale ce l'ho su ubuntu, e paint .NET purtroppo è solo per windows), ma credo che fondamentalmente il problema sia risolto.

Ora il procedimento, toccando ferro, dovrebbe essere questo:

converto txp -> png (con palette e trasparenze)
modifico il png con paint.net
converto png -> txp (usando la palette ricavata dal nuovo png)

Grazie mille per l'aiuto phoenix :)


PS nota:
Ho anche provato a convertire il txp in modo leggibile da tile molester e ci sono riuscito, ma purtroppo tile molester non permette di importare palette RGBA, ma solo RGB... Quindi avrei avuto lo stesso tipo di problema.

Phoenix

Pain .NET però credo possa partire su mono, vedi se trovi qualche cosa a riguardo.
Phoenix
****************
membro di SadNES cITy
I gruppo italiano di traduzione ROM
http://www.sadnescity.it
*****************************