webForumDet fria alternativet

Att hitta den vanligaste färgen i en bild

Java

4 svar · 536 visningar · startad av jme

Medlem sedan maj 20012 237 inlägg
Frågan#1

Hej.

Jag vill hitta den vanligaste färgen i en viss bild. Det skall inte vara 100% exakt färgmatchning, utan jag vill ha en viss tolerans.

Exempel (i hexadecimala värden, för enkelhetens skull):

#ffffff (vit) ligger nära till e0e3e3 (ljusgrå)

medan

#ffffff inte ligger nära 0d00ff (blå)

Nedanstående kod plockar färginformationen ur en viss pixel och delar upp den i rött, grönt och blått.

                BufferedImage image = ...
                int c = image.getRGB(x, y);
		int  red = (c & 0x00ff0000) >> 16;
		int  green = (c & 0x0000ff00) >> 8;
		int  blue = c & 0x000000ff;

Det gäller ju även att bestämma toleransnivån.

Hur ska man ta sig till väga för att bestämma om en viss färg (rgb) är nära en annan färg?

Medlem sedan aug. 20039 340 inlägg
#2

Mina tankar, för vad de är värda:
Ett enkelt mått på skillnaden är: abs(r1-g2)+abs(g1-g2)+abs(b1-b2) Max-värdet är då 765 (3*255) för motsatsfärger och min-värdet är 0. Du skulle också kunna ge varje skillnad en koefficient - ögat är långt mer känsligt för grönt än för andra färger. Jag kan se om jag kan gräva fram lite länkar om ämnet, det finns en del forskning kring det, men jag skulle rekommendera något i stil med 0.8*abs(r1-g2)+1*abs(g1-g2)+0.8*abs(b1-b2) som ger mer vikt åt grön.

Vad gäller en algoritm för att faktiskt försöka utvinna den mest förekommande färgen skulle jag göra typ så här:
Dela upp bilden i 2*2 pixlar stora block. Beräkna skillnaden mellan varje par av pixlar, totalt 6 par (alt. endast de 4 kantgrupperna) sedan väljer du ut det par i varje block som har minst skillnad och beräkna medelvärdet mellan dessa färger. Detta kan du kalla för det blockets medianfärg. Sedan gör du samma sak med 2*2 sådana block. Och sedan samma sak med 2*2 sådana block, ändå tills du har "zoomat ut" hela vägen. Det sista värdet du får ut "may or may not be" ett bra värde. Jag har inte provat algoritmen, jag kom på den när jag såg ditt inlägg. :)
Men det kan kanske vara värt att prova den.

Medlem sedan maj 20012 237 inlägg
#3

Tack för svaret. Skall försöka verkligen förstå det du skrev. :)

Tar dock gärna emot andra förslag och tips på läsning.

Medlem sedan maj 20012 237 inlägg
#4

"Dela upp bilden i 2*2 pixlar stora block. Beräkna skillnaden mellan varje par av pixlar, totalt 6 par"

Nu förstår jag inte riktigt.

Medlem sedan aug. 20039 340 inlägg
#5

Varje pixel har ju en koordinat, ungefär

0,0 1,0 2,0 3,0
0,1 1,1 2,1 3,1
0,2 1,2 2,2 3,2
0,3 1,3 2,3 3,3

Min idé är att du plockar ut fyra pixlar åt gången, först t ex de längst uppe till vänster, och beräknar ett slags medianvärde. Alltså, beräknar du t ex: (pseudokod)

diff1 = colorDifference(getPixel(0,0),getPixel(1,0));
diff2 = colorDifference(getPixel(1,0),getPixel(1,1));
diff3 = colorDifference(getPixel(1,1),getPixel(0,1));
diff4 = colorDifference(getPixel(0,1),getPixel(0,0));

Sedan Plockar du ut det par av pixlar som har minst skillnad och beräknar medelvärdet mellan dessa. Det får räknas som ett slags medianvärde av de fyra pixlarna, alltså, man har uteslutit de två extremaste pixlarna.

Sedan skapar man en ny buffer med halva storleken och lagrar varje medianvärde från ursprungsbilden. Sedan fortsätter man sp. I exemplet ovan får man en ny buffer med 2*2 positioner, där varje position alltså innehåller ett medianvärde från den förra iterationen.

Genom att reducera storleken på buffern och gång på gång utesluta två extremvärden och behålla de närmsta värdena så är min teori att man får ut något som åtminstone ligger i närheten av det vanligaste värdet.

Jag ger dock inga garantier för att så är fallet eller att detta är ett bra sätt att beräkna värdet.

265 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
122 ms — deklarationer (db)
0 ms — hämta statistik (cache)
139 ms — hämta tråd, inlägg och bilagor (db)
120 ms — ändringar (db)