gemiddelde kleur
Op het moment ben ik bezig met een scriptje dat de gemiddelde kleur van een bepaalde foto berekend. Ik heb twee manier bedacht om deze kleur te berekenen.
1. Ik ga een voor een alle pixels van het plaatje af. Ik neem van elke pixel de RGB waarde tel deze op en deel ze door het aantal pixels (linker kolom plaatje).
2. Ik verklein het plaatje naar 1X1 px. Vervolgens haal ik de RGB waarde op (rechter kolom plaatje).
De eerste manier lijkt goed te lukken maar duurt langer naar mate het plaatje groter wordt. De tweede manier lijkt helemaal niet goed te lukken. Ik lijk niet de gemiddelde kleur te krijgen. Als ik de voorbeelden langs elkaar leg lijkt het als of ik de kleur van de pixel (1,1) krijg.
Dit is de code die ik heb gebruikt doe ik iets fout, zie ik misschien iets over het hoofd, zo ja wat moet ik aanpassen.
Code (php)
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
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
<?php
class average_color {
public $r;
public $g;
public $b;
function __construct($img) {
#image
$image = imagecreatefromjpeg($img);
list($width, $height) = getimagesize($img);
#new image
$new_image = imagecreatetruecolor(1,1);
imagecopyresized($new_image, $image, 0, 0, 0, 0, 1, 1, $width, $height);
$rgb = imagecolorat($image, 0, 0);
#average colors
$this->r = ($rgb >> 16) & 0xFF;
$this->g = ($rgb >> 8) & 0xFF;
$this->b = $rgb & 0xFF;
}
}?>
class average_color {
public $r;
public $g;
public $b;
function __construct($img) {
#image
$image = imagecreatefromjpeg($img);
list($width, $height) = getimagesize($img);
#new image
$new_image = imagecreatetruecolor(1,1);
imagecopyresized($new_image, $image, 0, 0, 0, 0, 1, 1, $width, $height);
$rgb = imagecolorat($image, 0, 0);
#average colors
$this->r = ($rgb >> 16) & 0xFF;
$this->g = ($rgb >> 8) & 0xFF;
$this->b = $rgb & 0xFF;
}
}?>
Gewijzigd op 07/10/2012 20:16:12 door Peter paul
als je een foto verkleint naar 1x1 pixel houd hij inderdaad de kleur van de pixel (x,y: 1,1). die is dus niet 'betrouwbaar'. je eerste methode hoort als het goed is wel te werken maar zoals je al eerder zei, gaat dat lang duren als je grote foto's hebt. toch schijnt 'ie prima te werken. ik zou niet weten wat er nog anders moet
ik denk als je eerst de foto vervaagt je al meer gemidekleuren hebt. En dan om de zoveel pixel de kleur bij houden.
Maar ja, ik had ergens een mapje "gemiddelde_kleur" in mijn xampp subfolders. Misschien ben je er iets mee.
Mijn idee: je laat via Ajax de kleur berekenen (door php). Dan duurt het nog even lang, maar het gebeurt 1 voor 1 en je ziet het gebeuren.
Zie zelf eens wat je er van denkt.
Zorg gewoon dat je de <img>'s de juiste src geeft bij jou (001.jpg, 002.jpg, ... aanpassen naar bestaande images bij jou.)
Je merkt trouwens dat ik basically het zelfde doe: waarden optellen per r, g, of b -waarde en delen door het aantal pixels.
Code (php)
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?php
// AJAX verzoek
if (isset($_GET['ajax'])) {
if(!empty($_POST['src'])) {
$img = imagecreatefromjpeg($_POST['src']);
$average = average($img);
echo $average;
}
exit();
}
function average($img) {
$w = imagesx($img);
$h = imagesy($img);
$r = $g = $b = 0;
for($y = 0; $y < $h; $y++) {
for($x = 0; $x < $w; $x++) {
$rgb = imagecolorat($img, $x, $y);
$r += $rgb >> 16;
$g += $rgb >> 8 & 255;
$b += $rgb & 255;
}
}
$pxls = $w * $h;
$r = dechex(round($r / $pxls));
$g = dechex(round($g / $pxls));
$b = dechex(round($b / $pxls));
if(strlen($r) < 2) {
$r = 0 . $r;
}
if(strlen($g) < 2) {
$g = 0 . $g;
}
if(strlen($b) < 2) {
$b = 0 . $b;
}
return "#" . $r . $g . $b;
}
echo '
<html>
<head>
</head>
<body>
<div id="results">
Gemiddelde kleur van foto\'s berekenen. Asynchroon, 1 per 1.
<input type="button" class="go" value="GO!"/>
</div>
<div class="photo"><img src="001.jpg"/></div>
<div class="photo"><img src="002.jpg"/></div>
<div class="photo"><img src="003.jpg"/></div>
<div class="photo"><img src="004.jpg"/></div>
<div class="photo"><img src="005.jpg"/></div>
<div class="photo"><img src="006.jpg"/></div>
<div class="photo"><img src="007.jpg"/></div>
<div class="photo"><img src="008.jpg"/></div>
<div class="photo"><img src="009.jpg"/></div>
<div class="photo"><img src="010.jpg"/></div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
var i=0;
function probe_photo() {
var src = $($(".photo img")[i]).attr("src");
$.ajax({
url: "?ajax=1",
type: "POST",
data: "src=" + escape(src),
success: function(html) {
$($(".photo")[i]).css("background", html);
$($(".photo")[i]).append(html);
i++;
if (i < $(".photo img").length) {
setTimeout("probe_photo();", 200);
}
}
});
}
$(document).ready(function() {
$(".go").click(function() {
probe_photo();
});
});
</script>
</body>
</html>';
?>
// AJAX verzoek
if (isset($_GET['ajax'])) {
if(!empty($_POST['src'])) {
$img = imagecreatefromjpeg($_POST['src']);
$average = average($img);
echo $average;
}
exit();
}
function average($img) {
$w = imagesx($img);
$h = imagesy($img);
$r = $g = $b = 0;
for($y = 0; $y < $h; $y++) {
for($x = 0; $x < $w; $x++) {
$rgb = imagecolorat($img, $x, $y);
$r += $rgb >> 16;
$g += $rgb >> 8 & 255;
$b += $rgb & 255;
}
}
$pxls = $w * $h;
$r = dechex(round($r / $pxls));
$g = dechex(round($g / $pxls));
$b = dechex(round($b / $pxls));
if(strlen($r) < 2) {
$r = 0 . $r;
}
if(strlen($g) < 2) {
$g = 0 . $g;
}
if(strlen($b) < 2) {
$b = 0 . $b;
}
return "#" . $r . $g . $b;
}
echo '
<html>
<head>
</head>
<body>
<div id="results">
Gemiddelde kleur van foto\'s berekenen. Asynchroon, 1 per 1.
<input type="button" class="go" value="GO!"/>
</div>
<div class="photo"><img src="001.jpg"/></div>
<div class="photo"><img src="002.jpg"/></div>
<div class="photo"><img src="003.jpg"/></div>
<div class="photo"><img src="004.jpg"/></div>
<div class="photo"><img src="005.jpg"/></div>
<div class="photo"><img src="006.jpg"/></div>
<div class="photo"><img src="007.jpg"/></div>
<div class="photo"><img src="008.jpg"/></div>
<div class="photo"><img src="009.jpg"/></div>
<div class="photo"><img src="010.jpg"/></div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
var i=0;
function probe_photo() {
var src = $($(".photo img")[i]).attr("src");
$.ajax({
url: "?ajax=1",
type: "POST",
data: "src=" + escape(src),
success: function(html) {
$($(".photo")[i]).css("background", html);
$($(".photo")[i]).append(html);
i++;
if (i < $(".photo img").length) {
setTimeout("probe_photo();", 200);
}
}
});
}
$(document).ready(function() {
$(".go").click(function() {
probe_photo();
});
});
</script>
</body>
</html>';
?>
Gewijzigd op 08/10/2012 11:18:29 door Kris Peeters
Ik ben zelf ook nog even verder gegaan met dit probleempje en ik heb het weten op te lossen. Door imagecopyresized() te vervangen voor imagecopyresampled () werkt alles perfect. Ook zag ik in mijn vereenvoudigde script nog een klein foutje, ik verwijs bij imagecolorat() naar $image dit moet uiteraard $new_image zijn. Dit had ik in mijn eigen script uiteraard wel goed.
Bedankt.
Kun je nog een screenshot tonen van het uiteindelijke resultaat met een paar andere plaatjes? Ik weet niet waar je het voor gaat gebruiken, maar (mocht je dit nog niet doen) je kunt die gemiddelde kleur ook eenmalig berekenen op het moment dat een foto wordt geupload. Dus niet telkens wanneer de foto getoond moet worden het script uitvoeren, maar slechts 1 keer als de foto wordt geupload. De gemiddelde kleur waarde sla je dan bij die foto op in de database.
Kun je niet beter php escapen voor dat HTML gedeelte? Waarom je server daarmee belasten?
Ja, inderdaad
Hier de screenshot waar je om vroeg. Je ziet het misschien niet maar de bovenste kleuren van de linker en rechter kolom zijn niet exact het zelfde. Maar dit verschil is zo minimaal dat ik het goed vind.
En ik was inderdaad van plan de kleuren op te slaan in mijn DB.
Peter paul op 08/10/2012 13:20:23:
Welke bovenste kleuren bedoel je? Ik meet exact dezelfde waardes (de achtergrond kleur). Kun je de complete code nog eens plaatsen? Misschien leuk voor anderen?