PDA

View Full Version : determine colors used in an image



james438
09-10-2008, 12:17 PM
I am learning more about the GD library of functions in php. I also know that it is a bit processor heavy, so I am trying to figure out a way to determine which colors are used in an image.

Let's say I take a jpeg image and convert it to palette form with 125 possible colors using the function imagetruecolortopalette(). I then use imagecolorstotal() to determine that the image only has 100 different colors in its image. That is still 100 different colors from a possible 16.7 million different colors. I can use imagecolorclosest() to discover the exact value of any one color that is closest to say the color black.

Now that I know the value of that one color that came closest to the color black I could convert all of that color in the image to white to get it out of the way and rescan the image for the next closest color to black.

While this would work, it would also be incredibly taxing on the server if I were to actually use the method described above. Can anyone describe a better way to determine the values of the 100 colors that are used in this hypothetical image that is not so processor heavy?

What I have described is the best way I can think of so far. I'll try to post some php later so people can get a better idea of how this code would look in action.

james438
09-12-2008, 02:07 AM
Still, working on it. Here is the latest script I am using:

<pre><?php
$filename = 'http://www.animeviews.com/images/pops/maincontent1.JPG';
$im = imagecreatefromjpeg($filename);
imagetruecolortopalette($im, false, 255);
$a= imagecolorstotal($im);
echo"$a";
$g=$a;
$a++;
$b=0;
$c=0;
$d=0;
$e=0;
while ($b<$a){
$x=rand(0,255);
$y=rand(0,255);
$z=rand(0,255);
$result = imagecolorclosest($im, $x, $y, $z);
$c++;
##if ($c>255){$d++;$c=255;}
##if ($d>255){$e++;$d=255;}
$e++;
$result = imagecolorsforindex($im, $result);
$result = "({$result['red']}, {$result['green']}, {$result['blue']})";
$arry[]="$result";
$arry=array_unique($arry);
$b=count($arry);
if ($b>254){break;}
if ($e>10000){break;}
}
print_r($arry);Echo"<br><br>$b";
?></pre>

It will generate random colors to check until it either finds all of the colors or goes through 10000 tries; which ever comes first.

EDIT: The following is better:

<pre><?php
$filename = 'http://www.animeviews.com/images/pops/maincontent1.JPG';
$im = imagecreatefromjpeg($filename);
imagetruecolortopalette($im, false, 25);
$a= imagecolorstotal($im);
echo"$a";
$e=0;
while ($b<$a){
$x=rand(0,255);
$y=rand(0,255);
$z=rand(0,255);
$result = imagecolorclosest($im, $x, $y, $z);
$e++;
$result=imagecolorsforindex($im, $result);
$result="({$result['red']}, {$result['green']}, {$result['blue']})";
$arry[]="$result";
$arry=array_unique($arry);
$b=count($arry);
if ($e>10000){break;}
}
asort($arry);
print_r($arry);Echo"<br><br>
number of colors in image=$a
<br>number of colors located=$b
<br>Number of tries=$e<br>";
?></pre>
It seems that one of my errors was that imagecolorstotal() determines how many colors are in the palette; not how many colors were used from the palette.

On a side note I am not all that good at using the semicolon in a sentence :?.

djr33
09-12-2008, 04:38 AM
I think there are optimization functions specifically for this, if you want to output a gif, for example. I'm not quite sure on which would work best for you at the moment, but they're worth looking into.
Your method is incredibly inefficient, not that you're coding it wrong, because you have to manually run through pixels. GD isn't incredibly slow, in some ways, but when you're running through individual pixels, as is needed to do most anything manually, it will be.
Any built in function will likely be faster, if it exists, if for nothing else than that it may be able to avoid some of the steps you're required to take per pixel.
(The slowest functions in GD, when I'm working on stuff, I find, are getting and setting pixel colors. The rest, the math, etc., isn't that bad.)

james438
09-12-2008, 06:58 AM
Thank you for reading. Yes, it is incredibly inefficient, but sadly it is the most efficient way I can think of. I have spent a lot of time scanning the many functions in the GD library listed at php.net, but so far I have been unable to find anything that will display the colors used in an image that is either truecolor or preferably palette format. I am rather surprised that I have not been able to find a built in function that does this. imagecolorclosest() is the best that I can find thus far.

Not even all that sure why I am trying to figure this out. Just curious I guess ;)

Ah, well. Thanks for for the tips and explanations!

djr33
09-12-2008, 07:53 AM
As I said, this is the fault of GD, not your approach. GD is, unfortunately, nearly worthless sometimes, because it's just such a pain to run.

I'm not really sure what you're going for, and there might be a way to find more info, though if you're just curious about this specifically, not sure if there's an answer. But if you want to accomplish something with those colors, for example, there might be another method.

james438
09-13-2008, 02:56 AM
heh, I thought you were agreeing with me that my code was poorly written as opposed to GD being poorly designed :p. I can misunderstand people in forums that way.

I kinda like GD. I don't really have mauch experience with image manipulation using any other program like photoshop or what not. Why do you find GD a pain to run sometimes? I probably just like it because it is a rather new discovery for as to what else PHP can do.

Possible uses I see include:
automatically resize images submitted to a website with minimal loss in quality
generate thumbnails of all the images in a folder
creeate rounded corners, generate images with words written on it for a password protection against robots
use it to analyze a picture for general image manipulation (fun).

In this case my curiosity lies in what GD's potential could be for my site and also to figure out a way to best create a program that better answers the post located in: UNSOLVED: Dynamically changing colors and resizing image (http://www.dynamicdrive.com/forums/showthread.php?t=35505).

It is a little frustrating though, because I would figure that there would be a better way to determine what the specific colors are that are used in an image as opposed to the hunt and peck method that I am resorting to. I also can not see any reliable way to determine exactly how many colors are used in an image :(.

No real questions here I guess. I think I may have what I need to design a simple image manipulation program that will take a jpeg file and allow the casual user to alter the different colors in an image how they want. I am rather curious what an image would look like if I were to randomize the colors :).

djr33
09-13-2008, 04:14 AM
No, you were right. I'm saying that there may be another method, using something more efficient in GD, to get your END GOAL done, and somehow bypass this (slow) step.

GD is slow and hard to work with. It has a lot of potential. I don't dislike it, exactly, but it's frustrating to work with. If you do something complex enough, it will take too much server processing power (my account got suspended once, just for running a single script a few times that was generating a pattern-based image).

For some of the simpler uses, it's fine. And for smaller images, especially, it's good.


So, ok, for your real application you'd want to shift the colors in an image randomly while keeping the distributions of any certain color the same?

That would look really odd, and probably not be visibly related to the old image.

james438
09-13-2008, 05:21 PM
Yes, I am at a bit of an impasse with this script as far as making it more efficient. In other words this is as efficient as I know how to make it at present. I have been over and over the functions in the GD library, but have not found one that will help.

I finished my little toy script by the way :)

<?php
header('Content-type: image/jpeg');
$filename = 'http://www.animeviews.com/images/screenshots/cowboybebop27.JPG';
$im = imagecreatefromjpeg($filename);
imagetruecolortopalette($im, false, 25);
$e=0;
while ($e<10000){
$x=rand(0,255);
$y=rand(0,255);
$z=rand(0,255);
$result = imagecolorclosest($im, $x, $y, $z);
$e++;
$exact[]=$result;
$result=imagecolorsforindex($im, $result);
$result="{$result['red']},{$result['green']},{$result['blue']}";
$arry[]="$result";
$arry =array_unique($arry);
$exact=array_unique($exact);
}
$e=0;
$b=count($arry);
natsort($arry);
natsort($exact);
$arry=array_values($arry);
$exact=array_values($exact);
shuffle($arry);
while($e<=$b)
{
$arry[$e]=explode(',',$arry[$e]);
imagecolorset($im,$exact[$e],$arry[$e][0],$arry[$e][1],$arry[$e][2]);
$e++;
}
imagejpeg($im, null, 100);
?>It looks a bit psychedelic. Basically it looks like a negative of an image. The best results are when I keep the palette size small < 25 colors. I'll add this to my tiny collection of GD scripts. This latest one makes me feel like I have gotten my feet sufficiently wet with the GD library of php.