Log in

View Full Version : Resolved Image brightness normalizer fails to populate grayscale levels array



techno_race
04-06-2011, 04:02 AM
I am trying to create a PHP script to increase and decrease the brightnesses of images in a directory such that they all appear similar, then datestamp and save them (the datestamp is in the format of "MM/DD/YY HH:MM:SS AP" at the bottom and "Age: [weeks since March 22, 2011] weeks" at the top, based on a filename format of the images of "YYYY-MM-DDHH-MM-SS.jpg").

In the directory are this PHP script ("normalize.php"), a number of images, and two subdirectories, "brightness," which contains 1x1-pixel grayscale versions (I made these already) of the images as a basis to measure the overall brightness based on the grey level, and "corrected," which should contain the images generated by the script.


$images = array();
$processed = 0;
$brightnesses = array();
$offsets = array();
$dates = array();
$ages = array();
if ($handle = opendir('.')) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && $file != "brightness" && $file != "corrected" && $file != "normalize.php") {
$images[$processed] = "$file";
}
$processed++;
}
closedir($handle);
}
$processed = 0;
while ($processed < $images.count) {
$image = imagecreatefromjpeg("brightness/".$images[$processed]);
$rgb = imagecolorat($image, 1, 1);
$brightness = $rgb & 0xFF;
$brightnesses[$images[$processed]] = $brightness;
imagedestroy($image);
$processed++;
}
$processed = 0;
$total = 0;
while ($processed < $images.count) {
$total = $total + $brightnesses[$images[$processed]];
$processed++;
}
$processed = 0;
$average = $total/count($brightnesses);
while ($processed < $images.count) {
if ($brightnesses[$images[$processed]] === 0)
$offset = $average;
else
$offset = (100*($average-$brightnesses[$images[$processed]]))/$brightnesses[$images[$processed]];
$offsets[$images[$processed]] = $offset;
$processed++;
}
$processed = 0;
while ($processed < $images.count) {
$image = imagecreatefromjpeg($images[$processed]);
imagefilter($image,IMG_FILTER_BRIGHTNESS,$offsets[$images[$processed]]);
$width = imagesx($image);
$height = imagesy($image);
//YYYY-MM-DDHH-MM-SS.jpg
//0123456789012345678901
//MM/DD/YY HH:MM:SS AP
//Age: WW weeks
$year = substr($images[$processed],2,2);
$month = substr($images[$processed],5,2);
$day = substr($images[$processed],8,2);
$hour = (float) substr($images[$processed],10,2);
if (hour < 12 && hour > 0)
$ampm = 'AM';
else {
$ampm = 'PM';
if (hour === 0)
$hour = 12;
else
$hour = $hour - 12;
}
$minute = substr($images[$processed],13,2);
$second = substr($images[$processed],16,2);
$date = strtotime($year.'-'.$month.'-'.$day);
$born = strtotime('2011-03-22');
$difference = $date-$born;
$age = $difference/36288000000;
if ($age < 10)
$age = ' '.$age;
if (substr($month, 0, 1) === 0)
$month = ' '.substr($month,1,1);
if (substr($day, 0, 1) === 0)
$day = ' '.substr($day,1,1);
if ($hour < 10)
$hour = ' '.$hour;
imagettftext($image,10,0,0,$height,imagecolorallocate($image,255,255,255),"courier.ttf",$month.'/'.$day.'/'.$year.' '.$hour.':'.$minute.':'.$second.' '.$ampm);
imagettftext($image,10,0,0,10,imagecolorallocate($image,255,255,255),"courier.ttf",'Age: '.$age.' weeks');
imagejpeg($image, "corrected/".$images[$processed]);
imagedestroy($image);
$processed++;
}

For some reason, this script doesn't populate the $brightnesses array, thus causing a divide by zero on line 33 and, of course, the script not to function. I don't know if this happens with the other arrays, as the script never ran past the first one.

There must be someone out there who has a clue what I just said. REVEAL YOURSELF...

djr33
04-06-2011, 05:27 AM
Found your problem. The comments below may help in general, but there's an obvious problem with the code:
while ($processed < $images.count) {
$array.count is not PHP. In fact, I'm surprised you didn't get a parse error.
What you want is:
count($array);
Don't mix JS in with PHP! :)

Note: this appears many times, so be sure to find them all.
Also, using a foreach loop (or for loop) is better for this task. You can get a counting variable by using the key:
foreach ($array as $count => $value ) {



That's a lot of code to look through, so honestly I'm just saying the first thing that comes to mind. I'm not sure this is the problem.

This line:
$images[$processed] = "$file";
sets the values in the $images array to filenames.

But then later:
$brightnesses[$images[$processed]] = $brightness;
You are doing a layered array when it doesn't seem important. Why are you bothering to retain the filenames? you can simplify this and just use $count (or $processed if you want) and ignore the filenames.

Cleaning up the code like that will at least help to make things easier to read. At the moment trying to read your code requires thinking about 3 layers of arrays (and that's not easy), so it's not surprising that you've missed something in debugging it-- cleaner code helps faster debugging. It's probably something simple, but to find it you'll have to go line by line to find what's wrong.



BTW, in general the best way to debug this sort of thing is to add random echo 'PARSER GOT HERE!'; lines to your code, such as within loops. That's the easy way to see if that while loop was even running at all. Do that step by step through the code and you can find WHERE the problem is, then try to figure out WHAT the problem is.

techno_race
04-06-2011, 06:31 PM
$array.count is not PHP.

Huh. That explains some things.

I've debugged a bunch of the code, and now have issues with the image generation in the final loop:

$image = imagecreatefromjpeg($images[$processed]);
imagefilter($image,IMG_FILTER_BRIGHTNESS,$offsets[$images[$processed]]);
$width = imagesx($image);
$height = imagesy($image);
...


imagettftext($image,10,0,0,$height,imagecolorallocate($image,255,255,255),"courier.ttf",$month.'/'.$day.'/'.$year.' '.$hour.':'.$minute.':'.$second.' '.$ampm);
imagettftext($image,10,0,0,10,imagecolorallocate($image,255,255,255),"courier.ttf",'Age: '.$age.' weeks');
imagejpeg($image, "corrected/".$images[$processed], 80);
$processed++;
imagedestroy($image);

A var_dump($age); in the loop reveals that it is looping fine, but no JPEGs show up in the corrected subdirectory.

The expected result (made in Photoshop) of this running on the third picture is here (http://thetortoise.tk/Brightness%20normalizer/2011-11-1111-11-11.jpg) (with the original picture here (http://thetortoise.tk/Brightness%20normalizer/Test%201/2011-11-1111-11-11.jpg)). You can see that it is brighter, and 10-pixel Courier New (courier.ttf is in the directory with the script) datestamps are shown in the upper and lower left (they are small on this image due to its original largeness).

The variables being passed are all correct - in the case of the third image, they are:
$images[$processed] is passed to imagecreatefromjpeg() as 2011-11-1111-11-11.jpg
$offsets[$images[$processed]] is passed to imagefilter() as 162.6666666667
$month is passed to imagettftext() as 11
$day is passed to imagettftext() as 11
$year is passed to imagettftext() as 11
$hour is passed to imagettftext() as 11
$minute is passed to imagettftext() as 11
$second is passed to imagettftext() as 11
$ampm is passed to imagettftext() as 11
$age is passed to imagettftext() as 33
$images[$processed] is passed to imagejpeg() as 2011-11-1111-11-11.jpg
and, of course, $processed is 2 at this point.

djr33
04-06-2011, 10:41 PM
imagejpeg($image, "corrected/".$images[$processed], 80);
That line generates the image file. Try moving that up above some of the other lines until it works. In other words, try outputting the image earlier until you find the problematic line. For example, does it work immediately after:
$image = imagecreatefromjpeg($images[$processed]);
If not, that means the image wasn't created properly.
One reason might be if the filename doesn't include the relative path (if that's necessary).

techno_race
04-07-2011, 03:36 AM
I've narrowed it down to just the line imagejpeg($image, "corrected/".$images[$processed], 80);, as


header("Content-Type: image/jpeg");
imagejpeg($image);

outputs the image to the browser just fine.

djr33
04-07-2011, 03:59 AM
Ok, so have you checked that "corrected/".$images[$processed] is the right path? And if so, do you have the right permissions for that folder to do that?

techno_race
04-07-2011, 04:29 AM
Yeeep. Well, actually, I had to tell Windows to change the permissions three times before it actually did. Isn't technology fun?

I think I set the permissions right. I've never used an IIS server before, and never intend to again. I tried to install Apache, but it didn't work. I don't even know why I have IIS in the first place. It must have come with something... I have a habit of selecting "Install all program features" in the setup wizards. I have tried to switch to Linux several times. I, obviously, ultimately failed miserably. That last sentence was, indeed, structured oddly. Wait. What was I talking about?